changeset 37:cc7fae81afec

* Fix line terminators no-open-ticket
author IBBoard <dev@ibboard.co.uk>
date Sat, 27 Jun 2009 19:03:58 +0000
parents c949727ec0e0
children a47736adb1e8
files Arrays.cs AssemblyInfo.cs Commands/Command.cs Commands/CommandStack.cs Constants.cs CustomMath/Comparisons.cs IBBoard.cs IO/InvalidFileException.cs IO/UnsupportedFileTypeException.cs Lang/ITranslatable.cs Lang/StringManipulation.cs Lang/Translation.cs Logging/FileLogger.cs Logging/LogItem.cs Logging/Logger.cs Logging/SilentLogger.cs Logging/TextFileLogger.cs Preferences.cs UnixTimestamp.cs Xml/IBBXmlResolver.cs Xml/XmlParseException.cs
diffstat 21 files changed, 1225 insertions(+), 1225 deletions(-) [+]
line wrap: on
line diff
--- a/Arrays.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Arrays.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,93 +2,93 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.Collections;
-
-namespace IBBoard
-{
-	/// <summary>
-	/// Summary description for Arrays.
-	/// </summary>
-	public class Arrays
-	{
-		public static object[] Subtract(object[] items, object[] subtract)
-		{
-			ArrayList arr = new ArrayList();
-			arr.AddRange(items);
-			
-			foreach (object obj in subtract)
-			{
-				arr.Remove(obj);
-			}
-
-			return arr.ToArray();
-		}
-
-		public static object[] Difference(object[] items1, object[] items2)
-		{
-			ArrayList arr = new ArrayList();
-
-
-			//Difference with as few loops as possible, so see which is shortest			
-			if (items1.Length > items2.Length)
-			{
-				//add everything from the first list
-				arr.AddRange(items1);
-
-				foreach (object obj in items2)
-				{
-					//Then for each item in the second list, if it is in the list remove it
-					if (arr.Contains(obj))
-					{
-						arr.Remove(obj);
-					}
-					else
-					{
-						//and if it isn't in the list add it
-						arr.Add(obj);
-					}
-				}
-			}
-			else
-			{
-				//add everything from the second list
-				arr.AddRange(items2);
-
-				foreach (object obj in items1)
-				{
-					//Then for each item in the first list, if it is in the list remove it
-					if (arr.Contains(obj))
-					{
-						arr.Remove(obj);
-					}
-					else
-					{
-						//and if it isn't in the list add it
-						arr.Add(obj);
-					}
-				}
-			}
-
-			return arr.ToArray();
-		}
-
-		public static int IndexOf(object[] items, object item)
-		{
-			for (int i = 0; i<items.Length; i++)
-			{
-				if (items[i].Equals(item))
-				{
-					return i;
-				}
-			}
-
-			return -1;
-		}
-
-		public static bool Contains(object[] items, object item)
-		{
-			return IndexOf(items, item) != -1;
-		}
-	}
-}
+using System;
+using System.Collections;
+
+namespace IBBoard
+{
+	/// <summary>
+	/// Summary description for Arrays.
+	/// </summary>
+	public class Arrays
+	{
+		public static object[] Subtract(object[] items, object[] subtract)
+		{
+			ArrayList arr = new ArrayList();
+			arr.AddRange(items);
+			
+			foreach (object obj in subtract)
+			{
+				arr.Remove(obj);
+			}
+
+			return arr.ToArray();
+		}
+
+		public static object[] Difference(object[] items1, object[] items2)
+		{
+			ArrayList arr = new ArrayList();
+
+
+			//Difference with as few loops as possible, so see which is shortest			
+			if (items1.Length > items2.Length)
+			{
+				//add everything from the first list
+				arr.AddRange(items1);
+
+				foreach (object obj in items2)
+				{
+					//Then for each item in the second list, if it is in the list remove it
+					if (arr.Contains(obj))
+					{
+						arr.Remove(obj);
+					}
+					else
+					{
+						//and if it isn't in the list add it
+						arr.Add(obj);
+					}
+				}
+			}
+			else
+			{
+				//add everything from the second list
+				arr.AddRange(items2);
+
+				foreach (object obj in items1)
+				{
+					//Then for each item in the first list, if it is in the list remove it
+					if (arr.Contains(obj))
+					{
+						arr.Remove(obj);
+					}
+					else
+					{
+						//and if it isn't in the list add it
+						arr.Add(obj);
+					}
+				}
+			}
+
+			return arr.ToArray();
+		}
+
+		public static int IndexOf(object[] items, object item)
+		{
+			for (int i = 0; i<items.Length; i++)
+			{
+				if (items[i].Equals(item))
+				{
+					return i;
+				}
+			}
+
+			return -1;
+		}
+
+		public static bool Contains(object[] items, object item)
+		{
+			return IndexOf(items, item) != -1;
+		}
+	}
+}
--- a/AssemblyInfo.cs	Tue May 19 19:55:21 2009 +0000
+++ b/AssemblyInfo.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -1,58 +1,58 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-//
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly: AssemblyTitle("IBBoard utility library")]
-[assembly: AssemblyDescription("A collection of utility functions and common classes")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("IBBoard 2007, 2009")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]		
-
-//
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers 
-// by using the '*' as shown below:
-
-[assembly: AssemblyVersion("1.0.*")]
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the 
-// Microsoft .NET Framework documentation for more information on assembly signing.
-//
-// Use the attributes below to control which key is used for signing. 
-//
-// Notes: 
-//   (*) If no key is specified, the assembly is not signed.
-//   (*) KeyName refers to a key that has been installed in the Crypto Service
-//       Provider (CSP) on your machine. KeyFile refers to a file which contains
-//       a key.
-//   (*) If the KeyFile and the KeyName values are both specified, the 
-//       following processing occurs:
-//       (1) If the KeyName can be found in the CSP, that key is used.
-//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
-//           in the KeyFile is installed into the CSP and used.
-//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
-//       When specifying the KeyFile, the location of the KeyFile should be
-//       relative to the project output directory which is
-//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
-//       located in the project directory, you would specify the AssemblyKeyFile 
-//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
-//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-//       documentation for more information on this.
-//
-[assembly: AssemblyDelaySign(false)]
-[assembly: AssemblyKeyFile("")]
-[assembly: AssemblyKeyName("")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("IBBoard utility library")]
+[assembly: AssemblyDescription("A collection of utility functions and common classes")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("IBBoard 2007, 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
--- a/Commands/Command.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Commands/Command.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,25 +2,25 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.Commands
-{
-	/// <summary>
-	/// Summary description for Command.
-	/// </summary>
-	public abstract class Command
-	{
-		public Command()
-		{
-		}
-
-		public abstract bool CanExecute();
-		public abstract bool Execute();
-		public abstract void Undo();
-		public abstract void Redo();
-		public abstract string Name { get; }
-		public abstract string Description { get; }
-		public abstract string UndoDescription { get; }
-	}
-}
+using System;
+
+namespace IBBoard.Commands
+{
+	/// <summary>
+	/// Summary description for Command.
+	/// </summary>
+	public abstract class Command
+	{
+		public Command()
+		{
+		}
+
+		public abstract bool CanExecute();
+		public abstract bool Execute();
+		public abstract void Undo();
+		public abstract void Redo();
+		public abstract string Name { get; }
+		public abstract string Description { get; }
+		public abstract string UndoDescription { get; }
+	}
+}
--- a/Commands/CommandStack.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Commands/CommandStack.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,179 +2,179 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.Collections;
-
-namespace IBBoard.Commands
-{
-	/// <summary>
-	/// Summary description for CommandStack.
-	/// </summary>
-	public class CommandStack
-	{
-		private ArrayList commandStack;
-		private int listPos = -1;
-		private int listMax = -1;
-		private int cleanPos;
-
-		public event MethodInvoker CommandStackUpdated;
-
-		public CommandStack()
-		{
-			commandStack = new ArrayList(10);
-			cleanPos = -1;
-		}
-
-		public bool IsDirty()
-		{
-			return listPos!=cleanPos;
-		}
-
-		public void setCleanMark()
-		{
-			cleanPos = listPos;
-		}
-
-		public bool IsEmpty()
-		{
-			return listMax == -1;
-		}
-
-		public bool CanUndo()
-		{
-			return listPos > -1;
-		}
-
-		public int UndoLength
-		{
-			get { return listPos + 1; }
-		}
-
-		public int RedoLength
-		{
-			get { return listMax - listPos; }
-		}
-
-		public bool CanRedo()
-		{
-			return listPos < listMax;
-		}
-
-		public void Reset()
-		{
-			commandStack.Clear();
-			listMax = -1;
-			listPos = -1;
-			DoCommandStackUpdated();
-		}
-
-		public void Undo()
-		{
-			if (CanUndo())
-			{
-				((Command)commandStack[listPos]).Undo();
-				listPos--;
-				DoCommandStackUpdated();
-			}
-			else
-			{
-				throw new InvalidOperationException("Cannot undo action on empty command stack");
-			}
-		}
-
-		public void Redo()
-		{
-			if (CanRedo())
-			{
-				((Command)commandStack[listPos+1]).Redo();
-				listPos++;
-				DoCommandStackUpdated();
-			}
-			else
-			{
-				throw new InvalidOperationException("No actions to redo");
-			}
-		}
-
-		public bool Execute(Command cmd)
-		{
-			if (cmd.CanExecute())
-			{
-				if (cmd.Execute())
-				{
-					//if we can't redo, i.e. there's no commands beyond our current point, add to the end else insert
-					if (!CanRedo())
-					{
-						commandStack.Add(cmd);
-						listPos++;
-					}
-					else
-					{
-						if (cleanPos>listPos)
-						{
-							cleanPos = -2;
-						}
-
-						//else overwrite at our current position, setting the listMax value will ignore any commands we could have redone beyond here
-						commandStack[++listPos] = cmd;
-					}
-
-					listMax = listPos;
-					DoCommandStackUpdated();
-					return true;
-				}
-				else
-				{
-					throw new InvalidOperationException("Executable command failed to execute");
-				}
-			}
-			else
-			{
-				return false;
-			}
-		}
-
-		protected void DoCommandStackUpdated()
-		{
-			if (CommandStackUpdated!=null)
-			{
-				CommandStackUpdated();
-			}
-		}
-
-		public Command PeekUndoCommand()
-		{
-			return PeekUndoCommand(1);
-		}
-
-		public Command PeekUndoCommand(int backCount)
-		{
-			backCount = backCount - 1;
-			if (backCount > -1 && backCount <= listPos)
-			{
-				return (Command)commandStack[listPos-backCount];
-			}
-			else
-			{
-				return null;
-			}
-		}
-
-		public Command PeekRedoCommand()
-		{
-			return PeekRedoCommand(1);
-		}
-
-		public Command PeekRedoCommand(int forwardCount)
-		{
-			if (forwardCount > 0 && listPos+forwardCount <= listMax)
-			{
-				return (Command)commandStack[listPos+forwardCount];
-			}
-			else
-			{
-				return null;
-			}
-		}
-	}
-}
+using System;
+using System.Collections;
+
+namespace IBBoard.Commands
+{
+	/// <summary>
+	/// Summary description for CommandStack.
+	/// </summary>
+	public class CommandStack
+	{
+		private ArrayList commandStack;
+		private int listPos = -1;
+		private int listMax = -1;
+		private int cleanPos;
+
+		public event MethodInvoker CommandStackUpdated;
+
+		public CommandStack()
+		{
+			commandStack = new ArrayList(10);
+			cleanPos = -1;
+		}
+
+		public bool IsDirty()
+		{
+			return listPos!=cleanPos;
+		}
+
+		public void setCleanMark()
+		{
+			cleanPos = listPos;
+		}
+
+		public bool IsEmpty()
+		{
+			return listMax == -1;
+		}
+
+		public bool CanUndo()
+		{
+			return listPos > -1;
+		}
+
+		public int UndoLength
+		{
+			get { return listPos + 1; }
+		}
+
+		public int RedoLength
+		{
+			get { return listMax - listPos; }
+		}
+
+		public bool CanRedo()
+		{
+			return listPos < listMax;
+		}
+
+		public void Reset()
+		{
+			commandStack.Clear();
+			listMax = -1;
+			listPos = -1;
+			DoCommandStackUpdated();
+		}
+
+		public void Undo()
+		{
+			if (CanUndo())
+			{
+				((Command)commandStack[listPos]).Undo();
+				listPos--;
+				DoCommandStackUpdated();
+			}
+			else
+			{
+				throw new InvalidOperationException("Cannot undo action on empty command stack");
+			}
+		}
+
+		public void Redo()
+		{
+			if (CanRedo())
+			{
+				((Command)commandStack[listPos+1]).Redo();
+				listPos++;
+				DoCommandStackUpdated();
+			}
+			else
+			{
+				throw new InvalidOperationException("No actions to redo");
+			}
+		}
+
+		public bool Execute(Command cmd)
+		{
+			if (cmd.CanExecute())
+			{
+				if (cmd.Execute())
+				{
+					//if we can't redo, i.e. there's no commands beyond our current point, add to the end else insert
+					if (!CanRedo())
+					{
+						commandStack.Add(cmd);
+						listPos++;
+					}
+					else
+					{
+						if (cleanPos>listPos)
+						{
+							cleanPos = -2;
+						}
+
+						//else overwrite at our current position, setting the listMax value will ignore any commands we could have redone beyond here
+						commandStack[++listPos] = cmd;
+					}
+
+					listMax = listPos;
+					DoCommandStackUpdated();
+					return true;
+				}
+				else
+				{
+					throw new InvalidOperationException("Executable command failed to execute");
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		protected void DoCommandStackUpdated()
+		{
+			if (CommandStackUpdated!=null)
+			{
+				CommandStackUpdated();
+			}
+		}
+
+		public Command PeekUndoCommand()
+		{
+			return PeekUndoCommand(1);
+		}
+
+		public Command PeekUndoCommand(int backCount)
+		{
+			backCount = backCount - 1;
+			if (backCount > -1 && backCount <= listPos)
+			{
+				return (Command)commandStack[listPos-backCount];
+			}
+			else
+			{
+				return null;
+			}
+		}
+
+		public Command PeekRedoCommand()
+		{
+			return PeekRedoCommand(1);
+		}
+
+		public Command PeekRedoCommand(int forwardCount)
+		{
+			if (forwardCount > 0 && listPos+forwardCount <= listMax)
+			{
+				return (Command)commandStack[listPos+forwardCount];
+			}
+			else
+			{
+				return null;
+			}
+		}
+	}
+}
--- a/Constants.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Constants.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,35 +2,35 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.IO;
-
-namespace IBBoard
-{
-	/// <summary>
-	/// Summary description for Constants.
-	/// </summary>
-	public class Constants
-	{
-		public static readonly char DirectoryChar = Path.DirectorySeparatorChar;
+using System;
+using System.IO;
+
+namespace IBBoard
+{
+	/// <summary>
+	/// Summary description for Constants.
+	/// </summary>
+	public class Constants
+	{
+		public static readonly char DirectoryChar = Path.DirectorySeparatorChar;
 		public static readonly string DirectoryString = Path.DirectorySeparatorChar.ToString();
 		private static string executablePath = AppDomain.CurrentDomain.BaseDirectory.TrimEnd(DirectoryChar);
 
 		static Constants()
-		{
-            string exe = Environment.GetCommandLineArgs()[0];
-            int slash = exe.LastIndexOf(DirectoryChar) + 1;
-            int dot = exe.LastIndexOf('.');
-
-            if (dot > slash)
-            {
-                exe = exe.Substring(slash, dot - slash);
-            }
-            else
-            {
-                exe = exe.Substring(slash);
-            }
-
+		{
+            string exe = Environment.GetCommandLineArgs()[0];
+            int slash = exe.LastIndexOf(DirectoryChar) + 1;
+            int dot = exe.LastIndexOf('.');
+
+            if (dot > slash)
+            {
+                exe = exe.Substring(slash, dot - slash);
+            }
+            else
+            {
+                exe = exe.Substring(slash);
+            }
+
             userDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).TrimEnd(DirectoryChar) + DirectoryChar + "IBBoard" + DirectoryChar + exe;
 		}
 
@@ -52,6 +52,6 @@
 			{
 				userDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)+DirectoryChar+path.Trim(DirectoryChar);
 			}
-		}*/
-	}
-}
+		}*/
+	}
+}
--- a/CustomMath/Comparisons.cs	Tue May 19 19:55:21 2009 +0000
+++ b/CustomMath/Comparisons.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,21 +2,21 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.CustomMath
-{
-	/// <summary>
-	/// Summary description for Comparisons.
-	/// </summary>
-	public class Comparisons
-	{
-		public static bool ValueWithinAmount(int baseline, int val, int delta)
-		{
-			int top = baseline + delta;
-			int bottom = baseline - delta;
-
-			return (val<=top && val>=bottom);
-		}
-	}
-}
+using System;
+
+namespace IBBoard.CustomMath
+{
+	/// <summary>
+	/// Summary description for Comparisons.
+	/// </summary>
+	public class Comparisons
+	{
+		public static bool ValueWithinAmount(int baseline, int val, int delta)
+		{
+			int top = baseline + delta;
+			int bottom = baseline - delta;
+
+			return (val<=top && val>=bottom);
+		}
+	}
+}
--- a/IBBoard.cs	Tue May 19 19:55:21 2009 +0000
+++ b/IBBoard.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,10 +2,10 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard
+using System;
+
+namespace IBBoard
 {
-	public delegate void MethodInvoker();
-	public delegate void PropertySetterInvoker(object obj, object val, object[] index);
-}
+	public delegate void MethodInvoker();
+	public delegate void PropertySetterInvoker(object obj, object val, object[] index);
+}
--- a/IO/InvalidFileException.cs	Tue May 19 19:55:21 2009 +0000
+++ b/IO/InvalidFileException.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,19 +2,19 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.IO
-{
-	/// <summary>
-	/// An exception thrown when the content of a file does not meet the requirements of that file.
-	/// </summary>
-	public class InvalidFileException : Exception
-	{
-		public InvalidFileException() : base() {}
-
-		public InvalidFileException(string message) : base(message) {}
-
-		public InvalidFileException(string message, Exception innerException) : base(message, innerException) {}
-	}
-}
+using System;
+
+namespace IBBoard.IO
+{
+	/// <summary>
+	/// An exception thrown when the content of a file does not meet the requirements of that file.
+	/// </summary>
+	public class InvalidFileException : Exception
+	{
+		public InvalidFileException() : base() {}
+
+		public InvalidFileException(string message) : base(message) {}
+
+		public InvalidFileException(string message, Exception innerException) : base(message, innerException) {}
+	}
+}
--- a/IO/UnsupportedFileTypeException.cs	Tue May 19 19:55:21 2009 +0000
+++ b/IO/UnsupportedFileTypeException.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,25 +2,25 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.IO
-{
-	/// <summary>
-	/// Summary description for UnsupportedFileTypeException.
-	/// </summary>
-	public class UnsupportedFileTypeException : Exception
-	{
-		public UnsupportedFileTypeException(): base("Operation attempted on an unsupported file type")
-		{
-		}
-
-		public UnsupportedFileTypeException(string fileType):base("Operation attempted on an unsupported file type ("+fileType+")")
-		{
-		}
-
-		public UnsupportedFileTypeException(string fileType, string operation):base("Operation "+operation+" does not support file type "+fileType)
-		{
-		}
-	}
-}
+using System;
+
+namespace IBBoard.IO
+{
+	/// <summary>
+	/// Summary description for UnsupportedFileTypeException.
+	/// </summary>
+	public class UnsupportedFileTypeException : Exception
+	{
+		public UnsupportedFileTypeException(): base("Operation attempted on an unsupported file type")
+		{
+		}
+
+		public UnsupportedFileTypeException(string fileType):base("Operation attempted on an unsupported file type ("+fileType+")")
+		{
+		}
+
+		public UnsupportedFileTypeException(string fileType, string operation):base("Operation "+operation+" does not support file type "+fileType)
+		{
+		}
+	}
+}
--- a/Lang/ITranslatable.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Lang/ITranslatable.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,16 +2,16 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.Lang
-{
-	/// <summary>
-	/// Summary description for ITranslatable.
-	/// </summary>
-	public interface ITranslatable
-	{
-		string Name{ get; set;}
-		string Text{ get; set;}
-	}
-}
+using System;
+
+namespace IBBoard.Lang
+{
+	/// <summary>
+	/// Summary description for ITranslatable.
+	/// </summary>
+	public interface ITranslatable
+	{
+		string Name{ get; set;}
+		string Text{ get; set;}
+	}
+}
--- a/Lang/StringManipulation.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Lang/StringManipulation.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,26 +2,26 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.Text;
-
-namespace IBBoard.Lang
-{
-	/// <summary>
-	/// Summary description for StringManipulation.
-	/// </summary>
-	public class StringManipulation
-	{		
-		private static Encoding utf8;
-
-		static StringManipulation()
-		{
-			utf8 = Encoding.UTF8;
-		}
-
-		public static byte[] StringToBytes(string str)
-		{
-			return utf8.GetBytes(str);
+using System;
+using System.Text;
+
+namespace IBBoard.Lang
+{
+	/// <summary>
+	/// Summary description for StringManipulation.
+	/// </summary>
+	public class StringManipulation
+	{		
+		private static Encoding utf8;
+
+		static StringManipulation()
+		{
+			utf8 = Encoding.UTF8;
+		}
+
+		public static byte[] StringToBytes(string str)
+		{
+			return utf8.GetBytes(str);
 		}
 
 		public static string ByteArrayToHexString(byte[] arr)
@@ -40,27 +40,27 @@
 			}
 
 			return sb.ToString().TrimEnd();
-		}
-
-		public static string RemoveFromLast(string stringToTrim, char removeFrom)
-		{
-			return stringToTrim.Substring(0, stringToTrim.LastIndexOf(removeFrom));
-		}
-
-		public static string CutToLength(string stringToShorten, int length)
-		{
-			int strLength = stringToShorten.Length;
-
-			if (length >= strLength-2)
-			{
-				return stringToShorten;
-			}
-			else
-			{
-				int diff = (strLength - length) / 2;
-				int halfLength = strLength / 2;
-				return stringToShorten.Substring(0, halfLength - diff)+"..."+stringToShorten.Substring(halfLength + diff);
-			}
-		}
-	}
-}
+		}
+
+		public static string RemoveFromLast(string stringToTrim, char removeFrom)
+		{
+			return stringToTrim.Substring(0, stringToTrim.LastIndexOf(removeFrom));
+		}
+
+		public static string CutToLength(string stringToShorten, int length)
+		{
+			int strLength = stringToShorten.Length;
+
+			if (length >= strLength-2)
+			{
+				return stringToShorten;
+			}
+			else
+			{
+				int diff = (strLength - length) / 2;
+				int halfLength = strLength / 2;
+				return stringToShorten.Substring(0, halfLength - diff)+"..."+stringToShorten.Substring(halfLength + diff);
+			}
+		}
+	}
+}
--- a/Lang/Translation.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Lang/Translation.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,33 +2,33 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.IO;
+using System;
+using System.IO;
 using System.Xml;
-using System.Xml.Schema;
-using System.Collections.Generic;
-using System.Reflection;
+using System.Xml.Schema;
+using System.Collections.Generic;
+using System.Reflection;
 using System.ComponentModel;
 using IBBoard.IO;
-using IBBoard.Logging;
-using IBBoard.Xml;
-
-namespace IBBoard.Lang
-{
-	/// <summary>
+using IBBoard.Logging;
+using IBBoard.Xml;
+
+namespace IBBoard.Lang
+{
+	/// <summary>
 	/// A basic string translator that loads a default language and a specified language and returns translated strings that correspond to translation IDs. 
 	/// If the string doesn't exist in the specified language then the translator falls back to the default language. If the translation doesn't exist in the default language
-	/// then either a supplied value or a "no validation available" message is returned.
-	/// </summary>
-	public class Translation
+	/// then either a supplied value or a "no validation available" message is returned.
+	/// </summary>
+	public class Translation
 	{		
 		private static readonly string DEFAULT_LANGUAGE = "en";
-		private static readonly string DIVIDER_STRING = "-";
-		private static string lang = "";
-		private static DirectoryInfo translationDir;
-		private static Dictionary<string, string> translationsLocal;
+		private static readonly string DIVIDER_STRING = "-";
+		private static string lang = "";
+		private static DirectoryInfo translationDir;
+		private static Dictionary<string, string> translationsLocal;
 		private static Dictionary<string, string> translationsDefault;
-		private static XmlReaderSettings settings;
+		private static XmlReaderSettings settings;
 
 		/// <summary>
 		/// Initialises the translations for the language specified and the default translations so that the Translation class can be used.
@@ -40,29 +40,29 @@
 		/// </param>
 		/// <param name="language">
 		/// The language to use as the load language
-		/// </param>
-		public static void InitialiseTranslations(string appPath, string language)
+		/// </param>
+		public static void InitialiseTranslations(string appPath, string language)
 		{
 			InitialiseDefaults(appPath);
-			FileInfo file = GetTranslationFile(DEFAULT_LANGUAGE);
-			XmlDocument doc = LoadTranslationDocument(file);
-			LoadTranslationsFromDocument(doc, translationsDefault);
-			LoadTranslationForLanguage(language);
+			FileInfo file = GetTranslationFile(DEFAULT_LANGUAGE);
+			XmlDocument doc = LoadTranslationDocument(file);
+			LoadTranslationsFromDocument(doc, translationsDefault);
+			LoadTranslationForLanguage(language);
 		}
 		
 		private static void InitialiseDefaults(string appPath)
 		{
-			string translationPath = appPath.TrimEnd(Constants.DirectoryChar) + Constants.DirectoryString + "translations";
-
-			if (Directory.Exists(translationPath))
+			string translationPath = appPath.TrimEnd(Constants.DirectoryChar) + Constants.DirectoryString + "translations";
+
+			if (Directory.Exists(translationPath))
 			{
 				translationsDefault = new Dictionary<string,string>();
-				translationsLocal = new Dictionary<string,string>();
-				translationDir = new DirectoryInfo(translationPath);
-			}
-			else
-			{
-				throw new TranslationLoadException("Translation path not found ("+translationPath+")");
+				translationsLocal = new Dictionary<string,string>();
+				translationDir = new DirectoryInfo(translationPath);
+			}
+			else
+			{
+				throw new TranslationLoadException("Translation path not found ("+translationPath+")");
 			}
 		}
 		
@@ -72,7 +72,7 @@
 			XmlReader valReader = XmlReader.Create(file.FullName, GetReaderSettings());
 			
 			try
-			{
+			{
 				doc.Load(valReader);
 			}
 			catch (DirectoryNotFoundException ex)
@@ -88,7 +88,7 @@
 				throw new TranslationLoadException("Problem reading data for translation: " + ex.Message, ex);
 			}
 			finally
-			{
+			{
 				valReader.Close();
 			}
 			
@@ -135,11 +135,11 @@
 		
 		private static FileInfo GetTranslationFile(string language)
 		{
-			FileInfo file = new FileInfo(translationDir.FullName + Constants.DirectoryString + language + ".translation");
-
-			if (!file.Exists)
-			{
-				throw new TranslationLoadException(language + ".translation could not be found in "+translationDir.FullName);
+			FileInfo file = new FileInfo(translationDir.FullName + Constants.DirectoryString + language + ".translation");
+
+			if (!file.Exists)
+			{
+				throw new TranslationLoadException(language + ".translation could not be found in "+translationDir.FullName);
 			}
 			
 			return file;
@@ -147,14 +147,14 @@
 		
 		private static void LoadTranslationsFromDocument(XmlDocument doc, Dictionary<string, string> translationTable)
 		{
-			try
-			{
+			try
+			{
 				XmlNodeList translations = doc.GetElementsByTagName("translation");				
-				Dictionary<string, string> tempTranslationTable = new Dictionary<string,string>();
-
-				foreach (XmlNode node in translations)
-				{
-					tempTranslationTable.Add(node.Attributes["id"].Value, node.InnerText);
+				Dictionary<string, string> tempTranslationTable = new Dictionary<string,string>();
+
+				foreach (XmlNode node in translations)
+				{
+					tempTranslationTable.Add(node.Attributes["id"].Value, node.InnerText);
 				}
 				
 				translationTable.Clear();
@@ -164,11 +164,11 @@
 					string translation;
 					tempTranslationTable.TryGetValue(key, out translation);
 					translationTable.Add(key, translation);
-				}
-			}
-			catch(Exception ex)
-			{
-				throw new TranslationLoadException("Error while parsing " + GetLanguageOfDocument(doc)+" translation: "+ex.Message, ex);
+				}
+			}
+			catch(Exception ex)
+			{
+				throw new TranslationLoadException("Error while parsing " + GetLanguageOfDocument(doc)+" translation: "+ex.Message, ex);
 			}	
 		}
 		
@@ -180,7 +180,7 @@
 		private static void ValidationEventMethod(object sender, ValidationEventArgs e)
 		{
 			throw new TranslationLoadException("Problem validating schema for translation: " + e.Exception.Message, e.Exception);
-		}
+		}
 
 		/// <summary>
 		/// Loads translations for a given language and sets them as the local language.
@@ -189,34 +189,34 @@
 		/// </summary>
 		/// <param name="translationLang">
 		/// The new local language to load
-		/// </param>
-		public static void LoadTranslation(string translationLanguage)
+		/// </param>
+		public static void LoadTranslation(string translationLanguage)
 		{			
 			if (translationLanguage == "" || translationLanguage == null)
 			{
 				throw new ArgumentException("Translation language cannot be null or empty");
-			}
-
-			LoadTranslationForLanguage(translationLanguage);
+			}
+
+			LoadTranslationForLanguage(translationLanguage);
 		}
 		
 		private static void LoadTranslationForLanguage(string translationLanguage)
-		{
+		{
 			CheckInitialisation();
 			
-			if (translationLanguage != DEFAULT_LANGUAGE && translationLanguage != "" && translationLanguage != null)
-			{
-				FileInfo file = GetTranslationFile(translationLanguage);
-				XmlDocument doc = LoadTranslationDocument(file);
-				LoadTranslationsFromDocument(doc, translationsLocal);	
+			if (translationLanguage != DEFAULT_LANGUAGE && translationLanguage != "" && translationLanguage != null)
+			{
+				FileInfo file = GetTranslationFile(translationLanguage);
+				XmlDocument doc = LoadTranslationDocument(file);
+				LoadTranslationsFromDocument(doc, translationsLocal);	
 			}
 			else
 			{
 				translationsLocal.Clear();				
 			}
-			
+			
 			lang = translationLanguage;
-		}
+		}
 
 		/// <summary>
 		/// Gets a translation for a given ID, falling back to a "missing translation" message if none can be found. Also optionally replaces any placeholders with the supplied values.
@@ -229,11 +229,11 @@
 		/// </param>
 		/// <returns>
 		/// The translation with the placeholders replaced or a "missing translation" message
-		/// </returns>
-		public static string GetTranslation(string translationID, params object[] replacements)
-		{
-			return GetTranslation(translationID, false, replacements);
-		}
+		/// </returns>
+		public static string GetTranslation(string translationID, params object[] replacements)
+		{
+			return GetTranslation(translationID, false, replacements);
+		}
 
 		/// <summary>
 		/// Gets a translation for a given ID, falling back to null or a warning message if a translation cannot be found. Also optionally replaces any placeholders with the supplied values.
@@ -249,11 +249,11 @@
 		/// </param>
 		/// <returns>
 		/// The translation with the placeholders replaced, or a "missing translation" message or null depending on <param name="returnNullOnFail">
-		/// </returns>
-		public static string GetTranslation(string translationID, bool returnNullOnFail, params object[] replacements)
-		{
-			return GetTranslation(translationID, returnNullOnFail ? null : "", replacements);
-		}
+		/// </returns>
+		public static string GetTranslation(string translationID, bool returnNullOnFail, params object[] replacements)
+		{
+			return GetTranslation(translationID, returnNullOnFail ? null : "", replacements);
+		}
 
 		/// <summary>
 		/// Gets a translation for a given ID, falling back to a supplied default if a translation cannot be found. Also optionally replaces any placeholders with the supplied values.
@@ -269,34 +269,34 @@
 		/// </param>
 		/// <returns>
 		/// The translation, if one exists, or the supplied default with the placeholders replaced
-		/// </returns>
-		public static string GetTranslation(string translationID, string defaultTranslation, params object[] replacements)
-		{
-			CheckInitialisation();
-			string trans = GetTranslationFromTables(translationID);
-			
-			if (trans == null)
-			{
-				trans = GetDefaultTranslation(translationID, defaultTranslation);
-			}
-
-			trans = AddVariablesToTranslation(trans, replacements);
-
-			return trans;
+		/// </returns>
+		public static string GetTranslation(string translationID, string defaultTranslation, params object[] replacements)
+		{
+			CheckInitialisation();
+			string trans = GetTranslationFromTables(translationID);
+			
+			if (trans == null)
+			{
+				trans = GetDefaultTranslation(translationID, defaultTranslation);
+			}
+
+			trans = AddVariablesToTranslation(trans, replacements);
+
+			return trans;
 		}
 		
 		private static string GetTranslationFromTables(string translationID)
 		{
 			string translation = null;
 			
-			if (translationsLocal!=null)
-			{
-				translationsLocal.TryGetValue(translationID, out translation);
-			}
-			
-			if (translation == null)
-			{
-				translationsDefault.TryGetValue(translationID, out translation);
+			if (translationsLocal!=null)
+			{
+				translationsLocal.TryGetValue(translationID, out translation);
+			}
+			
+			if (translation == null)
+			{
+				translationsDefault.TryGetValue(translationID, out translation);
 			}
 			
 			return translation;
@@ -305,7 +305,7 @@
 		private static string GetDefaultTranslation(string translationID, string defaultTranslation)
 		{
 			return (defaultTranslation != "" && defaultTranslation != null) ? defaultTranslation : GetMissingTranslationMessage(translationID);
-		}
+		}
 
 		private static string GetMissingTranslationMessage(string translationID)
 		{
@@ -314,21 +314,21 @@
 		
 		private static string AddVariablesToTranslation(string translation, object[] replacements)
 		{
-			if (translation != null && replacements != null && replacements.Length > 0)
-			{
-				translation = String.Format(translation, replacements);
+			if (translation != null && replacements != null && replacements.Length > 0)
+			{
+				translation = String.Format(translation, replacements);
 			}
 			
 			return translation;
 		}
 		
-		private static void CheckInitialisation()
-		{
-			if (translationDir==null)
-			{
-				throw new InvalidOperationException("Translation class has not been initialised");
-			}
-		}
+		private static void CheckInitialisation()
+		{
+			if (translationDir==null)
+			{
+				throw new InvalidOperationException("Translation class has not been initialised");
+			}
+		}
 
 		/// <summary>
 		/// Translate an <see cref="ITranslatable"/> item, with optional string replacement. If the translation
@@ -339,35 +339,35 @@
 		/// </param>
 		/// <param name="replacements">
 		/// A collection of <see cref="System.Object"/>s that will be used to fill place-holders
-		/// </param>
-		public static void Translate(ITranslatable item, params object[] replacements)
-		{
-			Translate(item, (string)null, replacements);
-		}
-
-		/// <summary>
-		/// Translate an <see cref="ITranslatable"/> item, with optional string replacement. The <code>defaultText</code>
-		/// can be used to specify an alternate translation. Passing <code>null</code> will result in a warning message
-		/// about a missing translation ID.
-		/// </summary>
-		/// <param name="item">
-		/// A <see cref="ITranslatable"/> to set the text for
-		/// </param>
-		/// <param name="defaultText">
-		/// The default string to display if no translation could be found.
-		/// </param>
-		/// <param name="replacements">
-		/// A collection of <see cref="System.Object"/>s that will be used to fill place-holders
-		/// </param>
-		public static void Translate(ITranslatable item, string defaultText, params object[] replacements)
-		{
-			if (item.Text == "" || item.Text == DIVIDER_STRING)
-			{
-				//it doesn't need translating - either there is no text from the developer or it's a hyphen for a divider
-				return;
-			}
-
-			item.Text = GetTranslation(item.Name, defaultText, replacements);
+		/// </param>
+		public static void Translate(ITranslatable item, params object[] replacements)
+		{
+			Translate(item, (string)null, replacements);
+		}
+
+		/// <summary>
+		/// Translate an <see cref="ITranslatable"/> item, with optional string replacement. The <code>defaultText</code>
+		/// can be used to specify an alternate translation. Passing <code>null</code> will result in a warning message
+		/// about a missing translation ID.
+		/// </summary>
+		/// <param name="item">
+		/// A <see cref="ITranslatable"/> to set the text for
+		/// </param>
+		/// <param name="defaultText">
+		/// The default string to display if no translation could be found.
+		/// </param>
+		/// <param name="replacements">
+		/// A collection of <see cref="System.Object"/>s that will be used to fill place-holders
+		/// </param>
+		public static void Translate(ITranslatable item, string defaultText, params object[] replacements)
+		{
+			if (item.Text == "" || item.Text == DIVIDER_STRING)
+			{
+				//it doesn't need translating - either there is no text from the developer or it's a hyphen for a divider
+				return;
+			}
+
+			item.Text = GetTranslation(item.Name, defaultText, replacements);
 		}
 		
 		/// <summary>
@@ -379,6 +379,6 @@
 		public static string GetTranslationLanguage()
 		{
 			return lang;
-		}
-	}
-}
+		}
+	}
+}
--- a/Logging/FileLogger.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Logging/FileLogger.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -30,9 +30,9 @@
 			return MakeLogFilePath(Constants.UserDataPath);
 		}
 		
-		public static string MakeLogFilePath(string path)
-		{
-			return path.TrimEnd(IBBoard.Constants.DirectoryChar) + IBBoard.Constants.DirectoryChar + "logs" + IBBoard.Constants.DirectoryChar + String.Format("{0:yyyy-MM-dd-HHmmss}", DateTime.Now)+".log";
+		public static string MakeLogFilePath(string path)
+		{
+			return path.TrimEnd(IBBoard.Constants.DirectoryChar) + IBBoard.Constants.DirectoryChar + "logs" + IBBoard.Constants.DirectoryChar + String.Format("{0:yyyy-MM-dd-HHmmss}", DateTime.Now)+".log";
 		}
 		
 		public static FileStream CreateDefaultLogFileStream()
--- a/Logging/LogItem.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Logging/LogItem.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -6,47 +6,47 @@
 
 namespace IBBoard.Logging
 {
-	public class LogItem 
-	{
-		private LogLevel logLevel;
-		private string logMessage, stacktrace;
-		private DateTime occurance;
-
-		public LogItem(LogLevel level, string message) : this(level, message, "")
-		{
-		}
-
-		public LogItem(LogLevel level, string message, string stack)
-		{
-			logLevel = level;
-			logMessage = message;
-			occurance = DateTime.Now;
-			stacktrace = stack;
-		}
-
-		public LogLevel Level
-		{
-			get { return logLevel; }
-		}
-
-		public string Message
-		{
-			get { return logMessage; }
-		}
-
-		public DateTime OccuranceTime
-		{
-			get { return occurance; }
-		}
-
-		public override string ToString()
-		{
-			return OccuranceTime.ToString()+" ("+Level+"): "+Message;
-		}
-
-		public string StackTrace
-		{
-			get { return stacktrace; }
-		}
+	public class LogItem 
+	{
+		private LogLevel logLevel;
+		private string logMessage, stacktrace;
+		private DateTime occurance;
+
+		public LogItem(LogLevel level, string message) : this(level, message, "")
+		{
+		}
+
+		public LogItem(LogLevel level, string message, string stack)
+		{
+			logLevel = level;
+			logMessage = message;
+			occurance = DateTime.Now;
+			stacktrace = stack;
+		}
+
+		public LogLevel Level
+		{
+			get { return logLevel; }
+		}
+
+		public string Message
+		{
+			get { return logMessage; }
+		}
+
+		public DateTime OccuranceTime
+		{
+			get { return occurance; }
+		}
+
+		public override string ToString()
+		{
+			return OccuranceTime.ToString()+" ("+Level+"): "+Message;
+		}
+
+		public string StackTrace
+		{
+			get { return stacktrace; }
+		}
 	}
 }
--- a/Logging/Logger.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Logging/Logger.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,124 +2,124 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.IO;
-using System.Text;
-using System.Collections.Generic;
-
-namespace IBBoard.Logging
-{
-	public enum LogLevel {Debug = 1, Info = 2, Warning = 3, Error = 4, Critical = 5}
-	/// <summary>
-	/// Summary description for Logger.
-	/// </summary>
-	public abstract class Logger : TextWriter
-	{
-
-		protected LogLevel logLevel;
-		protected Stream stream;
-		protected UTF8Encoding encoding = new UTF8Encoding();
-		private List<LogItem> logMessages = new List<LogItem>();
-
-		public delegate void LogUpdatedDelegate(LogItem item);
-		public event LogUpdatedDelegate LogUpdatedEvent;
-
-		protected Logger(Stream logStream)
-		{
-			logLevel = LogLevel.Error;
+using System;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+
+namespace IBBoard.Logging
+{
+	public enum LogLevel {Debug = 1, Info = 2, Warning = 3, Error = 4, Critical = 5}
+	/// <summary>
+	/// Summary description for Logger.
+	/// </summary>
+	public abstract class Logger : TextWriter
+	{
+
+		protected LogLevel logLevel;
+		protected Stream stream;
+		protected UTF8Encoding encoding = new UTF8Encoding();
+		private List<LogItem> logMessages = new List<LogItem>();
+
+		public delegate void LogUpdatedDelegate(LogItem item);
+		public event LogUpdatedDelegate LogUpdatedEvent;
+
+		protected Logger(Stream logStream)
+		{
+			logLevel = LogLevel.Error;
 			stream = logStream;	
-			
-			//null stream means we're not actually logging out so we don't need to check it is writable
-			if (stream!=null)
-			{
-				if (!stream.CanWrite)
-				{
-					throw new ArgumentException("Log stream was not writable");
-				}
+			
+			//null stream means we're not actually logging out so we don't need to check it is writable
+			if (stream!=null)
+			{
+				if (!stream.CanWrite)
+				{
+					throw new ArgumentException("Log stream was not writable");
+				}
 			}
 			
-			LogMessageString("Log started at " + String.Format("{0:HH:mm:ss, yyyy-MM-dd}", DateTime.Now));
+			LogMessageString("Log started at " + String.Format("{0:HH:mm:ss, yyyy-MM-dd}", DateTime.Now));
 		}
 		
 		~Logger()
 		{
 			LogMessageString("Log closed at " + String.Format("{0:HH:mm:ss, yyyy-MM-dd}", DateTime.Now));
-		}
-
-		public LogLevel LogLevel
-		{
-			get { return logLevel; }
-			set { logLevel = value; }
-		}
-
-		public void Log(Exception ex, LogLevel level)
-		{
-			Log(ex.Message, ex.StackTrace, level);
-		}
-
-		public void Log(string message, LogLevel level)
-		{	
-			Log(message, "", level);
-		}
-
-		private void Log(string message, string stacktrace, LogLevel level)
-		{
-			if (level >= LogLevel)
-			{		
-				LogItem item = new LogItem(level, message, stacktrace);
-				LogMessage(item);
-				logMessages.Add(item);
-				OnLogUpdated(item);
-			}
-		}
-
-		private void OnLogUpdated(LogItem item)
-		{
-			if (LogUpdatedEvent!=null)
-			{
-				LogUpdatedEvent(item);
-			}
-		}
-
+		}
+
+		public LogLevel LogLevel
+		{
+			get { return logLevel; }
+			set { logLevel = value; }
+		}
+
+		public void Log(Exception ex, LogLevel level)
+		{
+			Log(ex.Message, ex.StackTrace, level);
+		}
+
+		public void Log(string message, LogLevel level)
+		{	
+			Log(message, "", level);
+		}
+
+		private void Log(string message, string stacktrace, LogLevel level)
+		{
+			if (level >= LogLevel)
+			{		
+				LogItem item = new LogItem(level, message, stacktrace);
+				LogMessage(item);
+				logMessages.Add(item);
+				OnLogUpdated(item);
+			}
+		}
+
+		private void OnLogUpdated(LogItem item)
+		{
+			if (LogUpdatedEvent!=null)
+			{
+				LogUpdatedEvent(item);
+			}
+		}
+
 		protected abstract void LogMessage(LogItem item);
-		protected abstract void LogMessageString(string str);
-
-		public void ResetInternalLog()
-		{
+		protected abstract void LogMessageString(string str);
+
+		public void ResetInternalLog()
+		{
 			logMessages = new List<IBBoard.Logging.LogItem>();
-			LogMessageString("Log reset at " + String.Format("{0:yyyy-MM-dd-HHmmss}", DateTime.Now));
-		}
-
-		public int LogLength
-		{
-			get { return logMessages.Count; }
-		}
-
-		public LogItem GetLogItem(int index)
-		{
-			if (index < LogLength)
-			{
-				return logMessages[index];
-			}
-			else
-			{
-				throw new IndexOutOfRangeException();
-			}
-		}
-
-		public LogItem[] GetLogItems(LogLevel minLogLevel)
-		{
-			List<LogItem> logItems = new List<LogItem>();
-
-			foreach (LogItem item in logMessages)
-			{
-				if (item.Level>=minLogLevel)
-				{
-					logItems.Add(item);
-				}
-			}
-
-			return logItems.ToArray();
+			LogMessageString("Log reset at " + String.Format("{0:yyyy-MM-dd-HHmmss}", DateTime.Now));
+		}
+
+		public int LogLength
+		{
+			get { return logMessages.Count; }
+		}
+
+		public LogItem GetLogItem(int index)
+		{
+			if (index < LogLength)
+			{
+				return logMessages[index];
+			}
+			else
+			{
+				throw new IndexOutOfRangeException();
+			}
+		}
+
+		public LogItem[] GetLogItems(LogLevel minLogLevel)
+		{
+			List<LogItem> logItems = new List<LogItem>();
+
+			foreach (LogItem item in logMessages)
+			{
+				if (item.Level>=minLogLevel)
+				{
+					logItems.Add(item);
+				}
+			}
+
+			return logItems.ToArray();
 		}
 		
 		//Allow the Logger to be used as the output point for System.Console.Error. In this case assume all messages are Error level
@@ -149,6 +149,6 @@
 		{
 			Write(value);	
 		}
-
-	}
-}
+
+	}
+}
--- a/Logging/SilentLogger.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Logging/SilentLogger.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,20 +2,20 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.Logging
-{
-	/// <summary>
-	/// Summary description for SilentLogger.
-	/// </summary>
-	public class SilentLogger : Logger
-	{
-		public SilentLogger() : base(null)
-		{
-		}
-
-		protected override void LogMessage(LogItem item)
+using System;
+
+namespace IBBoard.Logging
+{
+	/// <summary>
+	/// Summary description for SilentLogger.
+	/// </summary>
+	public class SilentLogger : Logger
+	{
+		public SilentLogger() : base(null)
+		{
+		}
+
+		protected override void LogMessage(LogItem item)
 		{
 			//Do nothing
 		}
@@ -24,6 +24,6 @@
 		{
 			//Do nothing
 		}
-
-	}
-}
+
+	}
+}
--- a/Logging/TextFileLogger.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Logging/TextFileLogger.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,39 +2,39 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
+using System;
 using System.IO;
-using IBBoard;
-
-namespace IBBoard.Logging
-{
-	/// <summary>
-	/// Summary description for FileLogger.
-	/// </summary>
-	public class TextFileLogger : FileLogger
+using IBBoard;
+
+namespace IBBoard.Logging
+{
+	/// <summary>
+	/// Summary description for FileLogger.
+	/// </summary>
+	public class TextFileLogger : FileLogger
 	{
 		public TextFileLogger() : base()
 		{
 		}
 		
-		public TextFileLogger(string path) : base(path)
-		{
-		}
-
-		protected override void LogMessage(LogItem item)
-		{
-			string stack = item.StackTrace;
-			string message = item.Message + Environment.NewLine + (stack!= "" ? stack + Environment.NewLine : "");
-			LogMessageString(message);
+		public TextFileLogger(string path) : base(path)
+		{
+		}
+
+		protected override void LogMessage(LogItem item)
+		{
+			string stack = item.StackTrace;
+			string message = item.Message + Environment.NewLine + (stack!= "" ? stack + Environment.NewLine : "");
+			LogMessageString(message);
 		}
 		
 		protected override void LogMessageString (string str)
 		{
 			str.TrimEnd();
 			str+= Environment.NewLine + Environment.NewLine;
-			stream.Write(encoding.GetBytes(str), 0, encoding.GetByteCount(str));
+			stream.Write(encoding.GetBytes(str), 0, encoding.GetByteCount(str));
 			stream.Flush();
 		}
-
-	}
-}
+
+	}
+}
--- a/Preferences.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Preferences.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,27 +2,27 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.Collections;
-using System.IO;
-using System.Xml;
+using System;
+using System.Collections;
+using System.IO;
+using System.Xml;
 using System.Reflection;
-using IBBoard.IO;
+using IBBoard.IO;
 
-//TODO: Add import/export
-namespace IBBoard
-{
-	/// <summary>
-	/// Summary description for Preferences.
-	/// </summary>
-	public class Preferences
-	{
-		private static Type stringType = typeof(string);
-		private static Type hashtableType = typeof(Hashtable);
-		private Hashtable htGlobal;
-		private Hashtable htLocal;
-
-		private string app;
+//TODO: Add import/export
+namespace IBBoard
+{
+	/// <summary>
+	/// Summary description for Preferences.
+	/// </summary>
+	public class Preferences
+	{
+		private static Type stringType = typeof(string);
+		private static Type hashtableType = typeof(Hashtable);
+		private Hashtable htGlobal;
+		private Hashtable htLocal;
+
+		private string app;
 		private bool modified = false;
 
 		
@@ -30,226 +30,226 @@
 		{
 			app = appName;
 			LoadPreferences();
-		}
-
-		/*public Preferences(string appExecPath, string appName, string fullUserDataDir)
-		{
-			LoadPreferences(appExecPath.TrimEnd(Constants.DirectoryChar) + Constants.DirectoryChar + appName + "Pref.xml", fullUserDataDir.TrimEnd(Constants.DirectoryChar));
-		}
-
-		public Preferences(string filepath, string appDir)
-		{
-			LoadPreferences(filepath, appDir);
-		}*/
-
-		private void LoadPreferences()
-		{
-			htGlobal = new Hashtable();
+		}
+
+		/*public Preferences(string appExecPath, string appName, string fullUserDataDir)
+		{
+			LoadPreferences(appExecPath.TrimEnd(Constants.DirectoryChar) + Constants.DirectoryChar + appName + "Pref.xml", fullUserDataDir.TrimEnd(Constants.DirectoryChar));
+		}
+
+		public Preferences(string filepath, string appDir)
+		{
+			LoadPreferences(filepath, appDir);
+		}*/
+
+		private void LoadPreferences()
+		{
+			htGlobal = new Hashtable();
 			htLocal = new Hashtable();
 			
 			string globalPath = Constants.ExecutablePath + Constants.DirectoryChar + app + "Pref.xml";
 			
 			if (File.Exists(globalPath))
-			{
-				XmlDocument xmld = new XmlDocument();
-				xmld.Load(globalPath);
-				XmlNodeList nl = xmld.LastChild.ChildNodes;
-				XmlNodeList nlHash;
-				MethodInfo m;
-				Type t;
-				Hashtable htTemp;
-
-				if (nl == null || nl.Count==0)
-				{
-					throw new InvalidFileException("Preference file "+globalPath+" did not contain any preferences");
-				}
-
-				for (int i = 0; i<nl.Count; i++)
-				{
-					t = Type.GetType(nl[i].Attributes["type"].Value, true);
-
-					if (t!=stringType)
-					{
-						if (t==hashtableType)
-						{
-							htTemp = new Hashtable();
-							nlHash = nl[i].ChildNodes;
-
-							for (int j = 0; j<nlHash.Count; j++)
-							{
-								if (nlHash[j].NodeType.GetType()==typeof(XmlElement))
-								{
-									t = Type.GetType(nlHash[j].Attributes["type"].Value, true);
-									m = t.GetMethod("Parse", new Type[]{stringType});
-									htTemp[nlHash[j].Attributes["key"].Value] = m.Invoke(null, new object[]{nlHash[j].InnerText});
-								}
-							}							
-
-							htGlobal[nl[i].Attributes["id"].Value] = htTemp;
-						}
-						else if (t.IsEnum)
-						{
-							htGlobal[nl[i].Attributes["id"].Value] = Enum.Parse(t, nl[i].InnerText, true);
-						}
-						else
-						{
-							m = t.GetMethod("Parse", new Type[]{stringType});
-							htGlobal[nl[i].Attributes["id"].Value] = m.Invoke(null, new object[]{nl[i].InnerText});
-						}
-					}
-					else
-					{
-						htGlobal[nl[i].Attributes["id"].Value] = nl[i].InnerText;
-					}
-				}
-				
-				LoadLocalPreferences();
-			}
-			else
-			{
-				throw new FileNotFoundException("Could not find default preferences at "+globalPath);
-			}
+			{
+				XmlDocument xmld = new XmlDocument();
+				xmld.Load(globalPath);
+				XmlNodeList nl = xmld.LastChild.ChildNodes;
+				XmlNodeList nlHash;
+				MethodInfo m;
+				Type t;
+				Hashtable htTemp;
+
+				if (nl == null || nl.Count==0)
+				{
+					throw new InvalidFileException("Preference file "+globalPath+" did not contain any preferences");
+				}
+
+				for (int i = 0; i<nl.Count; i++)
+				{
+					t = Type.GetType(nl[i].Attributes["type"].Value, true);
+
+					if (t!=stringType)
+					{
+						if (t==hashtableType)
+						{
+							htTemp = new Hashtable();
+							nlHash = nl[i].ChildNodes;
+
+							for (int j = 0; j<nlHash.Count; j++)
+							{
+								if (nlHash[j].NodeType.GetType()==typeof(XmlElement))
+								{
+									t = Type.GetType(nlHash[j].Attributes["type"].Value, true);
+									m = t.GetMethod("Parse", new Type[]{stringType});
+									htTemp[nlHash[j].Attributes["key"].Value] = m.Invoke(null, new object[]{nlHash[j].InnerText});
+								}
+							}							
+
+							htGlobal[nl[i].Attributes["id"].Value] = htTemp;
+						}
+						else if (t.IsEnum)
+						{
+							htGlobal[nl[i].Attributes["id"].Value] = Enum.Parse(t, nl[i].InnerText, true);
+						}
+						else
+						{
+							m = t.GetMethod("Parse", new Type[]{stringType});
+							htGlobal[nl[i].Attributes["id"].Value] = m.Invoke(null, new object[]{nl[i].InnerText});
+						}
+					}
+					else
+					{
+						htGlobal[nl[i].Attributes["id"].Value] = nl[i].InnerText;
+					}
+				}
+				
+				LoadLocalPreferences();
+			}
+			else
+			{
+				throw new FileNotFoundException("Could not find default preferences at "+globalPath);
+			}
 		}
-		
-		private void LoadLocalPreferences()
-		{
-			string path = Constants.UserDataPath + Constants.DirectoryString + "preferences.xml";
-
-			if (File.Exists(path))
-			{
-				XmlDocument xmld = new XmlDocument();
-				xmld.Load(path);
-				XmlNodeList nl = xmld.LastChild.ChildNodes;
-				XmlNodeList nlHash;
-				MethodInfo m;
-				Type t;
-				Hashtable htTemp = new Hashtable();
-
-				nl = xmld.LastChild.ChildNodes;
-
-				for (int i = 0; i<nl.Count; i++)
-				{
-					if (!htGlobal.ContainsKey(nl[i].Attributes["id"].Value))
-					{
-						throw new InvalidFileException("User preferences file contains a value for key \""+nl[i].Attributes["id"].Value+"\" which is not contained in the main preferences");
-					}
-
-					t = Type.GetType(nl[i].Attributes["type"].Value, true);
-					if (t!=stringType)
-					{
-						if (t==hashtableType)
-						{
-							htTemp = new Hashtable();
-							nlHash = nl[i].ChildNodes;
-							Hashtable htTempInner = new Hashtable();
-
-							for (int j = 0; j<nlHash.Count; j++)
-							{
-								if (nlHash[j].NodeType==XmlNodeType.Element)
-								{
-									t = Type.GetType(nlHash[j].Attributes["type"].Value, true);
-									m = t.GetMethod("Parse", new Type[]{stringType});
-									htTempInner[nlHash[j].Attributes["key"].Value] = m.Invoke(null, new object[]{nlHash[j].InnerText});
-								}
-							}							
-
-							htTemp[nl[i].Attributes["id"].Value] = htTempInner;
-						}
-						else if (t.IsEnum)
-						{
-							htTemp[nl[i].Attributes["id"].Value] = Enum.Parse(t, nl[i].InnerText, true);
-						}
-						else
-						{
+		
+		private void LoadLocalPreferences()
+		{
+			string path = Constants.UserDataPath + Constants.DirectoryString + "preferences.xml";
+
+			if (File.Exists(path))
+			{
+				XmlDocument xmld = new XmlDocument();
+				xmld.Load(path);
+				XmlNodeList nl = xmld.LastChild.ChildNodes;
+				XmlNodeList nlHash;
+				MethodInfo m;
+				Type t;
+				Hashtable htTemp = new Hashtable();
+
+				nl = xmld.LastChild.ChildNodes;
+
+				for (int i = 0; i<nl.Count; i++)
+				{
+					if (!htGlobal.ContainsKey(nl[i].Attributes["id"].Value))
+					{
+						throw new InvalidFileException("User preferences file contains a value for key \""+nl[i].Attributes["id"].Value+"\" which is not contained in the main preferences");
+					}
+
+					t = Type.GetType(nl[i].Attributes["type"].Value, true);
+					if (t!=stringType)
+					{
+						if (t==hashtableType)
+						{
+							htTemp = new Hashtable();
+							nlHash = nl[i].ChildNodes;
+							Hashtable htTempInner = new Hashtable();
+
+							for (int j = 0; j<nlHash.Count; j++)
+							{
+								if (nlHash[j].NodeType==XmlNodeType.Element)
+								{
+									t = Type.GetType(nlHash[j].Attributes["type"].Value, true);
+									m = t.GetMethod("Parse", new Type[]{stringType});
+									htTempInner[nlHash[j].Attributes["key"].Value] = m.Invoke(null, new object[]{nlHash[j].InnerText});
+								}
+							}							
+
+							htTemp[nl[i].Attributes["id"].Value] = htTempInner;
+						}
+						else if (t.IsEnum)
+						{
+							htTemp[nl[i].Attributes["id"].Value] = Enum.Parse(t, nl[i].InnerText, true);
+						}
+						else
+						{
 							m = t.GetMethod("Parse", new Type[]{stringType});
 							
 							if (m!=null)
-							{
+							{
 								htTemp[nl[i].Attributes["id"].Value] = m.Invoke(null, new object[]{nl[i].InnerText});
-							}
-						}
-					}
-					else
-					{
-						htTemp[nl[i].Attributes["id"].Value] = nl[i].InnerText;
-					}
-				}
-
-				htLocal = htTemp;
-			}
-		}
-
-		public void ReloadPreferences()
-		{
-			htLocal.Clear();
-			LoadLocalPreferences();
-		}
-
-		public object this[string key]
+							}
+						}
+					}
+					else
+					{
+						htTemp[nl[i].Attributes["id"].Value] = nl[i].InnerText;
+					}
+				}
+
+				htLocal = htTemp;
+			}
+		}
+
+		public void ReloadPreferences()
+		{
+			htLocal.Clear();
+			LoadLocalPreferences();
+		}
+
+		public object this[string key]
 		{
-			get { return this[key, true]; }
-
-			set
-			{
-				if (!htGlobal.ContainsKey(key))
-				{
-					throw new InvalidOperationException("Preference must already exist in the Global Preferences");
-				}
-
-				if (htGlobal[key].GetType()!=value.GetType())
-				{
-					throw new InvalidOperationException("Preferences must be set with an object of the same type as the existing preference");
-				}
-
-				if (value is Hashtable)
-				{
-					throw new InvalidOperationException("Hashtables in Preferences cannot be set, they can only be added to or removed from.");
-				}
-
-				if (htGlobal[key].Equals(value))
-				{
-					if (htLocal.ContainsKey(key))
-					{
-						htLocal.Remove(key);
-						modified = true;
-					}
-				}
-				else if (!((htLocal[key]==null && value==null) || value.Equals(htLocal[key])))
-				{
-					htLocal[key] = value;
-					modified = true;
-				}
-				//else nothing actually needs modifying
+			get { return this[key, true]; }
+
+			set
+			{
+				if (!htGlobal.ContainsKey(key))
+				{
+					throw new InvalidOperationException("Preference must already exist in the Global Preferences");
+				}
+
+				if (htGlobal[key].GetType()!=value.GetType())
+				{
+					throw new InvalidOperationException("Preferences must be set with an object of the same type as the existing preference");
+				}
+
+				if (value is Hashtable)
+				{
+					throw new InvalidOperationException("Hashtables in Preferences cannot be set, they can only be added to or removed from.");
+				}
+
+				if (htGlobal[key].Equals(value))
+				{
+					if (htLocal.ContainsKey(key))
+					{
+						htLocal.Remove(key);
+						modified = true;
+					}
+				}
+				else if (!((htLocal[key]==null && value==null) || value.Equals(htLocal[key])))
+				{
+					htLocal[key] = value;
+					modified = true;
+				}
+				//else nothing actually needs modifying
 			}
 		}
 		
 		public object this[string key, bool errorOnNoVal]
-		{
-			get
-			{
-				if (htLocal.ContainsKey(key))
-				{
-					return htLocal[key];
-				}
-				else if (htGlobal.ContainsKey(key))
-				{
-					if (htGlobal[key] is Hashtable)
-					{
-						htLocal[key] = ((Hashtable)htGlobal[key]).Clone();
-						return htLocal[key];
-					}
-					else
-					{
-						return htGlobal[key];
-					}
-				}
-				else if (errorOnNoVal)
-				{
-					throw new InvalidOperationException("Key \""+key+"\" was not associated with a preference value");
+		{
+			get
+			{
+				if (htLocal.ContainsKey(key))
+				{
+					return htLocal[key];
+				}
+				else if (htGlobal.ContainsKey(key))
+				{
+					if (htGlobal[key] is Hashtable)
+					{
+						htLocal[key] = ((Hashtable)htGlobal[key]).Clone();
+						return htLocal[key];
+					}
+					else
+					{
+						return htGlobal[key];
+					}
+				}
+				else if (errorOnNoVal)
+				{
+					throw new InvalidOperationException("Key \""+key+"\" was not associated with a preference value");
 				}
 								
-				return null;
-			}
+				return null;
+			}
 		}
 		
 		public bool GetBooleanProperty(string key)
@@ -278,91 +278,91 @@
 			return str;
 		}
 		
-		//public String
-
-		public bool IsModified()
-		{
-			return modified;
-		}
-
-		public void Save()
-		{
-			if (htLocal.Count>0)
-			{
-				XmlDocument xmld = new XmlDocument();
-				xmld.LoadXml("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"+
-					"<!DOCTYPE prefs["+
-					"<!ELEMENT preferences (preferece*)> "+
-					"<!ELEMENT preference (CDATA|prefsub)> "+
-					"<!ELEMENT prefsub (CDATA)> "+
-					"<!ATTLIST preference id ID #REQUIRED>"+
-					"<!ATTLIST preference type CDATA #REQUIRED>"+
-					"<!ATTLIST prefsub key CDATA #REQUIRED>"+
-					"<!ATTLIST prefsub type CDATA #REQUIRED>"+
-					"]>"+"<preferences></preferences>");
-				XmlNode xmln = xmld.LastChild;
-				XmlNode pref;
-				XmlAttribute attr;
-				XmlNode prefSub;
-				XmlAttribute attrSub;
-				object o;
-				Hashtable htTemp;
-				Hashtable htGlobalTemp;
-
-				foreach (string key in htLocal.Keys)
-				{
-					pref = xmld.CreateNode(XmlNodeType.Element, "preference","");
-					attr = xmld.CreateAttribute("id");
-					attr.Value = key;
-					pref.Attributes.Append(attr);
-					attr = xmld.CreateAttribute("type");
-					o = htLocal[key];
-
-					attr.Value = o.GetType().AssemblyQualifiedName;					
-
-					if (o.GetType().ToString() == "System.Collections.Hashtable")
-					{
-						htTemp = (Hashtable)o;
-						htGlobalTemp = (Hashtable)htGlobal[key];
-
-						foreach(object subkey in htTemp.Keys)
-						{
-							if (!htGlobalTemp.ContainsKey(subkey) || !htGlobalTemp[subkey].Equals(htTemp[subkey]))
-							{
-								prefSub = xmld.CreateNode(XmlNodeType.Element, "prefsub", "");
-								attrSub = xmld.CreateAttribute("key");
-								attrSub.Value = subkey.ToString();
-								prefSub.Attributes.Append(attrSub);
-								attrSub = xmld.CreateAttribute("type");
-								attrSub.Value = htTemp[subkey].GetType().AssemblyQualifiedName;
-								prefSub.Attributes.Append(attrSub);
-								prefSub.InnerText = htTemp[subkey].ToString();
-								pref.AppendChild(prefSub);
-							}
-						}
-					}
-					else
-					{
-						pref.InnerText = o.ToString();
-					}
-
-					pref.Attributes.Append(attr);
-					xmln.AppendChild(pref);
+		//public String
+
+		public bool IsModified()
+		{
+			return modified;
+		}
+
+		public void Save()
+		{
+			if (htLocal.Count>0)
+			{
+				XmlDocument xmld = new XmlDocument();
+				xmld.LoadXml("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"+
+					"<!DOCTYPE prefs["+
+					"<!ELEMENT preferences (preferece*)> "+
+					"<!ELEMENT preference (CDATA|prefsub)> "+
+					"<!ELEMENT prefsub (CDATA)> "+
+					"<!ATTLIST preference id ID #REQUIRED>"+
+					"<!ATTLIST preference type CDATA #REQUIRED>"+
+					"<!ATTLIST prefsub key CDATA #REQUIRED>"+
+					"<!ATTLIST prefsub type CDATA #REQUIRED>"+
+					"]>"+"<preferences></preferences>");
+				XmlNode xmln = xmld.LastChild;
+				XmlNode pref;
+				XmlAttribute attr;
+				XmlNode prefSub;
+				XmlAttribute attrSub;
+				object o;
+				Hashtable htTemp;
+				Hashtable htGlobalTemp;
+
+				foreach (string key in htLocal.Keys)
+				{
+					pref = xmld.CreateNode(XmlNodeType.Element, "preference","");
+					attr = xmld.CreateAttribute("id");
+					attr.Value = key;
+					pref.Attributes.Append(attr);
+					attr = xmld.CreateAttribute("type");
+					o = htLocal[key];
+
+					attr.Value = o.GetType().AssemblyQualifiedName;					
+
+					if (o.GetType().ToString() == "System.Collections.Hashtable")
+					{
+						htTemp = (Hashtable)o;
+						htGlobalTemp = (Hashtable)htGlobal[key];
+
+						foreach(object subkey in htTemp.Keys)
+						{
+							if (!htGlobalTemp.ContainsKey(subkey) || !htGlobalTemp[subkey].Equals(htTemp[subkey]))
+							{
+								prefSub = xmld.CreateNode(XmlNodeType.Element, "prefsub", "");
+								attrSub = xmld.CreateAttribute("key");
+								attrSub.Value = subkey.ToString();
+								prefSub.Attributes.Append(attrSub);
+								attrSub = xmld.CreateAttribute("type");
+								attrSub.Value = htTemp[subkey].GetType().AssemblyQualifiedName;
+								prefSub.Attributes.Append(attrSub);
+								prefSub.InnerText = htTemp[subkey].ToString();
+								pref.AppendChild(prefSub);
+							}
+						}
+					}
+					else
+					{
+						pref.InnerText = o.ToString();
+					}
+
+					pref.Attributes.Append(attr);
+					xmln.AppendChild(pref);
 				}
 				
 				if (!Directory.Exists(Constants.UserDataPath))
 				{
 					Directory.CreateDirectory(Constants.UserDataPath);
 				}
-				
-				xmld.Save(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml");
-			}
-			else if (File.Exists(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml"))
-			{
-				File.Delete(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml");
-			}
-
-			modified = false;
-		}
-	}
-}
+				
+				xmld.Save(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml");
+			}
+			else if (File.Exists(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml"))
+			{
+				File.Delete(Constants.UserDataPath + Constants.DirectoryString + "preferences.xml");
+			}
+
+			modified = false;
+		}
+	}
+}
--- a/UnixTimestamp.cs	Tue May 19 19:55:21 2009 +0000
+++ b/UnixTimestamp.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,47 +2,47 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard
-{
-	/// <summary>
-	/// Summary description for UnixTimestamp.
-	/// </summary>
-	public class UnixTimestamp
-	{
-		private long stamp;
-		private static DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime();
-
-		public UnixTimestamp(DateTime date)
-		{
-			stamp = GetTimestamp(date);
-		}
-
-		public UnixTimestamp(long timestamp)
-		{
-			stamp = timestamp;
-		}
-
-		public DateTime GetDate()
-		{
-			return unixEpoch.AddSeconds(stamp);
-		}
-
-		public DateTime GetDate(int timestamp)
-		{
-			return unixEpoch.AddSeconds(timestamp);
-		}
-
-		public long GetTimestamp()
-		{
-			return stamp;
-		}
-
-		public static long GetTimestamp(DateTime date)
-		{
-			TimeSpan span = date.ToUniversalTime() - unixEpoch;
-			return (long)span.TotalSeconds;
-		}
-	}
-}
+using System;
+
+namespace IBBoard
+{
+	/// <summary>
+	/// Summary description for UnixTimestamp.
+	/// </summary>
+	public class UnixTimestamp
+	{
+		private long stamp;
+		private static DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime();
+
+		public UnixTimestamp(DateTime date)
+		{
+			stamp = GetTimestamp(date);
+		}
+
+		public UnixTimestamp(long timestamp)
+		{
+			stamp = timestamp;
+		}
+
+		public DateTime GetDate()
+		{
+			return unixEpoch.AddSeconds(stamp);
+		}
+
+		public DateTime GetDate(int timestamp)
+		{
+			return unixEpoch.AddSeconds(timestamp);
+		}
+
+		public long GetTimestamp()
+		{
+			return stamp;
+		}
+
+		public static long GetTimestamp(DateTime date)
+		{
+			TimeSpan span = date.ToUniversalTime() - unixEpoch;
+			return (long)span.TotalSeconds;
+		}
+	}
+}
--- a/Xml/IBBXmlResolver.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Xml/IBBXmlResolver.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,34 +2,34 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-using System.Xml;
-
-namespace IBBoard.Xml
-{
-	/// <summary>
-	/// Summary description for IBBXmlResolver.
-	/// </summary>
-	public class IBBXmlResolver : XmlUrlResolver
-	{
-		private string baseFilePath = "";
-
-		public IBBXmlResolver(string basePath)
-		{
-			baseFilePath = basePath;
-		}
-
-		public override Uri ResolveUri(Uri baseUri, string relativeUri)
-		{
-			if (relativeUri.StartsWith("dtds/"))
-			{
-				//Uri uri = base.ResolveUri(baseUri, relativeUri);
-				return new Uri(Uri.UriSchemeFile + "://" + baseFilePath + Constants.DirectoryString + relativeUri);
-			}
-			else
-			{
-				return base.ResolveUri(baseUri, relativeUri);
-			}
-		}
-	}
-}
+using System;
+using System.Xml;
+
+namespace IBBoard.Xml
+{
+	/// <summary>
+	/// Summary description for IBBXmlResolver.
+	/// </summary>
+	public class IBBXmlResolver : XmlUrlResolver
+	{
+		private string baseFilePath = "";
+
+		public IBBXmlResolver(string basePath)
+		{
+			baseFilePath = basePath;
+		}
+
+		public override Uri ResolveUri(Uri baseUri, string relativeUri)
+		{
+			if (relativeUri.StartsWith("dtds/"))
+			{
+				//Uri uri = base.ResolveUri(baseUri, relativeUri);
+				return new Uri(Uri.UriSchemeFile + "://" + baseFilePath + Constants.DirectoryString + relativeUri);
+			}
+			else
+			{
+				return base.ResolveUri(baseUri, relativeUri);
+			}
+		}
+	}
+}
--- a/Xml/XmlParseException.cs	Tue May 19 19:55:21 2009 +0000
+++ b/Xml/XmlParseException.cs	Sat Jun 27 19:03:58 2009 +0000
@@ -2,19 +2,19 @@
 //
 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license.
 
-using System;
-
-namespace IBBoard.Xml
-{
-	/// <summary>
-	/// Summary description for XmlParseException.
-	/// </summary>
-	public class XmlParseException : Exception
-	{
-		public XmlParseException() : base() {}
-
-		public XmlParseException(string message) : base(message) {}
-
-		public XmlParseException(string message, Exception innerException) : base(message, innerException) {}
-	}
-}
+using System;
+
+namespace IBBoard.Xml
+{
+	/// <summary>
+	/// Summary description for XmlParseException.
+	/// </summary>
+	public class XmlParseException : Exception
+	{
+		public XmlParseException() : base() {}
+
+		public XmlParseException(string message) : base(message) {}
+
+		public XmlParseException(string message, Exception innerException) : base(message, innerException) {}
+	}
+}