changeset 0:3ab940a0c7a0

Initial commit
author Ivo Smits <Ivo@UCIS.nl>
date Tue, 11 Sep 2012 16:28:53 +0200
parents
children 28dc7d535036
files Cache.cs Cci/CciCommand.cs DBReader.cs Database.cs Net/ConnectionList.cs Net/HTTP.cs Net/INetworkConnection.cs Net/TCPServer.cs Net/TCPStream.cs Pml/Channels/ActivePmlChannel.cs Pml/Channels/IPmlChannel.cs Pml/Channels/PassivePmlChannel.cs Pml/Channels/PmlChannel.cs Pml/Channels/TCPPmlChannel.cs Pml/Elements/Array.cs Pml/Elements/Binary.cs Pml/Elements/Collection.cs Pml/Elements/Dictionary.cs Pml/Elements/Element.cs Pml/Elements/Integer.cs Pml/Elements/Number.cs Pml/Elements/PmlNull.cs Pml/Elements/PmlString.cs Pml/IPmlCommunicator.cs Pml/IPmlRpc.cs Pml/LegacyPmlCommunicator.cs Pml/PmlBuilder.cs Pml/PmlCommunicator.cs Pml/PmlCommunicator2.cs Pml/PmlConnection.cs Pml/RW/IPmlRW.cs Pml/RW/PmlAmfRW.cs Pml/RW/PmlBinaryRW.cs Pml/RW/PmlPHPRW.cs Pml/RW/PmlTextRW.cs Pml/RW/PmlXmlRW.cs Properties/AssemblyInfo.cs Radio/Tuner.cs ThreadPool.cs UCIS.csproj UTF8NoPreamble.cs Util/ArrayUtil.cs Util/AsyncStream.cs Util/CrossStream.cs Util/HoldStream.cs Util/PipeStream.cs Windows/ServiceManager.cs Xml/PolicyFile.cs Xml/Server.cs Xml/Socket.cs
diffstat 50 files changed, 6692 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cache.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+
+namespace UCIS {
+	public class Cache<TKey, TValue> {
+		private Dictionary<TKey, WeakReference> _items;
+
+		public Cache() {
+			_items = new Dictionary<TKey, WeakReference>();
+		}
+
+		public int Count { get { return _items.Count; } }
+		public int getCount(bool checkAlive) {
+			Purge();
+			return _items.Count;
+		}
+
+		private void getItem(TKey key, out TValue value, out bool exists, out bool collected) {
+			WeakReference w;
+			lock (_items) {
+				if (!_items.TryGetValue(key, out w)) {
+					value = default(TValue);
+					exists = false;
+					collected = false;
+					return;
+				}
+				Object r = w.Target;
+				if (r == null) {
+					_items.Remove(key);
+					value = default(TValue);
+					exists = false;
+					collected = true;
+					return;
+				}
+				value = (TValue)r;
+				exists = true;
+				collected = false;
+				return;
+			}
+		}
+
+		public bool TryGetValue(TKey key, out TValue value) {
+			bool exists, collected;
+			getItem(key, out value, out exists, out collected);
+			return exists;
+		}
+
+		public void Purge() {
+			lock (_items) {
+				List<TKey> remove = new List<TKey>();
+				foreach (KeyValuePair<TKey, WeakReference> kvp in _items) {
+					if (!kvp.Value.IsAlive) remove.Add(kvp.Key);
+				}
+				foreach (TKey key in remove) {
+					_items.Remove(key);
+				}
+			}
+		}
+
+		public void Add(TKey key, TValue value) {
+			lock(_items) _items.Add(key, new WeakReference(value));
+		}
+
+		public bool Remove(TKey key) {
+			lock(_items) return _items.Remove(key);
+		}
+
+		public void Clear() {
+			_items.Clear();
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Cci/CciCommand.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,195 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using UCIS.Pml;
+
+namespace UCIS.Cci {
+	public enum CciResultType {
+		Success,
+		Error,
+		Value,
+		Message,
+		List,
+		Pml,
+		Object,
+		Binary
+	}
+
+	public class CciResult {
+		private CciResultType _type;
+		private Object _value;
+
+		public CciResult(CciResultType type, Object value) {
+			_type = type;
+			_value = value;
+		}
+		public CciResult(CciResultType type) : this(type, null) { }
+		public CciResult(Exception ex) : this(CciResultType.Error, ex) { }
+		public CciResult(Pml.PmlElement pml) : this(CciResultType.Pml, pml) { }
+		public CciResult(byte[] binary) : this(CciResultType.Binary, binary) { }
+		public CciResult(string[] stringList) : this(CciResultType.List, stringList) { }
+		public CciResult(string message) : this(CciResultType.Message, message) { }
+
+		public override string ToString() {
+			if (_value == null) {
+				return _type.ToString();
+			} else {
+				return _type.ToString() + ": " + ValueToString();
+			}
+		}
+		public string ValueToString() {
+			if (_value == null) {
+				return "";
+			} else if (_value is string) {
+				return (string)_value;
+			} else if (_value is byte[]) {
+				return Encoding.UTF8.GetString((byte[])_value);
+			} else if (_value is PmlElement) {
+					return Pml.PmlTextWriter.GetMessageString((PmlElement)_value);
+			} else if (_value is IEnumerable<Object>) {
+				StringBuilder sb = new StringBuilder();
+				foreach (Object i in (Array)_value) sb.AppendLine(i.ToString());
+				return sb.ToString();
+			} else {
+				return _value.ToString();
+			}
+		}
+		public PmlElement ValueToPml() {
+			if (_value == null) return new PmlNull();
+			switch (_type) {
+				case CciResultType.Binary: return new PmlBinary((byte[])_value);
+				case CciResultType.Message:
+				case CciResultType.Object:
+				case CciResultType.Value:
+				case CciResultType.Error: return new PmlString(_value.ToString());
+				case CciResultType.Success: return new PmlInteger(1);
+				case CciResultType.List: {
+						PmlCollection c = new PmlCollection();
+						foreach (Object i in (Array)_value) c.Add(i.ToString());
+						return c;
+					}
+				case CciResultType.Pml: return (PmlElement)_value;
+				default: return new PmlString("Unknown type: " + _type.ToString());
+			}
+		}
+		public PmlElement ToPml() {
+			PmlDictionary d = new PmlDictionary();
+			//d.Add("Type", (int)_type);
+			d.Add("Type", (int)CciResultType.Message);
+			//d.Add("TypeName", _type.ToString());
+			d.Add("TypeName", "Message");
+			//d.Add("Value", ValueToPml());
+			d.Add("Value", ToString());
+			d.Add("String", ToString());
+			return d;
+		}
+
+		public CciResultType Type { get { return _type; } }
+		public Object Value { get { return _value; } }
+	}
+
+	public class CciCommand {
+		private string[] _command;
+		private int _offset;
+		private CciResult _result;
+
+		public CciCommand(string[] command) {
+			_command = command;
+			_offset = 0;
+			_result = null;
+		}
+
+		public int Offset { get { return _offset; } set { _offset = value; } }
+
+		public static CciCommand Parse(string command, bool urlEncode, bool cEscape, bool quotes) {
+			List<string> l = new List<string>();
+
+			StringBuilder part = new StringBuilder();
+			bool inQuotes = false;
+			int len = command.Length;
+			for (int i = 0; i < len; i++) {
+				char c = command[i];
+				if (quotes && !inQuotes && c == '"') {
+					inQuotes = true;
+				} else if (quotes && inQuotes && c == '"') {
+					inQuotes = false;
+				} else if (urlEncode && c == '%') {
+					part.Append(Uri.HexUnescape(command, ref i));
+					i--;
+				} else if (cEscape && c == '\\' && i + 1 < len) {
+					i++;
+					switch (command[i]) {
+						case 't': part.Append('\t'); break;
+						case 'n': part.Append('\n'); break;
+						case 'r': part.Append('\r'); break;
+						default: part.Append(command[i]); break;
+					}
+				} else if (!inQuotes && (c == ' ' || c == '\t')) {
+					if (part.Length > 0) l.Add(part.ToString());
+					part.Length = 0;
+				} else {
+					part.Append(c);
+				}
+			}
+			if (part.Length > 0) l.Add(part.ToString());
+
+			return new CciCommand(l.ToArray());
+		}
+
+		public PmlCollection ToPml() { return ToPml(0); }
+		public PmlCollection ToPml(int offset) {
+			PmlCollection c = new PmlCollection();
+			for (int i = _offset + offset; i < _command.Length; i++) c.Add(_command[i]);
+			return c;
+		}
+		public static CciCommand FromPml(PmlCollection pml) {
+			List<string> l = new List<string>();
+			foreach (PmlElement e in pml) l.Add(e.ToString());
+			return new CciCommand(l.ToArray());
+		}
+
+		public string Command {
+			get {
+				return _command[_offset];
+			}
+		}
+
+		public string GetArgument(int index) {
+			return _command[_offset + index + 1];
+		}
+
+		public CciCommand Jump(int offset) {
+			_offset += offset;
+			return this;
+		}
+
+		public int Count {
+			get {
+				return _command.Length - _offset - 1;
+			}
+		}
+
+		public CciResult Result {
+			get {
+				return _result;
+			}
+			set {
+				_result = value;
+			}
+		}
+
+		public CciCommand Return(CciResult result) {
+			_result = result;
+			return this;
+		}
+		public CciCommand Return(CciResultType type, Object value) { return Return(new CciResult(type, value)); }
+		public CciCommand Return() { return Return(CciResultType.Success); }
+		public CciCommand Return(int value) { return Return(CciResultType.Value, value); }
+		public CciCommand Return(CciResultType type) { return Return(type, null); }
+		public CciCommand Return(Exception ex) { return Return(CciResultType.Error, ex); }
+		public CciCommand Return(PmlElement pml) { return Return(CciResultType.Pml, pml); }
+		public CciCommand Return(byte[] binary) { return Return(CciResultType.Binary, binary); }
+		public CciCommand Return(string[] stringList) { return Return(CciResultType.List, stringList); }
+		public CciCommand Return(string message) { return Return(CciResultType.Message, message); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DBReader.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,103 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+
+namespace UCIS {
+	public class DBReader : IEnumerable, IEnumerator {
+		private IDbCommand _Command;
+		private IDataReader _Reader;
+		private object[] _CurrentRow;
+
+		internal DBReader(IDbCommand Command) {
+			_Command = Command;
+		}
+
+		public bool Read() {
+			if (_Reader == null) {
+				if (_Command == null) return false;
+				_Reader = _Command.ExecuteReader();
+			}
+			if (_Reader.Read()) {
+				return true;
+			} else {
+				Close();
+				return false;
+			}
+		}
+
+		public void Close() {
+			if (_Reader != null) _Reader.Close();
+			if (_Command != null) {
+				_Command.Connection.Close();
+				_Command.Dispose();
+			}
+			_Command = null;
+			_CurrentRow = null;
+			_Reader = null;
+		}
+
+		public object GetField() {
+			if (_Reader == null) {
+				return _Command.ExecuteScalar();
+			} else {
+				return _Reader.GetValue(0);
+			}
+		}
+
+		public object GetField(int Offset) {
+			if (_Reader == null) Read();
+			return _Reader.GetValue(Offset);
+		}
+		public object[] GetRow(bool GoNextRow) {
+			object[] Result = null;
+			if (_Reader == null) {
+				if (!Read()) return null;
+			}
+			Result = new object[_Reader.FieldCount];
+
+			_Reader.GetValues(Result);
+			if (GoNextRow) Read();
+			return Result;
+		}
+		public object[] GetRow() {
+			return GetRow(true);
+		}
+		public object[][] GetAllRows() {
+			List<object[]> Result = new List<object[]>();
+			object[] ResultArray = null;
+			if (_Reader == null) {
+				if (!Read()) return null;
+			}
+			do {
+				ResultArray = new object[_Reader.FieldCount];
+
+				_Reader.GetValues(ResultArray);
+				Result.Add(ResultArray);
+			}
+			while (_Reader.Read());
+			Close();
+			return Result.ToArray();
+		}
+
+		IEnumerator IEnumerable.GetEnumerator() {
+			return this;
+		}
+		object IEnumerator.Current {
+			get { return _CurrentRow; }
+		}
+		bool IEnumerator.MoveNext() {
+			if (!Read()) return false;
+			_CurrentRow = GetRow(false);
+			return true;
+		}
+		void IEnumerator.Reset() {
+			throw new NotImplementedException();
+		}
+
+		public void Dispose() {
+			Close();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Database.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,127 @@
+using System;
+using System.Reflection;
+using System.Data;
+using System.Data.Common;
+using System.Collections.Generic;
+
+namespace UCIS {
+	public class Database {
+		private delegate object ConstructorDelegate();
+		private ConstructorInfo _ConnectionConstructor;
+
+		public Database(Type DBConnectionType, string connectionString) {
+			this.ConnectionString = connectionString;
+			_ConnectionConstructor = DBConnectionType.GetConstructor(new Type[] { });
+		}
+
+		public string ConnectionString { get; set; }
+
+		public virtual IDbConnection GetConnection() {
+			lock (_ConnectionConstructor) {
+				IDbConnection conn = (IDbConnection)_ConnectionConstructor.Invoke(null);
+				conn.ConnectionString = ConnectionString;
+				conn.Open();
+				return conn;
+			}
+		}
+
+		public IDbCommand PrepareQuery(string Query, params object[] Parameters) {
+			int ParameterI = 0;
+			IDbConnection Connection = GetConnection();
+			try {
+				IDbCommand Command = Connection.CreateCommand();
+				Command.CommandType = CommandType.Text;
+				Command.CommandText = Query;
+				Command.Parameters.Clear();
+				foreach (object Parameter in Parameters) {
+					IDbDataParameter DBParameter = Command.CreateParameter();
+					DBParameter.Direction = ParameterDirection.Input;
+					DBParameter.ParameterName = "?" + ParameterI.ToString();
+					DBParameter.Value = Parameter;
+					Command.Parameters.Add(DBParameter);
+					ParameterI++;
+				}
+				if (ParameterI > 0) Command.Prepare();
+				return Command;
+			} catch (Exception ex) {
+				Connection.Close();
+				throw ex;
+			}
+		}
+
+		public int NonQuery(string QueryString, params object[] Parameters) {
+			IDbCommand Command = PrepareQuery(QueryString, Parameters);
+			try {
+				return Command.ExecuteNonQuery();
+			} finally {
+				Command.Connection.Close();
+			}
+		}
+
+		public object FetchField(string QueryString, params object[] Parameters) {
+			IDbCommand Command = PrepareQuery(QueryString, Parameters);
+			try {
+				return Command.ExecuteScalar();
+			} finally {
+				Command.Connection.Close();
+			}
+		}
+		public object[] FetchRow(string QueryString, params object[] Parameters) {
+			IDbCommand Command = PrepareQuery(QueryString, Parameters);
+			try {
+				IDataReader Reader = Command.ExecuteReader();
+				try {
+					if (!Reader.Read()) return null;
+					object[] Result = new object[Reader.FieldCount];
+					Reader.GetValues(Result);
+					return Result;
+				} finally {
+					Reader.Close();
+				}
+			} finally {
+				Command.Connection.Close();
+			}
+		}
+		public object[][] FetchRows(string QueryString, params object[] Parameters) {
+			IDbCommand Command = PrepareQuery(QueryString, Parameters);
+			try {
+				IDataReader Reader = Command.ExecuteReader();
+				try {
+					List<object[]> Result = new List<object[]>();
+					while (Reader.Read()) {
+						object[] ResultArray = new object[Reader.FieldCount];
+						Reader.GetValues(ResultArray);
+						Result.Add(ResultArray);
+					}
+					return Result.ToArray();
+				} finally {
+					Reader.Close();
+				}
+			} finally {
+				Command.Connection.Close();
+			}
+		}
+		public void ForEachRow(Action<Object[]> f, string QueryString, params object[] Parameters) {
+			IDbCommand Command = PrepareQuery(QueryString, Parameters);
+			try {
+				IDataReader Reader = Command.ExecuteReader();
+				try {
+					while (Reader.Read()) {
+						object[] ResultArray = new object[Reader.FieldCount];
+						Reader.GetValues(ResultArray);
+						f(ResultArray);
+					}
+				} finally {
+					Reader.Close();
+				}
+			} finally {
+				Command.Connection.Close();
+			}
+
+		}
+
+		/*public DBReader GetReader(string QueryString, params object[] Parameters) {
+			return new DBReader(PrepareQuery(QueryString, Parameters));
+		}*/
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Net/ConnectionList.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,133 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UCIS.Net {
+	public class NetworkConnectionList : ICollection<INetworkConnection> {
+		List<INetworkConnection> _list = new List<INetworkConnection>();
+
+		public ulong BytesWritten {
+			get {
+				ulong sum = 0;
+				lock (_list) foreach (INetworkConnection c in _list) sum += c.BytesWritten;
+				return sum;
+			}
+		}
+		public ulong BytesRead {
+			get {
+				ulong sum = 0;
+				lock (_list) foreach (INetworkConnection c in _list) sum += c.BytesRead;
+				return sum;
+			}
+		}
+		public NetworkConnectionList FindByHandler(Object Handler) {
+			NetworkConnectionList l = new NetworkConnectionList();
+			lock (_list) foreach (INetworkConnection c in _list) if (c.Handler == Handler) l.Add(c);
+			return l;
+		}
+		public NetworkConnectionList FindByHandlerType(Type HandlerType) {
+			NetworkConnectionList l = new NetworkConnectionList();
+			lock (_list) foreach (INetworkConnection c in _list) if (c.Handler.GetType() == HandlerType) l.Add(c);
+			return l;
+		}
+		public void CloseAll() {
+			foreach (INetworkConnection c in ToArray()) c.Close();
+		}
+
+		public void Add(INetworkConnection item) {
+			if (item == null) throw new ArgumentNullException("item");
+			lock (_list) _list.Add(item);
+			item.Closed += _ConnectionClosed;
+			if (!item.Connected) Remove(item);
+		}
+		public void Insert(int index, INetworkConnection item) {
+			throw new NotSupportedException();
+		}
+		public bool Remove(INetworkConnection item) {
+			if (item == null) throw new ArgumentNullException("item");
+			item.Closed -= _ConnectionClosed;
+			lock (_list) return _list.Remove(item);
+		}
+		public void RemoveAt(int index) {
+			lock (_list) {
+				INetworkConnection item = _list[index];
+				item.Closed -= _ConnectionClosed;
+				_list.Remove(item);
+			}
+		}
+		public int Count { get { lock (_list) return _list.Count; } }
+		public bool IsReadOnly { get { return false; } }
+		public bool Contains(INetworkConnection item) {
+			lock (_list) return _list.Contains(item);
+		}
+		public void Clear() {
+			lock (_list) {
+				foreach (INetworkConnection c in _list) c.Closed -= _ConnectionClosed;
+				_list.Clear();
+			}
+		}
+		public INetworkConnection this[int index] {
+			get { return _list[index]; }
+			set { throw new NotSupportedException(); }
+		}
+		public int IndexOf(INetworkConnection item) {
+			lock (_list) return _list.IndexOf(item);
+		}
+
+		IEnumerator IEnumerable.GetEnumerator() {
+			return new Enumerator(_list);
+		}
+		public IEnumerator<INetworkConnection> GetEnumerator() {
+			return new Enumerator(_list);
+		}
+
+		public void CopyTo(INetworkConnection[] array, int offset) {
+			lock (_list) _list.CopyTo(array, offset);
+		}
+
+		public INetworkConnection[] ToArray() {
+			lock (_list) return _list.ToArray();
+		}
+
+		private void _ConnectionClosed(Object sender, EventArgs e) {
+			if (sender == null || !(sender is INetworkConnection)) return;
+			Remove((INetworkConnection)sender);
+		}
+
+		private class Enumerator : IEnumerator<INetworkConnection> {
+			int index = 0;
+			INetworkConnection current = null;
+			IList<INetworkConnection> list;
+
+			public Enumerator(IList<INetworkConnection> list) {
+				this.list = list;
+			}
+
+			public void Reset() {
+				index = 0;
+			}
+			public bool MoveNext() {
+				lock (list) {
+					if (index < list.Count) {
+						current = list[index];
+						index++;
+						return true;
+					} else {
+						current = null;
+						return false;
+					}
+				}
+			}
+			public INetworkConnection Current {
+				get { return current; } 
+			}
+			object IEnumerator.Current {
+				get { return current; }
+			}
+			public void Dispose() {
+				current = null;
+				list = null;
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Net/HTTP.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+
+namespace UCIS.Net.HTTP {
+	public class HTTPServer : TCPServer.IModule {
+		public Dictionary<string, HTTPContent> Content = new Dictionary<string, HTTPContent>(StringComparer.InvariantCultureIgnoreCase);
+		public HTTPContent DefaultContent = null;
+
+		public bool Accept(TCPStream Stream) {
+			StreamReader StreamReader = new StreamReader(Stream, Encoding.ASCII);
+			String Line = StreamReader.ReadLine();
+			String[] Request = Line.Split(' ');
+
+			//Console.WriteLine("HTTP.Server.Accept Request: " + Line);
+
+			if (Request == null || Request.Length < 2 || Request[0] != "GET" || Request[1][0] != '/') {
+				//Console.WriteLine("HTTP.Server.Start Bad request");
+				SendError(Stream, 400);
+				return true;
+			}
+
+			Request = Request[1].Split(new Char[] { '?' }, 2);
+			HTTPContent content;
+			if (Content.TryGetValue(Request[0], out content)) {
+			} else if (DefaultContent != null) {
+				content = DefaultContent;
+			} else {
+				SendError(Stream, 404);
+				return true;
+			}
+			HTTPContext Context = new HTTPContext();
+			Context.Stream = Stream;
+			Context.Request = new HTTPRequest();
+			Context.Request.Method = Method.GET;
+			Context.Request.Path = Request[0];
+			if (Request.Length == 2) {
+				Context.Request.Query = Request[1];
+			} else {
+				Context.Request.Query = null;
+			}
+			HTTPContent.Result ServeResult = content.Serve(Context);
+
+			if (ServeResult == HTTPContent.Result.OK_KEEPALIVE) {
+				return false;
+			} else if (!(ServeResult == HTTPContent.Result.OK_CLOSE)) {
+				SendError(Stream, (int)ServeResult);
+			}
+			return true;
+		}
+
+		public static void SendError(Stream Stream, int ErrorCode) {
+			string ErrorText = null;
+			switch (ErrorCode) {
+				case 400:
+					ErrorText = "The request could not be understood by the server due to malformed syntax.";
+					break;
+				case 404:
+					ErrorText = "The requested file can not be found.";
+					break;
+				default:
+					ErrorText = "Unknown error code: " + ErrorCode.ToString() + ".";
+					break;
+			}
+			SendHeader(Stream, ErrorCode, "text/plain", ErrorText.Length);
+			WriteLine(Stream, ErrorText);
+			Thread.Sleep(100);
+			return;
+		}
+
+		public static void SendHeader(Stream Stream, int ResultCode, string ContentType) {
+			SendHeader(Stream, ResultCode, ContentType, -1);
+		}
+		public static void SendHeader(Stream Stream, int ResultCode, string ContentType, int ContentLength) {
+			//ResultCode = 200, ContentType = null, ContentLength = -1
+			string ResultString;
+			switch (ResultCode) {
+				case 200: ResultString = "OK"; break;
+				case 400: ResultString = "Bad Request"; break;
+				case 404: ResultString = "Not found"; break;
+				default: ResultString = "Unknown"; break;
+			}
+			WriteLine(Stream, "HTTP/1.1 " + ResultCode.ToString() + " " + ResultString);
+			WriteLine(Stream, "Expires: Mon, 26 Jul 1990 05:00:00 GMT");
+			WriteLine(Stream, "Cache-Control: no-store, no-cache, must-revalidate");
+			WriteLine(Stream, "Cache-Control: post-check=0, pre-check=0");
+			WriteLine(Stream, "Pragma: no-cache");
+			WriteLine(Stream, "Server: UCIS Simple Webserver");
+			WriteLine(Stream, "Connection: Close");
+			if ((ContentType != null)) WriteLine(Stream, "Content-Type: " + ContentType);
+			if (ContentLength != -1) WriteLine(Stream, "Content-Length: " + ContentLength.ToString());
+			WriteLine(Stream, "");
+		}
+
+		public static void WriteLine(Stream Stream, string Line) {
+			byte[] Buffer = null;
+			Buffer = Encoding.ASCII.GetBytes(Line);
+			Stream.Write(Buffer, 0, Buffer.Length);
+			Stream.WriteByte(13);
+			Stream.WriteByte(10);
+		}
+	}
+
+	public abstract class HTTPContent {
+		public abstract Result Serve(HTTPContext Context);
+		public enum Result : int {
+			OK_CLOSE = -2,
+			OK_KEEPALIVE = -1,
+			ERR_NOTFOUND = 404
+		}
+	}
+
+	public class HTTPFileContent : HTTPContent {
+		public string Filename { get; private set; }
+		public string ContentType { get; private set; }
+
+		public HTTPFileContent(string Filename) : this(Filename, "application/octet-stream") { }
+		public HTTPFileContent(string Filename, string ContentType) {
+			this.Filename = Filename;
+			this.ContentType = ContentType;
+		}
+
+		public override Result Serve(HTTPContext Context) {
+			if (!File.Exists(Filename)) return Result.ERR_NOTFOUND;
+
+			using (FileStream FileStream = File.OpenRead(Filename)) {
+				HTTPServer.SendHeader(Context.Stream, 200, ContentType, (int)FileStream.Length);
+				byte[] Buffer = new byte[1025];
+				while (FileStream.CanRead) {
+					int Length = FileStream.Read(Buffer, 0, Buffer.Length);
+					if (Length <= 0) break;
+					Context.Stream.Write(Buffer, 0, Length);
+				}
+			}
+			return Result.OK_CLOSE;
+		}
+	}
+
+	public class HTTPContext {
+		public HTTPRequest Request { get; internal set; }
+		public TCPStream Stream { get; internal set; }
+	}
+
+	public enum Method {
+		GET = 0,
+		HEAD = 1,
+		POST = 2,
+		PUT = 3
+	}
+
+	public class HTTPRequest {
+		public HTTP.Method Method { get; internal set; }
+		public string Path { get; internal set; }
+		public string Query { get; internal set; }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Net/INetworkConnection.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,16 @@
+using System;
+using System.Net;
+
+namespace UCIS.Net {
+	public interface INetworkConnection {
+		event EventHandler Closed;
+		void Close();
+		bool Connected { get; }
+		ulong BytesWritten { get; }
+		ulong BytesRead { get; }
+		TimeSpan Age { get; }
+		EndPoint RemoteEndPoint { get; }
+		//Object Proxy { get; }
+		Object Handler { get; }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Net/TCPServer.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,235 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace UCIS.Net {
+	public class TCPServer {
+		public class ModuleCollection : Dictionary<byte, IModule> {
+			public void Add(char Key, IModule Value) {
+				base.Add((byte)Key, Value);
+			}
+			public void Remove(char Key) {
+				base.Remove((byte)Key);
+			}
+		}
+
+		public class ClientAcceptedEventArgs : EventArgs {
+			private TCPStream _client;
+			internal ClientAcceptedEventArgs(TCPStream client) {
+				_client = client;
+			}
+			public TCPStream Client { get { return _client; } }
+		}
+
+		public event EventHandler<ClientAcceptedEventArgs> ClientAccepted;
+
+		private Socket _Listener;
+		private UCIS.ThreadPool _ThreadPool;
+		private NetworkConnectionList _Clients = new NetworkConnectionList();
+		private ModuleCollection _Modules = new ModuleCollection();
+		private IModule _CatchAllModule = null;
+		private Int32 _ThrottleCounter;
+		private Int32 _ThrottleBurst = 10;
+		private Int32 _ThrottleRate = 0;
+		private Timer _ThrottleTimer = null;
+
+		public TCPServer() {
+			_ThreadPool = UCIS.ThreadPool.DefaultPool;
+		}
+
+		public NetworkConnectionList Clients {
+			get { return _Clients; }
+		}
+
+		public ModuleCollection Modules {
+			get { return _Modules; }
+		}
+
+		public IModule CatchAllModule {
+			get {
+				return _CatchAllModule;
+			}
+			set {
+				_CatchAllModule = value;
+			}
+		}
+
+		public Int32 ThrottleRate {
+			get { return _ThrottleRate; }
+			set {
+				if (value < 0) throw new ArgumentOutOfRangeException("value");
+				_ThrottleRate = value;
+				if (_Listener == null) return;
+				if (value == 0 && _ThrottleTimer != null) {
+					_ThrottleTimer.Dispose();
+					_ThrottleTimer = null;
+				} else if (value > 0 && _ThrottleTimer == null) {
+					_ThrottleTimer = new Timer(ThrottleCallback, null, 1000, 1000);
+				}
+			}
+		}
+		public Int32 ThrottleBurst {
+			get { return _ThrottleBurst; }
+			set {
+				if (value < 1) throw new ArgumentOutOfRangeException("value");
+				_ThrottleBurst = value;
+			}
+		}
+
+		public EndPoint LocalEndPoint { get { return _Listener.LocalEndPoint; } }
+
+		public void Listen(int Port) {
+			Listen(AddressFamily.InterNetwork, Port);
+		}
+		public void Listen(AddressFamily af, int Port) {
+			Stop();
+
+			_Listener = new Socket(af, SocketType.Stream, ProtocolType.Tcp);
+
+			_Listener.Blocking = false;
+			_Listener.Bind(new IPEndPoint(af == AddressFamily.InterNetworkV6 ? IPAddress.IPv6Any : IPAddress.Any, Port));
+			_Listener.Listen(25);
+			_ThrottleCounter = _ThrottleBurst;
+			_Listener.BeginAccept(AcceptCallback, null);
+
+			if (_ThrottleRate > 0) {
+				_ThrottleTimer = new Timer(ThrottleCallback, null, 1000, 1000);
+			}
+		}
+
+		public void Stop() {
+			if (_ThrottleTimer != null) _ThrottleTimer.Dispose();
+			if (_Listener != null && _Listener.IsBound) _Listener.Close();
+			_Listener = null;
+		}
+
+		public void Close() {
+			Close(true);
+		}
+		public void Close(bool CloseClients) {
+			Stop();
+			if (CloseClients) {
+				_Clients.CloseAll();
+				if (_Clients.Count > 0) Console.WriteLine("TCPServer.Close: Warning: " + _Clients.Count.ToString() + " connections were not properly terminated.");
+			} else {
+				_Clients.Clear();
+			}
+		}
+
+		private void AcceptCallback(System.IAsyncResult ar) {
+			Client Client = null;
+			Socket Socket = null;
+			if (_Listener == null) return;
+			try {
+				Socket = _Listener.EndAccept(ar);
+			} catch (ObjectDisposedException) {
+				Console.WriteLine("TCPServer.AcceptCallback Listener object has been disposed. Aborting.");
+				return;
+			} catch (SocketException ex) {
+				Console.WriteLine("TCPServer.AcceptCallback SocketException: " + ex.Message);
+				Socket = null;
+			}
+			if (Socket != null) {
+				try {
+					Client = new Client(Socket, this);
+					_Clients.Add(Client);
+					if (ClientAccepted != null) ClientAccepted(this, new ClientAcceptedEventArgs(Client));
+					Client.Start(_ThreadPool);
+				} catch (Exception ex) {
+					Console.WriteLine(ex.ToString());
+				}
+			}
+			if (_ThrottleCounter > 0 || _ThrottleRate == 0) {
+				_ThrottleCounter--;
+				_Listener.BeginAccept(AcceptCallback, null);
+			}
+		}
+
+		private void ThrottleCallback(Object state) {
+			if (_Listener == null) return;
+			if (_ThrottleRate == 0) return;
+			if (_ThrottleCounter >= _ThrottleBurst) return;
+			if (_ThrottleCounter <= 0) {
+				_Listener.BeginAccept(AcceptCallback, null);
+			}
+			_ThrottleRate += _ThrottleRate;
+		}
+
+		public interface IModule {
+			// Return value: True = Close connection, False = keep alive
+			bool Accept(TCPStream Stream);
+		}
+
+		private class Client : TCPStream {
+			private TCPServer _Server;
+			private UCIS.ThreadPool.WorkItem _WorkItem;
+			private IModule _Module;
+			private byte _MagicNumber;
+
+			public TCPServer Server {
+				get { return _Server; }
+			}
+			public IModule Module {
+				get { return _Module; }
+			}
+
+			private void _Stream_Closed(object sender, EventArgs e) {
+				_WorkItem = null;
+				_Module = null;
+				_Server = null;
+				base.Closed -= _Stream_Closed;
+			}
+
+			internal Client(Socket Socket, TCPServer Server) : base(Socket) {
+				_Server = Server;
+				Socket.Blocking = true;
+				base.Closed += _Stream_Closed;
+				this.Tag = Server;
+			}
+
+			internal void Start(UCIS.ThreadPool Pool) {
+				_WorkItem = Pool.QueueWorkItem(WorkerProc, null);
+			}
+
+			private void WorkerProc(object state) {
+				bool CloseSocket = true;
+				try {
+					try {
+						base.Blocking = true;
+						//base.NoDelay = true;
+						base.ReadTimeout = 5000;
+						base.WriteBufferSize = 1024 * 10;
+						base.ReadBufferSize = 1024 * 10;
+						//Console.WriteLine("TCPServer: Accepted connection from " + base.Socket.RemoteEndPoint.ToString());
+						_MagicNumber = (byte)base.PeekByte();
+					} catch (TimeoutException ex) {
+						Console.WriteLine("TCPServer: Caught TimeoutException while reading magic number: " + ex.Message);
+						return;
+					}
+					if (_Server._Modules.TryGetValue(_MagicNumber, out _Module)) {
+						this.Tag = _Module;
+						CloseSocket = _Module.Accept(this);
+					} else if (_Server._CatchAllModule != null) {
+						this.Tag = _Server._CatchAllModule;
+						CloseSocket = _Server._CatchAllModule.Accept(this);
+					} else {
+						this.Tag = this;
+						Console.WriteLine("TCPServer: Unknown magic number: " + _MagicNumber.ToString());
+					}
+				} catch (ThreadAbortException) {
+					Console.WriteLine("TCPServer: Caught ThreadAbortException");
+				} catch (SocketException ex) {
+					Console.WriteLine("TCPServer: Caught SocketException: " + ex.Message);
+				} catch (Exception ex) {
+					Console.WriteLine("TCPServer: Caught Exception: " + ex.ToString());
+				} finally {
+					try {
+						if (CloseSocket) base.Close();
+					} catch { }
+				}
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Net/TCPStream.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,254 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+namespace UCIS.Net {
+	public class TCPStream : Stream, INetworkConnection {
+		private static long _totalBytesRead = 0;
+		private static long _totalBytesWritten = 0;
+		public static ulong TotalBytesWritten { get { return (ulong)_totalBytesWritten; } set { _totalBytesWritten = (long)value; } }
+		public static ulong TotalBytesRead { get { return (ulong)_totalBytesRead; } set { _totalBytesRead = (long)value; } }
+
+		private Socket _Socket;
+		private byte _PeekByte;
+		private bool _HasPeekByte;
+		private ulong _BytesWritten;
+		private ulong _BytesRead;
+		private DateTime _StartTime;
+		private bool _Blocking;
+
+		public event EventHandler Closed;
+
+		public TCPStream(Socket Socket) {
+			_Socket = Socket;
+			_HasPeekByte = false;
+			_StartTime = DateTime.Now;
+			_Blocking = _Socket.Blocking;
+		}
+
+		public Socket Socket {
+			get { return _Socket; }
+		}
+
+		public DateTime CreationTime {
+			get { return _StartTime; }
+		}
+
+		public bool Blocking {
+			get { return _Blocking; }
+			set {
+				Socket.Blocking = value;
+				_Blocking = value;
+			}
+		}
+
+		public bool NoDelay {
+			get { return Socket.NoDelay; }
+			set { Socket.NoDelay = value; }
+		}
+
+		public override bool CanTimeout {
+			get { return true; }
+		}
+
+		public override int ReadTimeout {
+			get { return Socket.ReceiveTimeout; }
+			set { Socket.ReceiveTimeout = value; }
+		}
+
+		public override int WriteTimeout {
+			get { return Socket.SendTimeout; }
+			set { Socket.SendTimeout = value; }
+		}
+
+		public override int ReadByte() {
+			if (_HasPeekByte) {
+				_HasPeekByte = false;
+				return _PeekByte;
+			} else {
+				byte[] Buffer = new byte[1];
+				if (Read(Buffer, 0, 1) != 1) return -1;
+				return Buffer[0];
+			}
+		}
+
+		public override int Read(byte[] buffer, int offset, int size) {
+			int Count = 0;
+
+			if (size < 1) return 0;
+			if (_HasPeekByte) {
+				buffer[offset] = _PeekByte;
+				_HasPeekByte = false;
+				Count = 1;
+				offset += 1;
+				size -= 1;
+			}
+
+			try {
+				if (size > 0) Count += Socket.Receive(buffer, offset, size, SocketFlags.None);
+			} catch (SocketException ex) {
+				switch (ex.SocketErrorCode) {
+					case SocketError.WouldBlock:
+						_Socket.Blocking = _Blocking;
+						throw new TimeoutException("The receive operation would block", ex);
+					case SocketError.TimedOut:
+						throw new TimeoutException("The receive operation timed out", ex);
+					case SocketError.ConnectionReset:
+					case SocketError.Disconnecting:
+					case SocketError.NetworkDown:
+					case SocketError.NetworkReset:
+					case SocketError.NetworkUnreachable:
+					case SocketError.NotConnected:
+						Close();
+						throw new SocketException((int)ex.SocketErrorCode);
+					default:
+						throw new SocketException((int)ex.SocketErrorCode);
+				}
+			}
+
+			_BytesRead += (ulong)Count;
+			Interlocked.Add(ref _totalBytesRead, (long)Count);
+			return Count;
+		}
+
+		public int PeekByte() {
+			if (_HasPeekByte) {
+				return _PeekByte;
+			} else {
+				int Result = 0;
+				Result = ReadByte();
+				if (Result >= 0 && Result <= 255) {
+					_PeekByte = (byte)Result;
+					_HasPeekByte = true;
+				}
+				return Result;
+			}
+		}
+
+		public int WriteBufferSize {
+			get { return Socket.SendBufferSize; }
+			set { Socket.SendBufferSize = value; }
+		}
+
+		public int ReadBufferSize {
+			get { return Socket.ReceiveBufferSize; }
+			set { Socket.ReceiveBufferSize = value; }
+		}
+
+		public override bool CanRead {
+			get { return Socket.Connected && (Blocking || (Socket.Available > 0)); }
+		}
+
+		public override bool CanSeek {
+			get { return false; }
+		}
+
+		public override bool CanWrite {
+			get { return Socket.Connected; }
+		}
+
+		public override void Flush() {
+			//Do nothing
+			//_Socket.NoDelay = true;
+		}
+
+		public override long Length {
+			get {
+				throw new NotSupportedException();
+			}
+		}
+
+		public override long Position {
+			get {
+				throw new NotSupportedException();
+			}
+			set {
+				throw new NotSupportedException();
+			}
+		}
+
+		public override long Seek(long offset, SeekOrigin origin) {
+			throw new NotSupportedException();
+		}
+
+		public override void SetLength(long value) {
+			throw new NotSupportedException();
+		}
+
+		public override void Write(byte[] buffer, int offset, int size) {
+			int left = size;
+			if (_Socket == null) throw new ObjectDisposedException("socket");
+			try {
+				while (left > 0) {
+					int sent = _Socket.Send(buffer, offset, left, 0);
+					left -= sent;
+					offset += sent;
+				}
+			} catch (SocketException ex) {
+				switch (ex.SocketErrorCode) {
+					case SocketError.WouldBlock:
+						_Socket.Blocking = _Blocking;
+						throw new TimeoutException("The send operation would block", ex);
+					case SocketError.TimedOut:
+						throw new TimeoutException("The send operation timed out", ex);
+					case SocketError.ConnectionReset:
+					case SocketError.Disconnecting:
+					case SocketError.NetworkDown:
+					case SocketError.NetworkReset:
+					case SocketError.NetworkUnreachable:
+					case SocketError.NotConnected:
+						Close();
+						throw new SocketException((int)ex.SocketErrorCode);
+					default:
+						throw new SocketException((int)ex.SocketErrorCode);
+				}
+			}
+			_BytesWritten += (ulong)size;
+			Interlocked.Add(ref _totalBytesWritten, (long)size);
+		}
+
+		public override void Close() {
+			System.Net.Sockets.Socket s = Interlocked.Exchange(ref _Socket, null);
+			try {
+				if (s != null) {
+					try {
+						if (s.Connected) s.Shutdown(SocketShutdown.Both);
+					} catch { }
+					s.Close();
+				}
+			} finally {
+				base.Close();
+				if (Closed != null) Closed(this, new EventArgs());
+			}
+		}
+
+		public bool Connected {
+			get {
+				if (Socket == null) return false;
+				if (Socket.Connected) return true;
+				Close();
+				return false;
+			}
+		}
+
+		public object Tag { get; set; }
+
+		public ulong BytesWritten { get { return _BytesWritten; } }
+		public ulong BytesRead { get { return _BytesRead; } }
+		public TimeSpan Age { get { return DateTime.Now.Subtract(_StartTime); } }
+		public EndPoint RemoteEndPoint {
+			get {
+				if (_Socket == null || !_Socket.Connected) return null;
+				try {
+					return _Socket.RemoteEndPoint;
+				} catch (SocketException) {
+					return null;
+				}
+			}
+		}
+		//public Object Proxy { get { return null; } }
+		Object INetworkConnection.Handler { get { return Tag; } }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Channels/ActivePmlChannel.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,107 @@
+using System;
+using UCIS.Pml;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace UCIS.Pml {
+	public abstract class ActivePmlChannel : IPmlChannel {
+		private AutoResetEvent _receiveEvent = new AutoResetEvent(false);
+		private ReadMessageAsyncResult _asyncWait = null;
+		private Queue<PmlElement> _queue = new Queue<PmlElement>();
+		private bool _isOpen = true;
+
+		public virtual bool IsOpen { get { return _isOpen; } }
+		public abstract void WriteMessage(PmlElement message);
+
+		public PmlElement ReadMessage() {
+			if (!IsOpen) throw new InvalidOperationException("The channel is not open");
+			if (_queue.Count == 0) {
+				_receiveEvent.WaitOne();
+				if (_queue.Count == 0) throw new OperationCanceledException("The operation did not complete");
+			} else if (_queue.Count == 1) {
+				_receiveEvent.Reset();
+			}
+			return _queue.Dequeue();
+		}
+
+		public IAsyncResult BeginReadMessage(AsyncCallback callback, object state) {
+			ReadMessageAsyncResult ar = new ReadMessageAsyncResult(state, callback);
+			if (!IsOpen) throw new InvalidOperationException("The channel is not open");
+			if (_asyncWait != null) throw new InvalidOperationException("Another asynchronous operation is in progress");
+			if (_queue.Count == 0) {
+				_asyncWait = ar;
+			} else {
+				if (_queue.Count == 1) _receiveEvent.Reset();
+				ar.Complete(true, _queue.Dequeue(), true);
+			}
+			return ar;
+		}
+
+		public PmlElement EndReadMessage(IAsyncResult asyncResult) {
+			ReadMessageAsyncResult ar = (ReadMessageAsyncResult)asyncResult;
+			if (ar.Error) new OperationCanceledException("The operation did not complete");
+			return ar.Message;
+		}
+
+		public virtual void Close() {
+			_isOpen = false;
+			ReadMessageAsyncResult asyncWait = Interlocked.Exchange<ReadMessageAsyncResult>(ref _asyncWait, null);
+			if (asyncWait != null) asyncWait.Complete(false, null, false);
+			_receiveEvent.Set();
+			_receiveEvent.Close();
+		}
+
+		public void Dispose() {
+			Close();
+		}
+
+		protected void PushReceivedMessage(PmlElement message) {
+			ReadMessageAsyncResult asyncWait = Interlocked.Exchange<ReadMessageAsyncResult>(ref _asyncWait, null);
+			if (asyncWait != null) {
+				asyncWait.Complete(true, message, false);
+			} else {
+				_queue.Enqueue(message);
+				_receiveEvent.Set();
+			}
+		}
+
+		private class ReadMessageAsyncResult : IAsyncResult {
+			private object state;
+			private AsyncCallback callback;
+			private bool completed;
+			private bool synchronously;
+			private ManualResetEvent waitHandle;
+
+			internal PmlElement Message;
+			internal bool Error;
+
+			public bool CompletedSynchronously { get { return synchronously; } }
+			public object AsyncState { get { return state; } }
+			public WaitHandle AsyncWaitHandle {
+				get {
+					if (waitHandle == null) waitHandle = new ManualResetEvent(completed);
+					return waitHandle;
+				}
+			}
+			public bool IsCompleted { get { return completed; } }
+
+			internal ReadMessageAsyncResult(object state, AsyncCallback callback) {
+				this.state = state;
+				this.callback = callback;
+				this.completed = false;
+				this.synchronously = false;
+				this.Message = null;
+				this.Error = false;
+				this.waitHandle = null;
+			}
+			internal void Complete(bool success, PmlElement message, bool synchronously) {
+				this.Message = message;
+				this.Error = !success;
+				this.synchronously = synchronously;
+				this.completed = true;
+				if (waitHandle != null) waitHandle.Set();
+				if (this.callback != null) this.callback.Invoke(this);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Channels/IPmlChannel.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,22 @@
+using System;
+
+namespace UCIS.Pml {
+	/*public class PmlMessageReceivedEventArgs : EventArgs {
+		private PmlElement _message;
+		public PmlMessageReceivedEventArgs(PmlElement message) {
+			_message = message;
+		}
+		public PmlElement Message { get { return _message; } }
+	}*/
+	public interface IPmlChannel : IDisposable {
+		//event EventHandler MessageReceived;
+		//event EventHandler Closed;
+		bool IsOpen { get; }
+		void WriteMessage(PmlElement message);
+		void Close();
+
+		PmlElement ReadMessage();
+		IAsyncResult BeginReadMessage(AsyncCallback callback, object state);
+		PmlElement EndReadMessage(IAsyncResult asyncResult);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Channels/PassivePmlChannel.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,59 @@
+using System;
+using UCIS.Pml;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace UCIS.Pml {
+	public abstract class PassivePmlChannel : IPmlChannel {
+		private bool _isOpen = true;
+
+		public virtual bool IsOpen { get { return _isOpen; } }
+		public abstract void WriteMessage(PmlElement message);
+
+		public void Dispose() {
+			Close();
+		}
+		public virtual void Close() {
+			_isOpen = false;
+		}
+
+		public abstract PmlElement ReadMessage();
+
+		public IAsyncResult BeginReadMessage(AsyncCallback callback, object state) {
+			ReadMessageAsyncResult ar = new ReadMessageAsyncResult();
+			ar.Callback = callback;
+			ar.State = state;
+			UCIS.ThreadPool.RunCall(AsyncReadMessage, ar);
+			return ar;
+		}
+		public PmlElement EndReadMessage(IAsyncResult asyncResult) {
+			ReadMessageAsyncResult ar = (ReadMessageAsyncResult)asyncResult;
+			if (ar.Error != null) throw new Exception("The asynchronous operation could not be completed", ar.Error);
+			return ar.Message;
+		}
+
+		private struct ReadMessageAsyncResult : IAsyncResult {
+			internal object State;
+			internal PmlElement Message;
+			internal AsyncCallback Callback;
+			internal Exception Error;
+			internal bool Completed;
+
+			public bool CompletedSynchronously { get { return false; } }
+			public object AsyncState { get { return State; } }
+			public WaitHandle AsyncWaitHandle { get { return null; } }
+			public bool IsCompleted { get { return Completed; } }
+		}
+		private void AsyncReadMessage(object state) {
+			ReadMessageAsyncResult ar = (ReadMessageAsyncResult)state;
+			try {
+				ar.Message = ReadMessage();
+				ar.Error = null;
+			} catch (Exception ex) {
+				ar.Error = ex;
+			}
+			ar.Completed = true;
+			ar.Callback.Invoke(ar);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Channels/PmlChannel.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace UCIS.Pml {
+	public class PmlChannel : ActivePmlChannel {
+		private IPmlRW _rw;
+		private bool _open;
+
+		public PmlChannel(IPmlRW rw) {
+			if (rw == null) throw new ArgumentNullException("rw");
+			_rw = rw;
+			_open = true;
+			ThreadPool.RunTask(worker, null);
+		}
+
+		public IPmlReader Reader { get { return _rw; } }
+		public IPmlWriter Writer { get { return _rw; } }
+
+		public new bool IsOpen { get { return _open; } }
+
+		public override void WriteMessage(PmlElement message) {
+			if (!_open) throw new InvalidOperationException("The channel is not open");
+			lock (_rw) _rw.WriteMessage(message);
+		}
+
+		public override void Close() {
+			if (!_open) return;
+			_open = false;
+			if (_rw != null) _rw = null;
+			base.Close();
+		}
+
+		private void worker(Object state) {
+			try {
+				while (_open) {
+					base.PushReceivedMessage(_rw.ReadMessage());
+				}
+			} catch (System.Net.Sockets.SocketException ex) {
+				Console.WriteLine("SocketException in PmlChannel.worker: " + ex.Message);
+			} catch (System.IO.EndOfStreamException ex) {
+				Console.WriteLine("EndOfStreamException in PmlChannel.worker: " + ex.Message);
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+			} finally {
+				Close();
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Channels/TCPPmlChannel.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+using UCIS.Net;
+
+namespace UCIS.Pml {
+	public class TCPPmlChannel : PassivePmlChannel {
+		private TCPStream _socket;
+		private IPmlRW _rw;
+		private bool _open = false;
+
+		public TCPPmlChannel(Socket socket) : this(new TCPStream(socket)) { }
+		public TCPPmlChannel(TCPStream socket) {
+			if (socket == null) throw new ArgumentNullException("socket");
+			_socket = socket;
+			_rw = new PmlBinaryRW(_socket);
+			_open = true;
+			//ThreadPool.RunTask(worker, null);
+		}
+
+		public override void WriteMessage(PmlElement message) {
+			if (!_open) throw new InvalidOperationException("The channel is not open");
+			lock (_rw) _rw.WriteMessage(message);
+		}
+
+		public override void Close() {
+			if (!_open) return;
+			_open = false;
+			if (_socket != null) try { _socket.Close(); } catch { }
+			base.Close();
+		}
+
+		public override PmlElement ReadMessage() {
+			return _rw.ReadMessage();
+		}
+
+		/*private void worker(Object state) {
+			try {
+				while (_open) {
+					base.PushReceivedMessage(_rw.ReadMessage());
+				}
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+			} finally {
+				Close();
+			}
+		}*/
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Array.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,281 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+//using KvpType = System.Collections.Generic.KeyValuePair<string, UCIS.Pml.PmlElement>;
+using KvpType = UCIS.Pml.PmlArray.KeyValuePair;
+
+namespace UCIS.Pml {
+	public class PmlArray : PmlElement, IDictionary<string, PmlElement>, IList<KvpType>, IList<PmlElement>, ICollection<String> {
+		/* Internal variables */
+		private List<KvpType> _items = new List<KvpType>();
+		private int _indexed = 0;
+
+		/* Internal key-value pair structure */
+		public class KeyValuePair {
+			internal KeyValuePair(string key, PmlElement value) { this.Key = key; this.Value = value; }
+			public string Key { get; set; }
+			public PmlElement Value { get; set; }
+		}
+
+		/* Constructors */
+		public PmlArray() {
+		}
+		public PmlArray(params KeyValuePair<string, PmlElement>[] elements) {
+			foreach (KeyValuePair<string, PmlElement> item in elements) Add(item);
+		}
+		public PmlArray(IEnumerable<KeyValuePair<string, PmlElement>> elements) {
+			foreach (KeyValuePair<String, PmlElement> item in elements) Add(item);
+		}
+		public PmlArray(params PmlElement[] elements) {
+			foreach (PmlElement item in elements) Add(item);
+		}
+		public PmlArray(IEnumerable<PmlElement> elements) {
+			foreach (PmlElement item in elements) Add(item);
+		}
+		public PmlArray(String key1, PmlElement val1) {
+			Add(key1, val1);
+		}
+		public PmlArray(String key1, PmlElement val1, String key2, PmlElement val2) {
+			Add(key1, val1);
+			Add(key2, val2);
+		}
+		public PmlArray(String key1, PmlElement val1, String key2, PmlElement val2, String key3, PmlElement val3) {
+			Add(key1, val1);
+			Add(key2, val2);
+			Add(key3, val3);
+		}
+		public PmlArray(params Object[] interleavedKeyValue) {
+			for (int i = 0; i < interleavedKeyValue.Length; ) {
+				Add(interleavedKeyValue[i++] as String, interleavedKeyValue[i++]);
+			}
+		}
+		public PmlArray(String[] keys, params PmlElement[] values) {
+			if (keys.Length != values.Length) throw new ArgumentException("Length of keys array does not match length of values array");
+			for (int i = 0; i < keys.Length; i++) { Add(keys[i] as String, values[i]); }
+		}
+
+		public bool IsIndexed {
+			get {
+				if (_indexed == -1) {
+					_indexed = 0;
+					foreach (KvpType kvp in _items) {
+						if (kvp.Key != null && kvp.Key.Length > 0) {
+							_indexed = 1;
+							break;
+						}
+					}
+				}
+				return _indexed != 0;
+			}
+		}
+
+		/* PmlElement implementation */
+		protected override object GetValue() { return _items; }
+		public override PmlElement GetChild(string Name) { return GetItem(Name); }
+		public override PmlElement GetChild(int index) { return GetItem(index); }
+		public override object ToNumeric() { return _items.Count; }
+		public override PmlElementType Type { get { return PmlElementType.Dictionary; } }
+
+		/* Internal KVP lookup */
+		private KvpType GetKVP(string name) {
+			return _items.Find(delegate(KvpType kvp) { return (kvp.Key == name); });
+		}
+		private KvpType GetKVP(PmlElement value) {
+			return _items.Find(delegate(KvpType kvp) { return (kvp.Value == value); });
+		}
+		private KvpType GetKVP(int index) {
+			if (index < 0 || index >= _items.Count) return null;
+			return _items[index];
+		}
+
+		/* Item retrieval */
+		public PmlElement GetItem(string name) {
+			KvpType kvp = GetKVP(name);
+			return kvp == null ? null : kvp.Value;
+		}
+		public PmlElement GetItem(int index) {
+			if (index < 0 || index >= _items.Count) return null;
+			return _items[index].Value;
+		}
+		public bool TryGetValue(string key, out PmlElement value) {
+			value = GetItem(key);
+			return (value != null);
+		}
+
+		/* Array implementation */
+		public PmlElement this[string key] {
+			get { return GetItem(key); }
+			set {
+				Remove(key);
+				Add(key, value);
+			}
+		}
+		public KvpType this[int id] {
+			get { return GetKVP(id); }
+			set { _items[id] = value; }
+		}
+		PmlElement IList<PmlElement>.this[int id] {
+			get { return GetItem(id); }
+			set {
+				KvpType item = GetKVP(id);
+				item = new KvpType(item == null ? null : item.Key, value);
+				_items[id] = item;
+			}
+		}
+
+		/* Add implementations */
+		public void Add(KvpType kvp) { //Final Add method, handles all additions (except insertions!)
+			if (_indexed == 0 && kvp.Key != null && kvp.Key.Length > 0) _indexed = 1;
+			_items.Add(kvp);
+		}
+
+		public PmlElement Add(string Key, PmlElement Element) {
+			if (Element == null) Element = new PmlNull();
+			Add(new KvpType(Key, Element));
+			return Element;
+		}
+
+		public PmlElement Add(string key, Object value) {
+			PmlElement el;
+			if (value == null) {
+				el = new PmlNull();
+			} else if (value is PmlElement) {
+				el = value as PmlElement;
+			} else if (value is String) {
+				el = new PmlString(value as string);
+			} else if (value is Int32 || value is Int64) {
+				el = new PmlNumber((Int64)value);
+			} else if (value is UInt32 || value is UInt32) {
+				el = new PmlNumber((UInt64)value);
+			} else {
+				el = new PmlString(value.ToString());
+			}
+			return Add(key, el);
+		}
+		public PmlElement Add(string Key, string Element) { return Add(Key, new PmlString(Element)); }
+		public PmlElement Add(string Key, long Element) { return Add(Key, new PmlInteger(Element)); }
+		public PmlElement Add(string Key, ulong Element) { return Add(Key, new PmlInteger(Element)); }
+
+		public PmlElement Add(PmlElement Element) { return Add(null, Element); }
+		public PmlElement Add(object Element) { return Add(null, Element); }
+		public PmlElement Add(string Element) { return Add(new PmlString(Element)); }
+		public PmlElement Add(long Element) { return Add(new PmlInteger(Element)); }
+		public PmlElement Add(ulong Element) { return Add(new PmlInteger(Element)); }
+
+		public void Add(KeyValuePair<string, PmlElement> item) { Add(item.Key, item.Value); }
+
+		void ICollection<PmlElement>.Add(PmlElement item) { Add(item); }
+		void IDictionary<String, PmlElement>.Add(string key, PmlElement value) { Add(key, value); }
+
+		/* Insert implementations */
+		private void Insert(int index, KvpType kvp) {
+			if (kvp.Key != null && kvp.Key.Length > 0 && _indexed == 0) _indexed = 1;
+			_items.Insert(index, kvp);
+		}
+		void IList<KvpType>.Insert(int index, KvpType value) { Insert(index, value); }
+		void IList<PmlElement>.Insert(int index, PmlElement value) { Insert(index, new KvpType(null, value)); }
+
+		/* Remove */
+		public bool Remove(KvpType item) {
+			_indexed = -1;
+			return _items.Remove(item);
+		}
+		public void RemoveAt(int index) {
+			_indexed = -1;
+			_items.RemoveAt(index);
+		}
+		public bool Remove(PmlElement item) {
+			KvpType kvp = GetKVP(item);
+			if (kvp == null) return false;
+			return Remove(kvp);
+		}
+		public bool Remove(string Key) {
+			KvpType kvp = GetKVP(Key);
+			if (kvp == null) return false;
+			return Remove(kvp);
+		}
+		bool ICollection<KeyValuePair<string, PmlElement>>.Remove(KeyValuePair<string, PmlElement> kvp) { return Remove(kvp.Key); }
+
+		public void Clear() {
+			_indexed = 0;
+			_items.Clear();
+		}
+
+		/* Contains */
+		public bool Contains(PmlElement item) { return GetKVP(item) != null; }
+		public bool Contains(string key) { return GetKVP(key) != null; }
+		bool IDictionary<String, PmlElement>.ContainsKey(string key) { return Contains(key); }
+		bool ICollection<KvpType>.Contains(KvpType kvp) { return _items.Contains(kvp); }
+		bool ICollection<KeyValuePair<String, PmlElement>>.Contains(KeyValuePair<String, PmlElement> kvp) { return Contains(kvp.Key); }
+
+		/* Index lookup */
+		public int IndexOf(PmlElement value) { return _items.FindIndex(delegate(KvpType kvp) { return (kvp.Value == value); }); }
+		int IList<KvpType>.IndexOf(KvpType value) { return _items.IndexOf(value); }
+
+		/* Copy operations */
+		public void CopyTo(KvpType[] array, int offset) {
+			_items.CopyTo(array, offset);
+		}
+		public void CopyTo(PmlElement[] array, int offset) {
+			foreach (KvpType kvp in _items) array[offset++] = kvp.Value;
+		}
+		void ICollection<String>.CopyTo(string[] array, int offset) {
+			foreach (KvpType kvp in _items) array[offset++] = kvp.Key;
+		}
+		void ICollection<KeyValuePair<string, PmlElement>>.CopyTo(KeyValuePair<string, PmlElement>[] array, int offset) {
+			foreach (KvpType kvp in _items) array[offset++] = new KeyValuePair<string,PmlElement>(kvp.Key, kvp.Value);
+		}
+
+		/* Dictionary props */
+		public ICollection<PmlElement> Values { get { return this as ICollection<PmlElement>; } }
+		public ICollection<String> Keys { get { return this as ICollection<String>; } }
+
+		/* Stuf... */
+		public int Count { get { return _items.Count; } }
+		public bool IsReadOnly { get { return false; } }
+		void ICollection<String>.Add(string value) { throw new NotImplementedException(); }
+
+		/* Enumerators */
+		IEnumerator<KvpType> IEnumerable<KvpType>.GetEnumerator() { return _items.GetEnumerator(); }
+		IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
+		public IEnumerator<PmlElement> GetEnumerator() { return new ValueEnumerator(this); }
+		IEnumerator<String> IEnumerable<String>.GetEnumerator() { return new KeyEnumerator(this); }
+		IEnumerator<KeyValuePair<string, PmlElement>> IEnumerable<KeyValuePair<string, PmlElement>>.GetEnumerator() { return new KvpEnumerator(this); }
+
+		private class KeyEnumerator : IEnumerator<String> {
+			protected IEnumerator<KvpType> _enum;
+			internal KeyEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); }
+			private KvpType KVP { get { return _enum.Current; } }
+			public bool MoveNext() { return _enum.MoveNext(); }
+			public void Reset() { _enum.Reset(); }
+			public void Dispose() { _enum.Dispose(); }
+			Object IEnumerator.Current { get { return Current; } }
+
+			public String Current { get { return KVP == null ? null : KVP.Key; } }
+		}
+		private class ValueEnumerator : IEnumerator<PmlElement> {
+			protected IEnumerator<KvpType> _enum;
+			internal ValueEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); }
+			private KvpType KVP { get { return _enum.Current; } }
+			public bool MoveNext() { return _enum.MoveNext(); }
+			public void Reset() { _enum.Reset(); }
+			public void Dispose() { _enum.Dispose(); }
+			Object IEnumerator.Current { get { return Current; } }
+
+			public PmlElement Current { get { return KVP == null ? null : KVP.Value; } }
+		}
+		private class KvpEnumerator : IEnumerator<KeyValuePair<String, PmlElement>> {
+			protected IEnumerator<KvpType> _enum;
+			internal KvpEnumerator(PmlArray array) { _enum = array._items.GetEnumerator(); }
+			private KvpType KVP { get { return _enum.Current; } }
+			public bool MoveNext() { return _enum.MoveNext(); }
+			public void Reset() { _enum.Reset(); }
+			public void Dispose() { _enum.Dispose(); }
+			Object IEnumerator.Current { get { return Current; } }
+
+			public KeyValuePair<String, PmlElement> Current { get {
+				return KVP == null ? default(KeyValuePair<String, PmlElement>) : new KeyValuePair<String, PmlElement>(KVP.Key, KVP.Value);
+			} }
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Binary.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,31 @@
+using System;
+using System.Text;
+
+namespace UCIS.Pml {
+	public class PmlBinary : PmlElement {
+		private byte[] _Value;
+
+		public PmlBinary(byte[] Value) {
+			_Value = Value;
+		}
+
+		public override PmlType Type { get { return PmlType.Binary; } }
+
+		public override object ToObject() { return _Value; }
+		public override string ToString() { return Encoding.UTF8.GetString(_Value); }
+		public override bool ToBoolean() { return BitConverter.ToBoolean(_Value, 0); }
+		public override byte ToByte() { return _Value[0]; }
+		public override decimal ToDecimal() { return _Value.Length == 4 ? (Decimal)BitConverter.ToSingle(_Value, 0) : (Decimal)BitConverter.ToDouble(_Value, 0); }
+		public override double ToDouble() { return BitConverter.ToDouble(_Value, 0); }
+		public override short ToInt16() { return BitConverter.ToInt16(_Value, 0); }
+		public override int ToInt32() { return BitConverter.ToInt32(_Value, 0); }
+		public override long ToInt64() { return BitConverter.ToInt64(_Value, 0); }
+		public override sbyte ToSByte() { return (SByte)_Value[0]; }
+		public override float ToSingle() { return BitConverter.ToSingle(_Value, 0); }
+		public override ushort ToUInt16() { return BitConverter.ToUInt16(_Value, 0); }
+		public override uint ToUInt32() { return BitConverter.ToUInt32(_Value, 0); }
+		public override ulong ToUInt64() { return BitConverter.ToUInt64(_Value, 0); }
+		public override char ToChar() { return BitConverter.ToChar(_Value, 0); }
+		public override byte[] ToByteArray() { return _Value; }
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Collection.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UCIS.Pml {
+	public class PmlCollection : PmlElement, ICollection<PmlElement> {
+			private List<PmlElement> pItems = new List<PmlElement>();
+
+			public PmlCollection() { 			}
+			public PmlCollection(params PmlElement[] Elements) {
+				pItems.AddRange(Elements);
+			}
+			public PmlCollection(IEnumerable<PmlElement> Elements) {
+				pItems.AddRange(Elements);
+			}
+
+			public PmlElement Add(PmlElement Element) {
+				pItems.Add(Element);
+				return Element;
+			}
+			public void Remove(PmlElement Element) {
+				pItems.Remove(Element);
+			}
+			public void RemoveAt(int Index) {
+				pItems.RemoveAt(Index);
+			}
+			public void Clear() {
+				pItems.Clear();
+			}
+			public bool Contains(PmlElement item) {
+				return pItems.Contains(item);
+			}
+			public void CopyTo(PmlElement[] array, int arrayIndex) {
+				pItems.CopyTo(array, arrayIndex);
+			}
+			public int Count { 				get { return pItems.Count; } 			}
+			public bool IsReadOnly { 				get { return false; } 			}
+			public IEnumerator<PmlElement> GetEnumerator() { 				return pItems.GetEnumerator(); 			}
+			IEnumerator IEnumerable.GetEnumerator() { 				return pItems.GetEnumerator(); 			}
+			bool ICollection<PmlElement>.Remove(PmlElement item) { 				return pItems.Remove(item); 			}
+			void ICollection<PmlElement>.Add(PmlElement item) { 				Add(item); 			}
+
+			public override PmlType Type { get { return PmlType.Collection; } }
+
+			public override object ToObject() { return pItems; }
+			public override string ToString() { return null; }
+			public override bool ToBoolean() { return pItems.Count > 0; }
+			public override byte ToByte() { return (Byte)pItems.Count; }
+			public override decimal ToDecimal() { return pItems.Count; }
+			public override double ToDouble() { return pItems.Count; }
+			public override short ToInt16() { return (Int16)pItems.Count; }
+			public override int ToInt32() { return pItems.Count; }
+			public override long ToInt64() { return pItems.Count; }
+			public override sbyte ToSByte() { return (SByte)pItems.Count; }
+			public override float ToSingle() { return pItems.Count; }
+			public override ushort ToUInt16() { return (UInt16)pItems.Count; }
+			public override uint ToUInt32() { return (UInt32)pItems.Count; }
+			public override ulong ToUInt64() { return (UInt64)pItems.Count; }
+			public override char ToChar() { return '\0'; }
+			public override byte[] ToByteArray() { return null; }
+
+			//public override PmlElement GetChild(string name) { return GetChild(name); }
+			public override PmlElement GetChild(int index) { return pItems[index]; }
+			public override IEnumerable<PmlElement> GetChildren() { return pItems; }
+			public override IEnumerable<KeyValuePair<String, PmlElement>> GetNamedChildren() {
+				KeyValuePair<String, PmlElement>[] kvps = new KeyValuePair<string, PmlElement>[pItems.Count];
+				for (int i = 0; i < kvps.Length; i++) kvps[i] = new KeyValuePair<string,PmlElement>(null, pItems[i]);
+				return kvps;
+			}
+			public override int GetChildCount() { return pItems.Count; }
+			public override void AddChild(string name, PmlElement value) { Add(value); }
+			public override void AddChild(PmlElement value) { Add(value); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Dictionary.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace UCIS.Pml {
+	public class PmlDictionary : PmlElement, IDictionary<string, PmlElement>, ICollection<PmlElement> {
+		private List<KeyValuePair<string, PmlElement>> pItems = new List<KeyValuePair<string, PmlElement>>();
+
+		public PmlDictionary() { }
+		public PmlDictionary(String[] keys, params PmlElement[] values) {
+			if (keys.Length != values.Length) throw new ArgumentException("keys.Length != values.Length", "values");
+			for (int i = 0; i < keys.Length; i++) Add(keys[i], values[i]);
+		}
+		public PmlDictionary(params KeyValuePair<string, PmlElement>[] Elements) {
+			foreach (KeyValuePair<string, PmlElement> Item in Elements) pItems.Add(Item);
+		}
+		public PmlDictionary(IEnumerable<KeyValuePair<string, PmlElement>> Elements) {
+			foreach (KeyValuePair<string, PmlElement> Item in Elements) pItems.Add(Item);
+		}
+
+		public override PmlElement GetChild(string Name) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				if (KVP.Key.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) return KVP.Value;
+			}
+			return null;
+		}
+		public override PmlElement GetChild(int index) {
+			return pItems[index].Value;
+		}
+		public bool TryGetValue(string key, out PmlElement value) {
+			value = GetChild(key);
+			return (value != null);
+		}
+		public PmlElement this[string key] {
+			get { return GetChild(key); }
+			set {
+				Remove(key);
+				Add(key, value);
+			}
+		}
+
+		public PmlElement Add(string Key, PmlElement Element) {
+			if (Element == null) Element = new PmlNull();
+			pItems.Add(new KeyValuePair<string, PmlElement>(Key, Element));
+			return Element;
+		}
+		private void Add(KeyValuePair<string, PmlElement> item) {
+			pItems.Add(item);
+		}
+		public void Add(PmlElement item) {
+			Add("", item);
+		}
+
+		void IDictionary<string, PmlElement>.Add(string key, PmlElement value) {
+			Add(key, value);
+		}
+		void ICollection<KeyValuePair<string, PmlElement>>.Add(KeyValuePair<string, PmlElement> item) {
+			Add(item);
+		}
+
+		public bool Remove(PmlElement item) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				if (KVP.Value == item) {
+					pItems.Remove(KVP);
+					return true;
+				}
+			}
+			return false;
+		}
+		public bool Remove(string Key) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				if (KVP.Key.Equals(Key, StringComparison.InvariantCultureIgnoreCase)) {
+					pItems.Remove(KVP);
+					return true;
+				}
+			}
+			return false;
+		}
+		public bool Remove(KeyValuePair<string, PmlElement> item) {
+			return ((ICollection<KeyValuePair<string, PmlElement>>)pItems).Remove(item);
+		}
+
+		public int Count {
+			get { return pItems.Count; }
+		}
+
+		public void Clear() {
+			pItems.Clear();
+		}
+
+		public bool Contains(PmlElement item) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				if (KVP.Value == item) return true;
+			}
+			return false;
+		}
+		bool ICollection<KeyValuePair<string, PmlElement>>.Contains(KeyValuePair<string, PmlElement> item) {
+			return ((ICollection<KeyValuePair<string, PmlElement>>)pItems).Contains(item);
+		}
+		public bool ContainsKey(string key) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				if (KVP.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)) return true;
+			}
+			return false;
+		}
+
+		void ICollection<KeyValuePair<string, PmlElement>>.CopyTo(KeyValuePair<string, PmlElement>[] array, int arrayIndex) {
+			((ICollection<KeyValuePair<string, PmlElement>>)pItems).CopyTo(array, arrayIndex);
+		}
+		void ICollection<PmlElement>.CopyTo(PmlElement[] array, int arrayIndex) {
+			foreach (KeyValuePair<string, PmlElement> KVP in pItems) {
+				array[arrayIndex] = KVP.Value;
+				arrayIndex += 1;
+			}
+		}
+
+		public ICollection<string> Keys {
+			get {
+				List<string> Ret = new List<string>();
+				foreach (KeyValuePair<string, PmlElement> KVP in pItems) Ret.Add(KVP.Key);
+				return Ret;
+			}
+		}
+		public ICollection<PmlElement> Values {
+			get {
+				List<PmlElement> Ret = new List<PmlElement>();
+				foreach (KeyValuePair<string, PmlElement> KVP in pItems) Ret.Add(KVP.Value);
+				return Ret;
+			}
+		}
+		public IEnumerator<KeyValuePair<string, PmlElement>> GetEnumerator() { return pItems.GetEnumerator(); }
+		IEnumerator IEnumerable.GetEnumerator() { return pItems.GetEnumerator(); }
+		IEnumerator<PmlElement> IEnumerable<PmlElement>.GetEnumerator() { return Values.GetEnumerator(); }
+
+		public bool IsReadOnly { get { return false; } }
+
+
+		public override PmlType Type { get { return PmlType.Dictionary; } }
+
+		public override object ToObject() { return pItems; }
+		public override string ToString() { return null; }
+		public override bool ToBoolean() { return pItems.Count > 0; }
+		public override byte ToByte() { return (Byte)pItems.Count; }
+		public override decimal ToDecimal() { return pItems.Count; }
+		public override double ToDouble() { return pItems.Count; }
+		public override short ToInt16() { return (Int16)pItems.Count; }
+		public override int ToInt32() { return pItems.Count; }
+		public override long ToInt64() { return pItems.Count; }
+		public override sbyte ToSByte() { return (SByte)pItems.Count; }
+		public override float ToSingle() { return pItems.Count; }
+		public override ushort ToUInt16() { return (UInt16)pItems.Count; }
+		public override uint ToUInt32() { return (UInt32)pItems.Count; }
+		public override ulong ToUInt64() { return (UInt64)pItems.Count; }
+		public override char ToChar() { return '\0'; }
+		public override byte[] ToByteArray() { return null; }
+
+		//public override PmlElement GetChild(string name) { return GetChild(name); }
+		//public override PmlElement GetChild(int index) { return GetChild(index); }
+		public override IEnumerable<PmlElement> GetChildren() { return Values; }
+		public override IEnumerable<KeyValuePair<String, PmlElement>> GetNamedChildren() { return pItems; }
+		public override int GetChildCount() { return pItems.Count; }
+		public override void AddChild(string name, PmlElement value) { Add(name, value); }
+		public override void AddChild(PmlElement value) { Add(value); }
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Element.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace UCIS.Pml {
+	/*public enum PmlElementType : byte {
+		Null = 0,
+
+		Dictionary = 1,
+		Collection = 2,
+
+		Binary = 10,
+		String = 11,
+
+		Integer = 20
+	}*/
+	public enum PmlType {
+		Null,
+		Dictionary,
+		Collection,
+		Binary,
+		String,
+		Integer,
+		//Number,
+	}
+	public abstract class PmlElement {
+		public abstract PmlType Type { get; }
+
+		public virtual PmlElement GetChild(string name) { return null; }
+		public virtual PmlElement GetChild(int index) { return null; }
+		public virtual IEnumerable<PmlElement> GetChildren() { return null; }
+		public virtual IEnumerable<KeyValuePair<String, PmlElement>> GetNamedChildren() { return null; }
+		public virtual int GetChildCount() { return 0; }
+		public virtual void AddChild(string name, PmlElement value) { throw new NotSupportedException(); }
+		public virtual void AddChild(PmlElement value) { throw new NotSupportedException(); }
+
+		public abstract object ToObject();
+		public abstract override string ToString();
+		public abstract bool ToBoolean();
+		public abstract byte ToByte();
+		public abstract decimal ToDecimal();
+		public abstract double ToDouble();
+		public abstract short ToInt16();
+		public abstract int ToInt32();
+		public abstract long ToInt64();
+		public abstract sbyte ToSByte();
+		public abstract float ToSingle();
+		public abstract ushort ToUInt16();
+		public abstract uint ToUInt32();
+		public abstract ulong ToUInt64();
+		public abstract char ToChar();
+		public abstract byte[] ToByteArray();
+
+		public static explicit operator string(PmlElement e) { return e == null ? null : e.ToString(); }
+		public static explicit operator bool(PmlElement e) { return e == null ? false : e.ToBoolean(); }
+		public static explicit operator byte(PmlElement e) { return e == null ? (byte)0 : e.ToByte(); }
+		public static explicit operator decimal(PmlElement e) { return e == null ? (decimal)0 : e.ToDecimal(); }
+		public static explicit operator double(PmlElement e) { return e == null ? (double)0 : e.ToDouble(); }
+		public static explicit operator short(PmlElement e) { return e == null ? (short)0 : e.ToInt16(); }
+		public static explicit operator int(PmlElement e) { return e == null ? (int)0 : e.ToInt32(); }
+		public static explicit operator long(PmlElement e) { return e == null ? (long)0 : e.ToInt64(); }
+		public static explicit operator sbyte(PmlElement e) { return e == null ? (sbyte)0 : e.ToSByte(); }
+		public static explicit operator float(PmlElement e) { return e == null ? (float)0 : e.ToSingle(); }
+		public static explicit operator ushort(PmlElement e) { return e == null ? (ushort)0 : e.ToUInt16(); }
+		public static explicit operator uint(PmlElement e) { return e == null ? (uint)0 : e.ToUInt32(); }
+		public static explicit operator ulong(PmlElement e) { return e == null ? (ulong)0 : e.ToUInt64(); }
+		public static explicit operator char(PmlElement e) { return e == null ? '\0' : e.ToChar(); }
+		public static explicit operator byte[](PmlElement e) { return e == null ? null : e.ToByteArray(); }
+
+		public static implicit operator PmlElement(String str) { return new PmlString(str); }
+		public static implicit operator PmlElement(UInt64 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(UInt32 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(Int64 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(Int32 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(Int16 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(UInt16 number) { return new PmlInteger(number); }
+		public static implicit operator PmlElement(Byte number) { return new PmlInteger(number); }
+		//public static implicit operator PmlElement(Double number) { return new PmlNumber(number); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Integer.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,52 @@
+using System;
+
+namespace UCIS.Pml {
+	public class PmlInteger : PmlElement {
+		private UInt64 pUValue;
+		private Int64 pSValue;
+		private bool pSigned;
+
+		public PmlInteger() {
+			pSValue = 0;
+			pSigned = true;
+		}
+		public PmlInteger(UInt64 Value) {
+			pUValue = Value;
+			pSigned = false;
+		}
+		public PmlInteger(Int64 Value) {
+			pSValue = Value;
+			pSigned = true;
+		}
+		public PmlInteger(string Value) {
+			if (Int64.TryParse(Value, out pSValue)) {
+				pSigned = true;
+			} else if (UInt64.TryParse(Value, out pUValue)) {
+				pSigned = false;
+			} else {
+				throw new FormatException();
+			}
+		}
+
+		public Boolean IsSigned { get { return pSigned; } }
+
+		public override PmlType Type { get { return PmlType.Integer; } }
+
+		public override object ToObject() { return pSigned ? (Object)pSValue : (Object)pUValue; }
+		public override string ToString() { return pSigned ? pSValue.ToString() : pUValue.ToString(); }
+		public override bool ToBoolean() { return pSigned ? (pSValue != 0) : (pUValue != 0); }
+		public override byte ToByte() { return pSigned ? (Byte)pSValue : (Byte)pUValue; }
+		public override decimal ToDecimal() { return pSigned ? (Decimal)pSValue : (Decimal)pUValue; }
+		public override double ToDouble() { return pSigned ? (Double)pSValue : (Double)pUValue; }
+		public override short ToInt16() { return pSigned ? (Int16)pSValue : (Int16)pUValue; }
+		public override int ToInt32() { return pSigned ? (Int32)pSValue : (Int32)pUValue; }
+		public override long ToInt64() { return pSigned ? pSValue : (Int64)pUValue; }
+		public override sbyte ToSByte() { return pSigned ? (SByte)pSValue : (SByte)pUValue; }
+		public override float ToSingle() { return pSigned ? (Single)pSValue : (Single)pUValue; }
+		public override ushort ToUInt16() { return pSigned ? (UInt16)pSValue : (UInt16)pUValue; }
+		public override uint ToUInt32() { return pSigned ? (UInt32)pSValue : (UInt32)pUValue; }
+		public override ulong ToUInt64() { return pSigned ? (UInt64)pSValue : pUValue; }
+		public override char ToChar() { return pSigned ? (Char)pSValue : (Char)pUValue; }
+		public override byte[] ToByteArray() { return pSigned ? BitConverter.GetBytes(pSValue) : BitConverter.GetBytes(pUValue); }
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/Number.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,37 @@
+using System;
+using System.Globalization;
+
+namespace UCIS.Pml {
+	public class PmlNumber : PmlElement {
+		private double _Value;
+
+		public PmlNumber() {
+			_Value = 0;
+		}
+		public PmlNumber(double Value) {
+			_Value = Value;
+		}
+		public PmlNumber(string Value) {
+			_Value = double.Parse(Value);
+		}
+
+		public override PmlType Type { get { return PmlType.Number; } }
+
+		public override object ToObject() { return _Value; }
+		public override string ToString() { return _Value.ToString("#,#", CultureInfo.InvariantCulture); }
+		public override bool ToBoolean() { return _Value != 0; }
+		public override byte ToByte() { return (Byte)_Value; }
+		public override decimal ToDecimal() { return (Decimal)_Value; }
+		public override double ToDouble() { return (Double)_Value; }
+		public override short ToInt16() { return (Int16)_Value; }
+		public override int ToInt32() { return (Int32)_Value; }
+		public override long ToInt64() { return (Int64)_Value; }
+		public override sbyte ToSByte() { return (SByte)_Value; }
+		public override float ToSingle() { return (Single)_Value; }
+		public override ushort ToUInt16() { return (UInt16)_Value; }
+		public override uint ToUInt32() { return (UInt32)_Value; }
+		public override ulong ToUInt64() { return (UInt64)_Value; }
+		public override char ToChar() { return (Char)_Value; }
+		public override byte[] ToByteArray() { return BitConverter.GetBytes(_Value); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/PmlNull.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,22 @@
+namespace UCIS.Pml {
+	public class PmlNull : PmlElement {
+		public override PmlType Type { get { return PmlType.Null; } }
+
+		public override object ToObject() { return null; }
+		public override string ToString() { return null; }
+		public override bool ToBoolean() { return false; }
+		public override byte ToByte() { return 0; }
+		public override decimal ToDecimal() { return 0; }
+		public override double ToDouble() { return 0; }
+		public override short ToInt16() { return 0; }
+		public override int ToInt32() { return 0; }
+		public override long ToInt64() { return 0; }
+		public override sbyte ToSByte() { return 0; }
+		public override float ToSingle() { return 0; }
+		public override ushort ToUInt16() { return 0; }
+		public override uint ToUInt32() { return 0; }
+		public override ulong ToUInt64() { return 0; }
+		public override char ToChar() { return '\0'; }
+		public override byte[] ToByteArray() { return null; }
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/Elements/PmlString.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,32 @@
+using System;
+using System.Text;
+using System.Globalization;
+
+namespace UCIS.Pml {
+	public class PmlString : PmlElement {
+		private string _Value;
+
+		public PmlString(string Value) {
+			_Value = Value;
+		}
+
+		public override PmlType Type { get { return PmlType.String; } }
+
+		public override object ToObject() { return _Value; }
+		public override string ToString() { return _Value; }
+		public override bool ToBoolean() { return Boolean.Parse(_Value); }
+		public override byte ToByte() { return Byte.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override decimal ToDecimal() { return Decimal.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override double ToDouble() { return Double.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override short ToInt16() { return Int16.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override int ToInt32() { return Int32.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override long ToInt64() { return Int64.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override sbyte ToSByte() { return SByte.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override float ToSingle() { return Single.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override ushort ToUInt16() { return UInt16.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override uint ToUInt32() { return UInt32.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override ulong ToUInt64() { return UInt64.Parse(_Value, CultureInfo.InvariantCulture); }
+		public override char ToChar() { return _Value[0]; }
+		public override byte[] ToByteArray() { return Encoding.UTF8.GetBytes(_Value); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/IPmlCommunicator.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace UCIS.Pml {
+	public class PmlCallReceivedEventArgs : EventArgs {
+		private PmlElement _request;
+		private PmlElement _reply;
+		private UInt32 _sid;
+		private bool _wantReply;
+
+		internal PmlCallReceivedEventArgs(PmlElement request, bool wantReply, UInt32 sid) {
+			_request = request;
+			_wantReply = wantReply;
+			_sid = sid;
+			_reply = null;
+		}
+		public bool WantReply {
+			get { return _wantReply; }
+		}
+		internal UInt32 SID {
+			get { return _sid; }
+		}
+		public PmlElement Reply {
+			get { return _reply; }
+			set { _reply = value; }
+		}
+		public PmlElement Request {
+			get { return _request; }
+		}
+	}
+	public abstract class PmlChannelRequestReceivedEventArgs : EventArgs {
+		public abstract IPmlChannel Accept();
+		public abstract void Reject();
+		public abstract PmlElement Data { get; }
+	}
+	public interface IPmlCommunicator {
+		event EventHandler<PmlCallReceivedEventArgs> CallReceived;
+		event EventHandler<PmlChannelRequestReceivedEventArgs> ChannelRequestReceived;
+
+		void Call(PmlElement message);
+		PmlElement Invoke(PmlElement message);
+
+		IAsyncResult BeginInvoke(PmlElement message, AsyncCallback callback, Object state);
+		PmlElement EndInvoke(IAsyncResult result);
+
+		IPmlChannel CreateChannel(PmlElement data);
+		IAsyncResult BeginCreateChannel(PmlElement data, AsyncCallback callback, Object state);
+		IPmlChannel EndCreateChannel(IAsyncResult result);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/IPmlRpc.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+
+namespace UCIS.Pml {
+	interface IPmlRpcServer {
+		IDictionary<string, Delegate> ExportedMethods { get; }
+		IDictionary<string, Object> ExportedObjects { get; }
+	}
+	interface IPmlRpcClient {
+		void Call(String method, params Object[] args);
+		void Invoke(String method, params Object[] args);
+		void BeginInvoke(String method, Object[] args, AsyncCallback callback, Object state);
+		Object EndInvoke(IAsyncResult result);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/LegacyPmlCommunicator.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,403 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using UCIS.Pml;
+
+namespace UCIS.Pml {
+	public class LegacyPmlCommunicator {
+		private class CSyncRequest {
+			internal PmlElement Reply;
+			internal ManualResetEvent ResetEvent = new ManualResetEvent(false);
+		}
+		public abstract class SessionBase {
+			private bool pActive;
+			private LegacyPmlCommunicator pConnection;
+			private UInt32 pSID;
+
+			public uint SID { get { return pSID; } }
+			public bool Active { get { return pActive; } }
+			public LegacyPmlCommunicator Communicator { get { return pConnection; } }
+
+			protected SessionBase(LegacyPmlCommunicator Connection) {
+				pConnection = Connection;
+			}
+
+			protected void Accept(UInt32 SID) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				pSID = SID;
+				lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this);
+				pActive = true;
+			}
+			protected void Request() {
+				Request(null);
+			}
+			protected void Request(PmlElement Message) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				pSID = pConnection.GetNextSessionId(true);
+				lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this);
+				pConnection.WriteSessionMessage(pSID, 0, Message);
+				pActive = true;
+			}
+
+			protected internal abstract void MessageIn(PmlElement Message);
+
+			protected void SendMessage(PmlElement Message) {
+				if (!pActive) throw new InvalidOperationException("Session is not active");
+				pConnection.WriteSessionMessage(pSID, 1, Message);
+			}
+
+			public void Close() {
+				Close(null);
+			}
+			public void Close(PmlElement Message) {
+				if (!pActive) return; // throw new InvalidOperationException("Session is not active");
+				pConnection.WriteSessionMessage(pSID, 2, Message);
+				ClosedA();
+			}
+
+			internal void ClosedA() {
+				pActive = false;
+				lock (pConnection.pSessions) pConnection.pSessions.Remove(pSID);
+			}
+
+			internal void ClosedB(PmlElement Message) {
+				pActive = false;
+				Closed(Message);
+			}
+
+			protected virtual void Closed(PmlElement Message) {
+			}
+		}
+		public class Session : SessionBase {
+			public event MessageReceivedEventHandler MessageReceived;
+			public delegate void MessageReceivedEventHandler(PmlElement Message);
+			public event SessionClosedEventHandler SessionClosed;
+			public delegate void SessionClosedEventHandler(PmlElement Message);
+
+			public Session(LegacyPmlCommunicator Connection) : base(Connection) { }
+
+			public new void Accept(UInt32 SID) {
+				base.Accept(SID);
+			}
+			public new void Request() {
+				Request(null);
+			}
+			public new void Request(PmlElement Message) {
+				base.Request(Message);
+			}
+
+			protected internal override void MessageIn(PmlElement Message) {
+				if (MessageReceived != null) MessageReceived(Message);
+			}
+
+			public new void SendMessage(PmlElement Message) {
+				base.SendMessage(Message);
+			}
+
+			protected override void Closed(PmlElement Message) {
+				if (SessionClosed != null) SessionClosed(Message);
+			}
+		}
+
+		private Dictionary<UInt32, SessionBase> pSessions = new Dictionary<UInt32, SessionBase>();
+		private UInt32 pNextSession;
+		private Dictionary<UInt32, CSyncRequest> pSyncRequests = new Dictionary<UInt32, CSyncRequest>();
+		private UInt32 pNextSyncRequest;
+
+		private IPmlChannel _channel;
+
+		public event MessageReceivedEventHandler MessageReceived;
+		public delegate void MessageReceivedEventHandler(PmlElement Message);
+		public event RequestReceivedEventHandler RequestReceived;
+		public delegate void RequestReceivedEventHandler(PmlElement Request, ref PmlElement Reply);
+		public event SessionRequestReceivedEventHandler SessionRequestReceived;
+		public delegate void SessionRequestReceivedEventHandler(PmlElement Request, uint SID);
+		public event EventHandler Closed;
+
+		public ICollection<SessionBase> Sessions { get { return (ICollection<SessionBase>)pSessions.Values; } }
+		public int SyncRequests { get { return pSyncRequests.Count; } }
+
+		public LegacyPmlCommunicator(IPmlChannel channel, bool autoStart) {
+			_channel = channel;
+			if (autoStart) Start();
+			//_channel.BeginReadMessage(messageReceived, null);
+			//_channel.MessageReceived += messageReceived;
+			//_channel.Closed += closed;
+		}
+		public void Start() {
+			_channel.BeginReadMessage(messageReceived, null);
+		}
+
+		public IPmlChannel Channel { get { return _channel; } }
+
+		public void Close() {
+			//_channel.MessageReceived -= messageReceived;
+			//_channel.Closed -= closed;
+			_channel.Close();
+		}
+
+		private void _WriteMessage(PmlElement Message) {
+			lock (_channel) {
+				if (_channel.IsOpen) {
+					_channel.WriteMessage(Message);
+				} else {
+					throw new InvalidOperationException("Could not write message: the channel is not open");
+				}
+			}
+		}
+
+		private UInt32 GetNextSessionId(bool IsSession) {
+			if (IsSession) {
+				lock (pSessions) {
+					do {
+						if (pNextSession == UInt32.MaxValue) {
+							pNextSession = 0;
+						} else {
+							pNextSession += (uint)1;
+						}
+					}
+					while (pSessions.ContainsKey(pNextSession));
+					return pNextSession;
+				}
+			} else {
+				lock (pSyncRequests) {
+					do {
+						if (pNextSyncRequest == UInt32.MaxValue) {
+							pNextSyncRequest = 0;
+						} else {
+							pNextSyncRequest += (uint)1;
+						}
+					}
+					while (pSyncRequests.ContainsKey(pNextSyncRequest));
+					return pNextSyncRequest;
+				}
+			}
+		}
+
+		protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			Msg2.Add("CMD", new PmlString("SES"));
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("SCMD", new PmlInteger(CMD));
+			Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+
+		protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			if (RPL) {
+				Msg2.Add("CMD", new PmlString("RPL"));
+			} else {
+				Msg2.Add("CMD", new PmlString("REQ"));
+			}
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+
+		private void messageReceived(IAsyncResult ar) {
+			PmlElement Message;
+			try {
+				Message = _channel.EndReadMessage(ar);
+				_channel.BeginReadMessage(messageReceived, null);
+			} catch (InvalidOperationException ex) {
+				Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message);
+				closed();
+				_channel.Close();
+				return;
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+				closed();
+				_channel.Close();
+				return;
+			}
+			int Ping = 0;
+			if (Message == null) {
+				if (Ping > 2) {
+					_channel.Close();
+					return;
+				} else {
+					_WriteMessage(new PmlString("PING"));
+				}
+				Ping += 1;
+			} else if (Message is PmlString) {
+				string Cmd = Message.ToString();
+				if (Cmd.Equals("PING")) {
+					_WriteMessage(new PmlString("PONG"));
+				} else if (Cmd.Equals("PONG")) {
+					Ping = 0;
+				}
+			} else if (Message is PmlDictionary) {
+				string Cmd = null;
+				Cmd = Message.GetChild("CMD").ToString();
+				if (Cmd.Equals("SES")) {
+					UInt32 SID = default(UInt32);
+					byte SCMD = 0;
+					SessionBase Session = default(SessionBase);
+					PmlElement InnerMsg = default(PmlElement);
+					SID = Message.GetChild("SID").ToUInt32();
+					SCMD = Message.GetChild("SCMD").ToByte();
+					InnerMsg = Message.GetChild("MSG");
+					lock (pSessions) {
+						if (pSessions.ContainsKey(SID)) {
+							Session = pSessions[SID];
+						} else {
+							Session = null;
+						}
+					}
+					if (SCMD == 0) {
+						if (Session == null) {
+							if (SessionRequestReceived != null) {
+								try {
+									SessionRequestReceived(InnerMsg, SID);
+								} catch (Exception ex) {
+									Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->SessionRequestReceived: " + ex.ToString());
+									WriteSessionMessage(SID, 2, null);
+								}
+							}
+						} else {
+							try {
+								Session.ClosedA();
+								Session.ClosedB(null);
+							} catch (Exception ex) {
+								Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.ClosedA/B: " + ex.ToString());
+							}
+							WriteSessionMessage(SID, 2, null);
+						}
+					} else if (SCMD == 1) {
+						if (Session == null) {
+							WriteSessionMessage(SID, 2, null);
+						} else {
+							try {
+								Session.MessageIn(InnerMsg);
+							} catch (Exception ex) {
+								Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.MessageIn: " + ex.ToString());
+								WriteSessionMessage(SID, 2, null);
+							}
+						}
+					} else if (SCMD == 2) {
+						if (Session != null) {
+							try {
+								Session.ClosedA();
+								Session.ClosedB(InnerMsg);
+							} catch (Exception ex) {
+								Console.WriteLine("Exception in LegacyPmlCommnuicator.messageReceived->Session.ClosedA/B: " + ex.ToString());
+							}
+						}
+					}
+				} else if (Cmd.Equals("RPL")) {
+					UInt32 SID = default(UInt32);
+					CSyncRequest SRequest = null;
+					SID = Message.GetChild("SID").ToUInt32();
+					lock (pSyncRequests) {
+						if (pSyncRequests.TryGetValue(SID, out SRequest)) {
+							pSyncRequests.Remove(SID);
+						} else {
+							Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString());
+						}
+					}
+					if (SRequest != null) {
+						SRequest.Reply = Message.GetChild("MSG");
+						SRequest.ResetEvent.Set();
+					}
+				} else if (Cmd.Equals("REQ")) {
+					UCIS.ThreadPool.RunCall(SyncRequestHandler, Message);
+					//System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SyncRequestHandler), Message);
+				} else if (Cmd.Equals("MSG")) {
+					PmlElement InnerMsg = Message.GetChild("MSG");
+					if (MessageReceived != null) MessageReceived(InnerMsg);
+				} else {
+					throw new InvalidOperationException("Invalid operation");
+				}
+			}
+		}
+		private void closed() {
+			//_channel.MessageReceived -= messageReceived;
+			//_channel.Closed -= closed;
+			Console.WriteLine("UCIS.PML.Connection: Connection closed");
+			try {
+				SessionBase[] sessions;
+				lock (pSessions) {
+					sessions = new SessionBase[pSessions.Count];
+					pSessions.Values.CopyTo(sessions, 0);
+				}
+				foreach (SessionBase S in sessions) {
+					try {
+						S.ClosedB(null);
+					} catch (Exception ex) {
+						Console.WriteLine(ex.ToString());
+					}
+				}
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+			}
+			lock (pSessions) pSessions.Clear();
+			try {
+				CSyncRequest[] reqs;
+				lock (pSyncRequests) {
+					reqs = new CSyncRequest[pSyncRequests.Count];
+					pSyncRequests.Values.CopyTo(reqs, 0);
+				}
+				foreach (CSyncRequest T in reqs) {
+					T.ResetEvent.Set();
+				}
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+			}
+			lock (pSyncRequests) pSyncRequests.Clear();
+			if (Closed != null) Closed(this, new EventArgs());
+		}
+
+		private void SyncRequestHandler(object state) {
+			PmlDictionary Message = (PmlDictionary)state;
+			PmlElement Reply = null;
+			UInt32 SID = 0;
+			try {
+				SID = Message.GetChild("SID").ToUInt32();
+				PmlElement InnerMsg = Message.GetChild("MSG");
+				if (RequestReceived != null) {
+					RequestReceived(InnerMsg, ref Reply);
+				}
+			} catch (Exception ex) {
+				Reply = new PmlDictionary();
+				((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString()));
+				Console.WriteLine(ex.ToString());
+			}
+			try {
+				WriteSyncMessage(SID, true, Reply);
+			} catch (Exception ex) {
+				Console.WriteLine("Exception: " + ex.ToString());
+			}
+		}
+
+		public PmlElement SyncRequest(PmlElement Request) {
+			return SyncRequest(Request, 30000);
+		}
+		public PmlElement SyncRequest(PmlElement Request, int Timeout) {
+			CSyncRequest SyncEvent = new CSyncRequest();
+			UInt32 SID = GetNextSessionId(false);
+			lock (pSyncRequests) pSyncRequests.Add(SID, SyncEvent);
+			try {
+				WriteSyncMessage(SID, false, Request);
+				if (!SyncEvent.ResetEvent.WaitOne(Timeout, false)) {
+					lock (pSyncRequests) pSyncRequests.Remove(SID);
+					throw new TimeoutException("The SyncRequest timed out (SID=" + SID.ToString() + ")");
+				}
+			} finally {
+				lock (pSyncRequests) pSyncRequests.Remove(SID);
+			}
+			return SyncEvent.Reply;
+		}
+
+		public void SendMessage(PmlElement Message) {
+			PmlDictionary Msg = new PmlDictionary();
+			Msg.Add("CMD", new PmlString("MSG"));
+			Msg.Add("MSG", Message);
+			_WriteMessage(Msg);
+		}
+
+		public void SendRawMessage(PmlElement Message) {
+			_WriteMessage(Message);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/PmlBuilder.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace UCIS.Pml {
+	public class PmlBuilder {
+		private IPmlWriter pWriter;
+		private Stack<PmlElement> pStack = new Stack<PmlElement>();
+
+		public PmlBuilder(IPmlWriter Writer) {
+			pWriter = Writer;
+		}
+		public PmlBuilder() {
+			pWriter = null;
+		}
+
+		public IPmlWriter BaseWriter {
+			get { return pWriter; }
+			set { pWriter = value; }
+		}
+
+		private PmlElement AddChildElement(PmlElement Element, bool AddToStack) {
+			return AddChildElement(Element, AddToStack, null);
+		}
+		private PmlElement AddChildElement(PmlElement Element, bool AddToStack, string ChildName) {
+			PmlElement Parent;
+			if (pStack.Count > 0) {
+				Parent = pStack.Peek();
+				if (Parent is PmlDictionary) {
+					if (ChildName == null) throw new ArgumentNullException("ChildName", "Dictionary items need a Name");
+					((PmlDictionary)Parent).Add(ChildName, Element);
+				} else if (Parent is PmlCollection) {
+					if (ChildName != null) throw new ArgumentOutOfRangeException("ChildName", "Can not add named element to a Collection");
+					((PmlCollection)Parent).Add(Element);
+				} else {
+					throw new InvalidOperationException("Invalid Element type in stack: " + Parent.Type.ToString());
+				}
+			} else {
+				if (ChildName != null) {
+					throw new ArgumentOutOfRangeException("ChildName", "Can not create named element without container (Dictionary)");
+				} else if (!AddToStack) {
+					pWriter.WriteMessage(Element);
+				}
+			}
+			if (AddToStack) pStack.Push(Element);
+			return Element;
+		}
+
+		public PmlElement EndElement() {
+			if (pStack.Count > 0) {
+				PmlElement Element = pStack.Pop();
+				if (pStack.Count == 0) {
+					if (pWriter != null) pWriter.WriteMessage(Element);
+				}
+				return Element;
+			} else {
+				return null;
+			}
+		}
+		public PmlElement GetMessage() {
+			if (pStack.Count == 1) {
+				PmlElement Element = pStack.Pop();
+				return Element;
+			} else if (pStack.Count == 0) {
+				throw new InvalidOperationException("No stacked element. The top most element should not be ended. All elements, except Dictionary and Collection, are sent automatically.");
+			} else {
+				throw new InvalidOperationException("All elements, except for the top most element, should be ended.");
+			}
+		}
+
+		public PmlElement SendMessage() {
+			PmlElement Element;
+			if (pWriter == null) throw new NullReferenceException("Writer is not set");
+			Element = GetMessage();
+			pWriter.WriteMessage(Element);
+			return Element;
+		}
+
+		public PmlDictionary Dictionary() {
+			return (PmlDictionary)AddChildElement(new PmlDictionary(), true);
+		}
+		public PmlCollection Collection() {
+			return (PmlCollection)AddChildElement(new PmlCollection(), true);
+		}
+		public PmlString String(string Value) {
+			return (PmlString)AddChildElement(new PmlString(Value), false);
+		}
+		public PmlBinary Binary(byte[] Value) {
+			return (PmlBinary)AddChildElement(new PmlBinary(Value), false);
+		}
+		public PmlInteger Integer(UInt64 Value) {
+			return (PmlInteger)AddChildElement(new PmlInteger(Value), false);
+		}
+		public PmlInteger Integer(Int64 Value) {
+			return (PmlInteger)AddChildElement(new PmlInteger(Value), false);
+		}
+		public PmlNull Null() {
+			return (PmlNull)AddChildElement(new PmlNull(), false);
+		}
+		public PmlElement Element(PmlElement Child) {
+			return AddChildElement(Child, false);
+		}
+
+		public PmlDictionary Dictionary(string Name) {
+			return (PmlDictionary)AddChildElement(new PmlDictionary(), true, Name);
+		}
+		public PmlCollection Collection(string Name) {
+			return (PmlCollection)AddChildElement(new PmlCollection(), true, Name);
+		}
+		public PmlString String(string Name, string Value) {
+			return (PmlString)AddChildElement(new PmlString(Value), false, Name);
+		}
+		public PmlBinary Binary(string Name, byte[] Value) {
+			return (PmlBinary)AddChildElement(new PmlBinary(Value), false, Name);
+		}
+		public PmlInteger Integer(string Name, UInt64 Value) {
+			return (PmlInteger)AddChildElement(new PmlInteger(Value), false, Name);
+		}
+		public PmlInteger Integer(string Name, Int64 Value) {
+			return (PmlInteger)AddChildElement(new PmlInteger(Value), false, Name);
+		}
+		public PmlNull Null(string Name) {
+			return (PmlNull)AddChildElement(new PmlNull(), false, Name);
+		}
+		public PmlElement Element(string Name, PmlElement Child) {
+			return AddChildElement(Child, false, Name);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/PmlCommunicator.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,342 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace UCIS.Pml {
+/*	class PmlCommunicator : IPmlCommunicator, IDisposable {
+		private IPmlChannel _channel;
+		private Dictionary<UInt32, IPmlSubChannel> _subchannels = new Dictionary<uint,IPmlSubChannel>();
+		private Random _random = new Random();
+
+		private enum CommandCode : int {
+			CallWithoutReply = 0,
+			CallWithReply = 1,
+			Message = 2,
+			ChannelRequest = 3,
+			ChannelAcknowledge = 4,
+			ChannelClose = 5,
+			Error = 6
+		}
+
+		private interface IPmlSubChannel {
+			void CloseIn();
+			void ErrorIn(PmlElement message);
+			void MessageIn(PmlElement message);
+		}
+
+		private class ChannelRequestWaitHandler : IAsyncResult {
+			internal AsyncCallback Callback = null;
+			internal Object CallbackState = null;
+			internal ManualResetEvent Event = null;
+			internal PmlSubChannel Channel = null;
+			internal bool Completed = false;
+
+			internal ChannelRequestWaitHandler(PmlSubChannel channel) {
+				Channel = channel;
+			}
+
+			internal void Complete() {
+				Completed = true;
+				if (Event != null) Event.Set();
+				if (Callback != null) Callback.Invoke(this);
+			}
+
+			public object AsyncState { get { return CallbackState; } }
+			public WaitHandle AsyncWaitHandle { get { return null; } }
+			public bool CompletedSynchronously { get { return false; } }
+			public bool IsCompleted { get { return Completed; } }
+		}
+		private class PmlSubChannel : ActivePmlChannel, IPmlSubChannel {
+			private enum ChannelState { Requesting, Acknowledged, Closed }
+
+			private PmlCommunicator _communicator;
+			private UInt32 _id;
+			private ChannelState _state;
+
+			internal PmlSubChannel(PmlCommunicator communicator, UInt32 sid) {
+				_communicator = communicator;
+				_id = sid;
+				_state = ChannelState.Requesting;
+			}
+
+			public override bool IsOpen { get { return _state == ChannelState.Acknowledged; } }
+
+			internal void AcknowledgeIn() {
+				if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement");
+				_state = ChannelState.Acknowledged;
+			}
+			void IPmlSubChannel.CloseIn() {
+				_state = ChannelState.Closed;
+				_communicator._subchannels.Remove(_id);
+				base.Close();
+			}
+			void IPmlSubChannel.ErrorIn(PmlElement message) {
+				(this as IPmlSubChannel).CloseIn();
+			}
+			void IPmlSubChannel.MessageIn(PmlElement message) {
+				base.PushReceivedMessage(message);
+			}
+
+			internal void AcknowledgeOut() {
+				if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement");
+				_state = ChannelState.Acknowledged;
+				_communicator.sendMessage(CommandCode.ChannelAcknowledge, _id, null);
+			}
+			internal void RejectOut() {
+				if (_state != 0) throw new InvalidOperationException("The subchannel is not awaiting an acknowledgement");
+				_state = ChannelState.Closed;
+				_communicator.sendMessage(CommandCode.ChannelClose, _id, null);
+			}
+
+			public override void SendMessage(PmlElement message) {
+				if (_state != ChannelState.Acknowledged) throw new InvalidOperationException("The subchannel is not open");
+				_communicator.sendMessage(CommandCode.Message, _id, message);
+			}
+			public override void Close() {
+				if (_state != ChannelState.Acknowledged) return;
+				_state = ChannelState.Closed;
+				_communicator.sendMessage(CommandCode.ChannelClose, _id, null);
+				_communicator._subchannels.Remove(_id);
+				base.Close();
+			}
+		}
+		private class PmlChannelRequestReceivedEventArgsA : PmlChannelRequestReceivedEventArgs {
+			private PmlCommunicator _communicator;
+			private PmlElement _data;
+			private PmlSubChannel _channel;
+			private bool _accepted;
+			private bool _rejected;
+			internal PmlChannelRequestReceivedEventArgsA(PmlCommunicator communicator, UInt32 sid, PmlElement message) {
+				_communicator = communicator;
+				_channel = new PmlSubChannel(communicator, sid);
+				_data = message;
+			}
+			public override IPmlChannel Accept() {
+				if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected");
+				_accepted = true;
+				_channel.AcknowledgeOut();
+				return _channel;
+			}
+			public override void Reject() {
+				if (_accepted) throw new InvalidOperationException("The channel has already been accepted");
+				if (_rejected) return;
+				_rejected = true;
+				_channel.RejectOut();
+			}
+			internal void RejectIfNotAccepted() {
+				if (!_accepted) Reject();
+			}
+			public override PmlElement Data {
+				get {
+					return _data;
+				}
+			}
+		}
+
+		private class PmlInvocation : IAsyncResult, IPmlSubChannel {
+			internal PmlCommunicator Communicator = null;
+			internal AsyncCallback Callback = null;
+			internal Object CallbackState = null;
+			internal bool Error = false;
+			internal bool Completed = false;
+			internal PmlElement Message = null;
+			internal ManualResetEvent Event = null;
+			internal UInt32 ID;
+
+			internal PmlInvocation(PmlCommunicator communicator, UInt32 id) {
+				Communicator = communicator;
+				ID = id;
+			}
+
+			void IPmlSubChannel.CloseIn() {
+				(this as IPmlSubChannel).ErrorIn(null);
+			}
+			void IPmlSubChannel.ErrorIn(PmlElement message) {
+				Error = true;
+				Communicator._subchannels.Remove(ID);
+				(this as IPmlSubChannel).MessageIn(message);
+			}
+			void IPmlSubChannel.MessageIn(PmlElement message) {
+				Message = message;
+				Completed = true;
+				if (Event != null) Event.Set();
+				if (Callback != null) Callback.Invoke(this);
+			}
+
+			public object AsyncState { get { return CallbackState; } }
+			public WaitHandle AsyncWaitHandle { get { return null; } }
+			public bool CompletedSynchronously { get { return false; } }
+			public bool IsCompleted { get { return Completed; } }
+		}
+
+		public event EventHandler<PmlCallReceivedEventArgs> CallReceived;
+		public event EventHandler<PmlChannelRequestReceivedEventArgs> ChannelRequestReceived;
+
+		public PmlCommunicator(IPmlChannel channel) {
+			_channel = channel;
+			_channel.Closed += channelClosed;
+		}
+
+		public void Dispose() {
+			_channel.Close();
+			_channel = null;
+			IPmlSubChannel[] A = new IPmlSubChannel[_subchannels.Count];
+			_subchannels.Values.CopyTo(A, 0);
+			foreach (IPmlSubChannel S in A) S.CloseIn();
+			_subchannels.Clear();
+			_subchannels = null;
+			_random = null;
+		}
+
+		private void channelClosed(Object sender, EventArgs e) {
+			Dispose();
+		}
+
+		public IPmlChannel Channel { get { return _channel; } }
+
+		public void Call(PmlElement message) {
+			sendMessage(0, 0, message); //Call without reply
+		}
+		public PmlElement Invoke(PmlElement message) {
+			return Invoke(message, 60000);
+		}
+		public PmlElement Invoke(PmlElement message, int timeout) {
+			UInt32 sid = getSessionID();
+			PmlInvocation inv = new PmlInvocation(this, sid);
+			inv.Event = new ManualResetEvent(false);
+			_subchannels.Add(sid, inv);
+			sendMessage(CommandCode.CallWithReply, sid, message);
+			inv.Event.WaitOne(timeout);
+			if (inv.Error) throw new Exception(message.ToString());
+			return inv.Message;
+		}
+
+		public IAsyncResult BeginInvoke(PmlElement message, AsyncCallback callback, Object state) {
+			UInt32 sid = getSessionID();
+			PmlInvocation inv = new PmlInvocation(this, sid);
+			inv.Callback = callback;
+			inv.CallbackState = state;
+			_subchannels.Add(sid, inv);
+			sendMessage(CommandCode.CallWithReply, sid, message);
+			return inv;
+		}
+		public PmlElement EndInvoke(IAsyncResult result) {
+			PmlInvocation ar = (PmlInvocation)result;
+			if (!ar.Completed) {
+				(_subchannels as IList<IPmlSubChannel>).Remove(ar);
+				throw new InvalidOperationException("The asynchronous operation has not completed");
+			} else if (ar.Error) {
+				throw new Exception(ar.Message.ToString());
+			} else {
+				return ar.Message;
+			}
+		}
+
+		public IPmlChannel CreateChannel(PmlElement data) {
+			UInt32 sid = getSessionID();
+			PmlSubChannel ch = new PmlSubChannel(this, sid);
+			ChannelRequestWaitHandler wh = new ChannelRequestWaitHandler(ch);
+			wh.Event = new ManualResetEvent(false);
+			_subchannels.Add(sid, ch);
+			sendMessage(CommandCode.ChannelRequest, sid, data);
+			wh.Event.WaitOne();
+			if (!ch.IsOpen) return null;
+			return ch;
+		}
+		public IAsyncResult BeginCreateChannel(PmlElement data, AsyncCallback callback, Object state) {
+			UInt32 sid = getSessionID();
+			PmlSubChannel ch = new PmlSubChannel(this, sid);
+			ChannelRequestWaitHandler wh = new ChannelRequestWaitHandler(ch);
+			wh.Callback = callback;
+			wh.CallbackState = state;
+			_subchannels.Add(sid, ch);
+			sendMessage(CommandCode.ChannelRequest, sid, data);
+			if (!ch.IsOpen) return null;
+			return wh;
+		}
+		public IPmlChannel EndCreateChannel(IAsyncResult result) {
+			ChannelRequestWaitHandler ar = (ChannelRequestWaitHandler)result;
+			if (!ar.Channel.IsOpen) return null;
+			return ar.Channel;
+		}
+
+		private UInt32 getSessionID() {
+			return (uint)_random.Next();
+		}
+
+		private void sendMessage(CommandCode cmd, uint sid, PmlElement message) {
+			PmlDictionary msg = new PmlDictionary();
+			msg.Add("c", (int)cmd);
+			if (cmd > 0) msg.Add("s", sid);
+			if (message != null) msg.Add("m", message);
+			_channel.SendMessage(msg);
+		}
+
+		private void invokeCallReceived(Object state) {
+			PmlCallReceivedEventArgs e = (PmlCallReceivedEventArgs)state;
+			try {
+				if (CallReceived != null) CallReceived(this, e);
+				if (e.WantReply) sendMessage(CommandCode.Message, e.SID, e.Reply);
+			} catch (Exception ex) {
+				if (e.WantReply) sendMessage(CommandCode.Error, e.SID, new PmlString(ex.ToString()));
+			}
+		}
+		private void invokeChannelRequestReceived(Object state) {
+			PmlChannelRequestReceivedEventArgsA e = (PmlChannelRequestReceivedEventArgsA)state;
+			if (ChannelRequestReceived != null) ChannelRequestReceived(this, e);
+			e.RejectIfNotAccepted();
+		}
+
+		private void messageReceived(Object sender, EventArgs e) {
+			IPmlSubChannel subChannel = null;
+			UInt32 sid = 0;
+			bool subChannelExists = false;
+			if (!(e.Message is PmlDictionary)) return;
+			PmlDictionary msg = (PmlDictionary)e.Message;
+			PmlElement cmdElement = msg.GetChild("c");
+			PmlElement sidElement = msg.GetChild("i");
+			PmlElement msgElement = msg.GetChild("m");
+			if (cmdElement == null) return;
+			if (sidElement != null) sid = sidElement.ToUInt32();
+			if (sidElement != null) subChannelExists = _subchannels.TryGetValue(sid, out subChannel);
+			if (!subChannelExists) subChannel = null;
+			switch ((CommandCode)cmdElement.ToInt32()) {
+				case CommandCode.CallWithoutReply:
+					if (CallReceived != null) ThreadPool.RunCall(invokeCallReceived, new PmlCallReceivedEventArgs(msgElement, false, 0));
+					break;
+				case CommandCode.CallWithReply:
+					if (CallReceived != null) ThreadPool.RunCall(invokeCallReceived, new PmlCallReceivedEventArgs(msgElement, true, sid));
+					else sendMessage(CommandCode.Error, sid, null);
+					break;
+				case CommandCode.Message: //Reply to call | subchannel message
+					if (subChannelExists) subChannel.MessageIn(msgElement);
+					else sendMessage(CommandCode.Error, sid, null);
+					break;
+				case CommandCode.ChannelRequest:
+					if (subChannelExists) {
+						sendMessage(CommandCode.Error, sid, null);
+						subChannel.CloseIn();
+					} else {
+						if (ChannelRequestReceived == null) sendMessage(CommandCode.ChannelClose, sid, null);
+						else ThreadPool.RunCall(invokeChannelRequestReceived, new PmlChannelRequestReceivedEventArgsA(this, sid, msgElement));
+					}
+					break;
+				case CommandCode.ChannelAcknowledge:
+					if (subChannelExists) {
+						if (subChannel is PmlSubChannel) (subChannel as PmlSubChannel).AcknowledgeIn();
+						else {
+							sendMessage(CommandCode.Error, sid, null); //Error
+							subChannel.CloseIn();
+						}
+					} else sendMessage(CommandCode.Error, sid, null); //Error
+					break;
+				case CommandCode.ChannelClose:
+					if (subChannelExists) subChannel.CloseIn();
+					break;
+				case CommandCode.Error:
+					if (subChannelExists) subChannel.ErrorIn(msgElement);
+					break;
+			}
+		}
+	}*/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/PmlCommunicator2.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,479 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using UCIS.Pml;
+
+namespace UCIS.Pml {
+	public class PmlCommunicator {
+		private class CSyncRequest {
+			internal PmlElement Reply;
+			internal ManualResetEvent ResetEvent = new ManualResetEvent(false);
+		}
+		private interface ISession {
+			void MessageIn(PmlElement message);
+			void CloseIn();
+			UInt32 ID { get; }
+		}
+		/*public abstract class SessionBase : ISession {
+			private bool pActive;
+			private PmlCommunicator _communicator;
+			private UInt32 _id;
+
+			public uint SID { get { return _id; } }
+			public bool Active { get { return pActive; } }
+			public PmlCommunicator Communicator { get { return _communicator; } }
+
+			protected SessionBase(PmlCommunicator Connection) {
+				_communicator = Connection;
+			}
+
+			protected void Accept(UInt32 sid) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				_id = sid;
+				lock (_communicator._sessions) _communicator._sessions.Add(_id, this);
+				pActive = true;
+			}
+			protected void Request() {
+				Request(null);
+			}
+			protected void Request(PmlElement Message) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				_id = _communicator.GetNextSessionId(true);
+				lock (_communicator._sessions) _communicator._sessions.Add(_id, this);
+				_communicator.WriteSessionMessage(_id, 0, Message);
+				pActive = true;
+			}
+
+			uint ISession.ID { get { return _id; } }
+			void ISession.MessageIn(PmlElement message) { this.MessageIn(message); }
+			void ISession.CloseIn() {
+				pActive = false;
+				_communicator.RemoveSession(this);
+				Closed(null);
+			}
+
+			protected internal abstract void MessageIn(PmlElement Message);
+
+			protected void SendMessage(PmlElement Message) {
+				if (!pActive) throw new InvalidOperationException("Session is not active");
+				_communicator.WriteSessionMessage(_id, 1, Message);
+			}
+
+			public void Close() {
+				if (!pActive) return;
+				pActive = false;
+				_communicator.WriteSessionMessage(_id, 2, null);
+				_communicator.RemoveSession(this);
+			}
+
+			protected virtual void Closed(PmlElement Message) { }
+		}
+		public class Session : SessionBase {
+			public event MessageReceivedEventHandler MessageReceived;
+			public delegate void MessageReceivedEventHandler(PmlElement Message);
+			public event SessionClosedEventHandler SessionClosed;
+			public delegate void SessionClosedEventHandler(PmlElement Message);
+
+			public Session(PmlCommunicator Connection) : base(Connection) { }
+
+			public new void Accept(UInt32 SID) {
+				base.Accept(SID);
+			}
+			public new void Request() {
+				Request(null);
+			}
+			public new void Request(PmlElement Message) {
+				base.Request(Message);
+			}
+
+			protected internal override void MessageIn(PmlElement Message) {
+				if (MessageReceived != null) MessageReceived(Message);
+			}
+
+			public new void SendMessage(PmlElement Message) {
+				base.SendMessage(Message);
+			}
+
+			protected override void Closed(PmlElement Message) {
+				if (SessionClosed != null) SessionClosed(Message);
+			}
+		}*/
+
+		private class PmlSubChannel : ActivePmlChannel, ISession {
+			private enum ChannelState { Requesting, Acknowledged, Closed }
+
+			private PmlCommunicator _communicator;
+			private UInt32 _id;
+			private ChannelState _state;
+
+			internal PmlSubChannel(PmlCommunicator communicator, UInt32 sid, bool accepted) {
+				_communicator = communicator;
+				_id = sid;
+				_state = accepted ? ChannelState.Acknowledged : ChannelState.Requesting;
+				if (accepted) _communicator.AddSession(this);
+			}
+
+			public override bool IsOpen { get { return _state == ChannelState.Acknowledged; } }
+
+			uint ISession.ID { get { return _id; } }
+			void ISession.CloseIn() {
+				_state = ChannelState.Closed;
+				_communicator.RemoveSession(this);
+				base.Close();
+			}
+			void ISession.MessageIn(PmlElement message) {
+				base.PushReceivedMessage(message);
+			}
+
+			public override void WriteMessage(PmlElement message) {
+				if (_state != ChannelState.Acknowledged) throw new InvalidOperationException("The subchannel is not open");
+				_communicator.WriteSessionMessage(_id, 1, message);
+			}
+			public override void Close() {
+				if (_state != ChannelState.Acknowledged) return;
+				_state = ChannelState.Closed;
+				_communicator.WriteSessionMessage(_id, 2, null);
+				_communicator.RemoveSession(this); 
+				base.Close();
+			}
+		}
+		private class PmlChannelRequestReceivedEventArgsA : PmlChannelRequestReceivedEventArgs {
+			private PmlCommunicator _communicator;
+			private PmlElement _data;
+			private bool _accepted, _rejected;
+			private UInt32 _sid;
+			internal PmlChannelRequestReceivedEventArgsA(PmlCommunicator communicator, UInt32 sid, PmlElement message) {
+				_communicator = communicator;
+				_data = message;
+				_sid = sid;
+				_accepted = _rejected = false;
+			}
+			public UInt32 AcceptSession() {
+				if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected");
+				_accepted = true;
+				return _sid;
+			}
+			public override IPmlChannel Accept() {
+				if (_accepted || _rejected) throw new InvalidOperationException("The channel has already been accepted or rejected");
+				_accepted = true;
+				return new PmlSubChannel(_communicator, _sid, true);
+			}
+			public override void Reject() {
+				if (_accepted) throw new InvalidOperationException("The channel has already been accepted");
+				if (_rejected) return;
+				_rejected = true;
+				_communicator.WriteSessionMessage(_sid, 2, null);
+				//_channel.RejectOut();
+			}
+			internal void RejectIfNotAccepted() {
+				if (!_accepted) Reject();
+			}
+			public override PmlElement Data {
+				get {
+					return _data;
+				}
+			}
+		}
+
+		public event EventHandler<PmlCallReceivedEventArgs> CallReceived;
+		public event EventHandler<PmlChannelRequestReceivedEventArgs> ChannelRequestReceived;
+		public event EventHandler Closed;
+
+		private Dictionary<UInt32, ISession> _sessions = new Dictionary<UInt32, ISession>();
+		private Dictionary<UInt32, CSyncRequest> _invocations = new Dictionary<UInt32, CSyncRequest>();
+		private UInt32 pNextSession;
+		private UInt32 pNextSyncRequest;
+
+		private bool _closed;
+		private IPmlChannel _channel;
+
+		public IPmlChannel Channel { get { return _channel; } }
+
+		public PmlCommunicator(IPmlChannel channel, bool autoStart) {
+			_channel = channel;
+			if (autoStart) Start();
+		}
+		public void Start() {
+			_channel.BeginReadMessage(messageReceived, null);
+		}
+		public void StartSync() {
+			while (true) {
+				try {
+					processMessage(_channel.ReadMessage());
+				} catch (InvalidOperationException ex) {
+					Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message);
+					closed();
+					_channel.Close();
+					return;
+				} catch (Exception ex) {
+					Console.WriteLine(ex.ToString());
+					closed();
+					_channel.Close();
+					return;
+				}
+			}
+		}
+		public void Close() {
+			_channel.Close();
+		}
+		public void WriteRawMessage(PmlElement Message) {
+			_WriteMessage(Message);
+		}
+
+		private void _WriteMessage(PmlElement Message) {
+			lock (_channel) {
+				if (!_channel.IsOpen) throw new InvalidOperationException("Could not write message: the channel is not open");
+				_channel.WriteMessage(Message);
+			}
+		}
+		private void closed() {
+			_closed = true;
+			lock (_sessions) {
+				foreach (ISession S in _sessions.Values) {
+					try {
+						S.CloseIn();
+					} catch (Exception ex) {
+						Console.WriteLine(ex.ToString());
+					}
+				}
+				_sessions.Clear();
+			}
+			lock (_invocations) {
+				foreach (CSyncRequest T in _invocations.Values) {
+					T.ResetEvent.Set();
+				}
+				_invocations.Clear();
+			}
+			if (Closed != null) Closed(this, new EventArgs());
+		}
+
+		private void messageReceived(IAsyncResult ar) {
+			try {
+				PmlElement Message = _channel.EndReadMessage(ar);
+				processMessage(Message);
+				_channel.BeginReadMessage(messageReceived, null);
+			} catch (InvalidOperationException ex) {
+				Console.WriteLine("InvalidOperationException in LegacyPmlCommunicator.messageReceived: " + ex.Message);
+				closed();
+				_channel.Close();
+				return;
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+				closed();
+				_channel.Close();
+				return;
+			}
+		}
+		private void processMessage(PmlElement Message) {
+			if (Message is PmlString) {
+				string Cmd = Message.ToString();
+				if (Cmd.Equals("PING")) {
+					_WriteMessage(new PmlString("PONG"));
+				/*} else if (Cmd.Equals("PONG")) {
+					Ping = 0;*/
+				}
+			} else if (Message is PmlDictionary) {
+				string Cmd = Message.GetChild("CMD").ToString();
+				if (Cmd.Equals("SES")) {
+					processSessionMessage(Message);
+				} else if (Cmd.Equals("RPL")) {
+					UInt32 SID = Message.GetChild("SID").ToUInt32();
+					CSyncRequest SRequest = null;
+					lock (_invocations) {
+						if (_invocations.TryGetValue(SID, out SRequest)) {
+							_invocations.Remove(SID);
+						} else {
+							Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString());
+						}
+					}
+					if (SRequest != null) {
+						SRequest.Reply = Message.GetChild("MSG");
+						SRequest.ResetEvent.Set();
+					}
+				} else if (Cmd.Equals("REQ") || Cmd.Equals("MSG")) {
+					UCIS.ThreadPool.RunCall(processCall, Message);
+				} else {
+					Console.WriteLine("UCIS.PML.Connection.Worker Invalid command received");
+				}
+			}
+		}
+		private void processSessionMessage(PmlElement Message) {
+			UInt32 SID = Message.GetChild("SID").ToUInt32();
+			byte SCMD = Message.GetChild("SCMD").ToByte();
+			PmlElement InnerMsg = Message.GetChild("MSG");
+			ISession Session = null;
+			lock (_sessions) if (!_sessions.TryGetValue(SID, out Session)) Session = null;
+			switch (SCMD) {
+				case 0: //Request
+					if (Session != null) {
+						try {
+							Session.CloseIn();
+						} catch (Exception ex) {
+							Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage-Request: exception in session.CloseIn: " + ex.ToString());
+						}
+						WriteSessionMessage(SID, 2, null);
+					} else if (ChannelRequestReceived != null) {
+						try {
+							PmlChannelRequestReceivedEventArgsA ea = new PmlChannelRequestReceivedEventArgsA(this, SID, InnerMsg);
+							ChannelRequestReceived(this, ea);
+							ea.RejectIfNotAccepted();
+						} catch (Exception ex) {
+							Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in ChannelRequestReceived: " + ex.ToString());
+							WriteSessionMessage(SID, 2, null);
+						}
+					} else {
+						WriteSessionMessage(SID, 2, null);
+					}
+					break;
+				case 1: //Message
+					if (Session != null) {
+						try {
+							Session.MessageIn(InnerMsg);
+						} catch (Exception ex) {
+							Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in session.MessageIn: " + ex.ToString());
+							WriteSessionMessage(SID, 2, null);
+						}
+					} else {
+						WriteSessionMessage(SID, 2, null);
+					}
+					break;
+				case 2: //Close
+					if (Session != null) {
+						try {
+							if (InnerMsg != null && !(InnerMsg is PmlNull)) Session.MessageIn(InnerMsg);
+						} catch (Exception ex) {
+							Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage-Close: exception in session.MessageIn: " + ex.ToString());
+						} finally {
+							try {
+								Session.CloseIn();
+							} catch (Exception ex) {
+								Console.WriteLine("UCIS.Pml.PmlCommunicator.processSessionMessage: exception in session.CloseIn: " + ex.ToString());
+							}
+						}
+					}
+					break;
+			}
+		}
+		private void processCall(object state) {
+			PmlDictionary Message = (PmlDictionary)state;
+			bool wantReply = Message.ContainsKey("SID");
+			UInt32 SID = 0;
+			if (wantReply) SID = Message.GetChild("SID").ToUInt32();
+			PmlElement Reply = null;
+			try {
+				if (CallReceived != null) {
+					PmlCallReceivedEventArgs ea = new PmlCallReceivedEventArgs(Message.GetChild("MSG"), wantReply, SID);
+					CallReceived(this, ea);
+					Reply = ea.Reply;
+				}
+			} catch (Exception ex) {
+				Reply = new PmlDictionary();
+				((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString()));
+				Console.WriteLine(ex.ToString());
+			} finally {
+				if (wantReply && Channel.IsOpen) {
+					try {
+						WriteSyncMessage(SID, true, Reply);
+					} catch (Exception ex) {
+						Console.WriteLine("UCIS.Pml.PmlCommunicator.processCall: exception: " + ex.ToString());
+						closed();
+						Channel.Close();
+					}
+				}
+			}
+		}
+
+		public void Call(PmlElement message) {
+			PmlDictionary Msg = new PmlDictionary();
+			Msg.Add("CMD", new PmlString("MSG"));
+			Msg.Add("MSG", message);
+			_WriteMessage(Msg);
+		}
+		public PmlElement Invoke(PmlElement message) {
+			return Invoke(message, 60000);
+		}
+		public PmlElement Invoke(PmlElement message, int timeout) {
+			if (_closed) throw new InvalidOperationException("Sorry, we're closed.");
+			CSyncRequest SyncEvent = new CSyncRequest();
+			UInt32 SID = GetNextSessionId(false);
+			lock (_invocations) _invocations.Add(SID, SyncEvent);
+			try {
+				WriteSyncMessage(SID, false, message);
+				if (!SyncEvent.ResetEvent.WaitOne(timeout, false)) {
+					if (!_closed) lock (_invocations) _invocations.Remove(SID);
+					throw new TimeoutException("The SyncRequest timed out (SID=" + SID.ToString() + ")");
+				}
+			} finally {
+				lock (_invocations) _invocations.Remove(SID);
+			}
+			return SyncEvent.Reply;
+		}
+
+		public IPmlChannel CreateChannel(PmlElement data) {
+			UInt32 sid = GetNextSessionId(true);
+			PmlSubChannel ch = new PmlSubChannel(this, sid, true);
+			WriteSessionMessage(sid, 0, data);
+			if (!ch.IsOpen) return null;
+			return ch;
+		}
+
+		private void AddSession(ISession session) {
+			if (_closed) return;
+			lock (_sessions) _sessions.Add(session.ID, session);
+		}
+		private void RemoveSession(UInt32 session) {
+			if (_closed) return;
+			lock (_sessions) _sessions.Remove(session);
+		}
+		private void RemoveSession(ISession session) {
+			RemoveSession(session.ID);
+		}
+
+		private UInt32 GetNextSessionId(bool IsSession) {
+			if (IsSession) {
+				lock (_sessions) {
+					do {
+						unchecked { pNextSession++; }
+					} while (_sessions.ContainsKey(pNextSession));
+					return pNextSession;
+				}
+			} else {
+				lock (_invocations) {
+					do {
+						unchecked { pNextSyncRequest++; }
+					} while (_invocations.ContainsKey(pNextSyncRequest));
+					return pNextSyncRequest;
+				}
+			}
+		}
+
+		protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			Msg2.Add("CMD", new PmlString(RPL ? "RPL" : "REQ"));
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+		protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			Msg2.Add("CMD", new PmlString("SES"));
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("SCMD", new PmlInteger(CMD));
+			if (MSG != null) Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+
+
+
+		/* LegacyPmlCommunicator compatibility */
+		public PmlElement SyncRequest(PmlElement Request) {
+			return Invoke(Request);
+		}
+		public PmlElement SyncRequest(PmlElement Request, int Timeout) {
+			return Invoke(Request, Timeout);
+		}
+		public void SendMessage(PmlElement Message) {
+			Call(Message);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/PmlConnection.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,384 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using UCIS.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.IO;
+
+namespace UCIS.Pml {
+	/*public class PmlConnection : LegacyPmlCommunicator {
+		public PmlConnection(Socket Socket) : this(new TCPPmlChannel(Socket)) { }
+		public PmlConnection(TCPStream Stream) : this(new TCPPmlChannel(Stream)) { }
+		public PmlConnection(Stream Stream) : this(new PmlBinaryRW(Stream)) {}
+		public PmlConnection(IPmlRW RW) : this(new PmlChannel(RW)) { }
+		public PmlConnection(IPmlChannel CH) : base(CH) { }
+	}*/
+	public class PmlConnection {
+		private class CSyncRequest {
+			internal PmlElement Reply;
+			internal ManualResetEvent ResetEvent = new ManualResetEvent(false);
+		}
+		public abstract class SessionBase {
+			private bool pActive;
+			private PmlConnection pConnection;
+			private UInt32 pSID;
+
+			protected SessionBase(PmlConnection Connection) {
+				pConnection = Connection;
+			}
+
+			protected void Accept(UInt32 SID) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				pSID = SID;
+				lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this);
+				pActive = true;
+			}
+			protected void Request() {
+				Request(null);
+			}
+			protected void Request(PmlElement Message) {
+				if (pActive) throw new InvalidOperationException("Session is active");
+				pSID = pConnection.GetNextSessionId(true);
+				lock (pConnection.pSessions) pConnection.pSessions.Add(pSID, this);
+				pConnection.WriteSessionMessage(pSID, 0, Message);
+				pActive = true;
+			}
+
+			protected internal abstract void MessageIn(PmlElement Message);
+
+			protected void SendMessage(PmlElement Message) {
+				if (!pActive) throw new InvalidOperationException("Session is not active");
+				pConnection.WriteSessionMessage(pSID, 1, Message);
+			}
+
+			public void Close() {
+				Close(null);
+			}
+			public void Close(PmlElement Message) {
+				if (!pActive) throw new InvalidOperationException("Session is not active");
+				pConnection.WriteSessionMessage(pSID, 2, Message);
+				ClosedA();
+			}
+
+			internal void ClosedA() {
+				pActive = false;
+				lock (pConnection.pSessions) pConnection.pSessions.Remove(pSID);
+			}
+
+			internal void ClosedB(PmlElement Message) {
+				pActive = false;
+				Closed(Message);
+			}
+
+			protected virtual void Closed(PmlElement Message) {
+			}
+		}
+		public class Session : SessionBase {
+			public event MessageReceivedEventHandler MessageReceived;
+			public delegate void MessageReceivedEventHandler(PmlElement Message);
+			public event SessionClosedEventHandler SessionClosed;
+			public delegate void SessionClosedEventHandler(PmlElement Message);
+
+			public Session(PmlConnection Connection) : base(Connection) { }
+
+			public new void Accept(UInt32 SID) {
+				base.Accept(SID);
+			}
+			public new void Request() {
+				Request(null);
+			}
+			public new void Request(PmlElement Message) {
+				base.Request(Message);
+			}
+
+			protected internal override void MessageIn(PmlElement Message) {
+				if (MessageReceived != null) MessageReceived(Message);
+			}
+
+			public new void SendMessage(PmlElement Message) {
+				base.SendMessage(Message);
+			}
+
+			protected override void Closed(PmlElement Message) {
+				if (SessionClosed != null) SessionClosed(Message);
+			}
+		}
+
+		private Dictionary<UInt32, SessionBase> pSessions = new Dictionary<UInt32, SessionBase>();
+		private UInt32 pNextSession;
+		private Dictionary<UInt32, CSyncRequest> pSyncRequests = new Dictionary<UInt32, CSyncRequest>();
+		private UInt32 pNextSyncRequest;
+
+		private Stream pStream;
+
+		public event MessageReceivedEventHandler MessageReceived;
+		public delegate void MessageReceivedEventHandler(PmlElement Message);
+		public event RequestReceivedEventHandler RequestReceived;
+		public delegate void RequestReceivedEventHandler(PmlElement Request, ref PmlElement Reply);
+		public event SessionRequestReceivedEventHandler SessionRequestReceived;
+		public delegate void SessionRequestReceivedEventHandler(PmlElement Request, uint SID);
+
+		private IPmlWriter _writer;
+		private IPmlReader _reader;
+
+		public PmlConnection(Socket Socket) : this(new TCPStream(Socket)) { }
+		public PmlConnection(Stream Stream) : this(new PmlBinaryRW(Stream)) {
+			pStream = Stream;
+		}
+		public PmlConnection(IPmlRW RMRW) : this(RMRW, RMRW) { }
+		public PmlConnection(IPmlReader Reader, IPmlWriter Writer) {
+			_reader = Reader;
+			_writer = Writer;
+		}
+
+		public void Close() {
+			if (pStream != null) pStream.Close();
+		}
+
+		public IPmlReader Reader {
+			get { return _reader; }
+		}
+		public IPmlWriter Writer {
+			get { return _writer; }
+		}
+		private PmlElement _ReadMessage() {
+			PmlElement Message = _reader.ReadMessage();
+			return Message;  //Warning: Can't lock reader because it can be the same as the Writer (possible deadlock)
+		}
+		private void _WriteMessage(PmlElement Message) {
+			lock (_writer) _writer.WriteMessage(Message);
+		}
+
+		private UInt32 GetNextSessionId(bool IsSession) {
+			if (IsSession) {
+				lock (pSessions) {
+					do {
+						if (pNextSession == UInt32.MaxValue) {
+							pNextSession = 0;
+						} else {
+							pNextSession += (uint)1;
+						}
+					}
+					while (pSessions.ContainsKey(pNextSession));
+					return pNextSession;
+				}
+			} else {
+				lock (pSyncRequests) {
+					do {
+						if (pNextSyncRequest == UInt32.MaxValue) {
+							pNextSyncRequest = 0;
+						} else {
+							pNextSyncRequest += (uint)1;
+						}
+					}
+					while (pSyncRequests.ContainsKey(pNextSyncRequest));
+					return pNextSyncRequest;
+				}
+			}
+		}
+
+		protected void WriteSessionMessage(UInt32 SID, byte CMD, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			Msg2.Add("CMD", new PmlString("SES"));
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("SCMD", new PmlInteger(CMD));
+			Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+
+		protected void WriteSyncMessage(UInt32 SID, bool RPL, PmlElement MSG) {
+			PmlDictionary Msg2 = new PmlDictionary();
+			if (RPL) {
+				Msg2.Add("CMD", new PmlString("RPL"));
+			} else {
+				Msg2.Add("CMD", new PmlString("REQ"));
+			}
+			Msg2.Add("SID", new PmlInteger(SID));
+			Msg2.Add("MSG", MSG);
+			_WriteMessage(Msg2);
+		}
+
+		public void Worker() {
+			try {
+				PmlElement Message = null;
+				int Ping = 0;
+				while (true) {
+					try {
+						Message = _ReadMessage();
+						if (Message == null) Console.WriteLine("UCIS.PML.Connection: Message is just null?");
+					} catch (EndOfStreamException) {
+						Console.WriteLine("UCIS.PML.Connection: End of stream");
+						return;
+					} catch (SocketException ex) {
+						if (ex.ErrorCode == (int)SocketError.TimedOut) {
+							Console.WriteLine("UCIS.PML.Connection: SocketException/TimedOut");
+							Message = null;
+						} else if (ex.ErrorCode == (int)SocketError.ConnectionReset) {
+							Console.WriteLine("UCIS.PML.Connection: Connection reset by peer");
+							return;
+						} else {
+							throw new Exception("Exception while reading message", ex);
+						}
+					} catch (IOException ex) {
+						Console.WriteLine("UCIS.PML.Connection: IOException: " + ex.Message);
+						Message = null;
+					} catch (TimeoutException) {
+						Message = null;
+					}
+					if (Message == null) {
+						if (Ping > 2) {
+							Console.WriteLine("UCIS.PML.Connection: Connection timed out");
+							break;
+						} else {
+							_WriteMessage(new PmlString("PING"));
+						}
+						Ping += 1;
+					} else if (Message is PmlString) {
+						string Cmd = Message.ToString();
+						if (Cmd.Equals("PING")) {
+							_WriteMessage(new PmlString("PONG"));
+						} else if (Cmd.Equals("PONG")) {
+							Ping = 0;
+						}
+					} else if (Message is PmlDictionary) {
+						string Cmd = null;
+						Cmd = Message.GetChild("CMD").ToString();
+						if (Cmd.Equals("SES")) {
+							UInt32 SID = default(UInt32);
+							byte SCMD = 0;
+							SessionBase Session = default(SessionBase);
+							PmlElement InnerMsg = default(PmlElement);
+							SID = Message.GetChild("SID").ToUInt32();
+							SCMD = Message.GetChild("SCMD").ToByte();
+							InnerMsg = Message.GetChild("MSG");
+							lock (pSessions) {
+								if (pSessions.ContainsKey(SID)) {
+									Session = pSessions[SID];
+								} else {
+									Session = null;
+								}
+							}
+							if (SCMD == 0) {
+								if (Session == null) {
+									if (SessionRequestReceived != null) {
+										SessionRequestReceived(InnerMsg, SID);
+									}
+								} else {
+									Session.ClosedA();
+									Session.ClosedB(null);
+									WriteSessionMessage(SID, 2, null);
+								}
+							} else if (SCMD == 1) {
+								if (Session == null) {
+									WriteSessionMessage(SID, 2, null);
+								} else {
+									Session.MessageIn(InnerMsg);
+								}
+							} else if (SCMD == 2) {
+								if (Session != null) {
+									Session.ClosedA();
+									Session.ClosedB(InnerMsg);
+								}
+							}
+						} else if (Cmd.Equals("RPL")) {
+							UInt32 SID = default(UInt32);
+							CSyncRequest SRequest = null;
+							SID = Message.GetChild("SID").ToUInt32();
+							lock (pSyncRequests) {
+								if (pSyncRequests.TryGetValue(SID, out SRequest)) {
+									pSyncRequests.Remove(SID);
+								} else {
+									Console.WriteLine("UCIS.PML.Connection.Worker Invalid request ID in reply: " + SID.ToString());
+								}
+							}
+							if (SRequest != null) {
+								SRequest.Reply = Message.GetChild("MSG");
+								SRequest.ResetEvent.Set();
+							}
+						} else if (Cmd.Equals("REQ")) {
+							System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(SyncRequestHandler), Message);
+						} else if (Cmd.Equals("MSG")) {
+							PmlElement InnerMsg = Message.GetChild("MSG");
+							if (MessageReceived != null) MessageReceived(InnerMsg);
+						} else {
+							throw new InvalidOperationException("Invalid operation");
+						}
+					}
+				}
+			} catch (System.Threading.ThreadAbortException ex) {
+				throw ex;
+			} catch (Exception ex) {
+				Console.WriteLine(ex.ToString());
+			} finally {
+				Console.WriteLine("UCIS.PML.Connection: Connection closed");
+				try {
+					foreach (SessionBase S in pSessions.Values) {
+						try {
+							S.ClosedB(null);
+						} catch (Exception ex) {
+							Console.WriteLine(ex.ToString());
+						}
+					}
+					pSessions.Clear();
+					foreach (CSyncRequest T in pSyncRequests.Values) {
+						T.ResetEvent.Set();
+					}
+				} catch (Exception ex) {
+					Console.WriteLine(ex.ToString());
+				}
+			}
+		}
+
+		private void SyncRequestHandler(object state) {
+			PmlDictionary Message = (PmlDictionary)state;
+			UInt32 SID = default(UInt32);
+			PmlElement InnerMsg = default(PmlElement);
+			PmlElement Reply = default(PmlElement);
+			Reply = null;
+			SID = Message.GetChild("SID").ToUInt32();
+			InnerMsg = Message.GetChild("MSG");
+			try {
+				if (RequestReceived != null) {
+					RequestReceived(InnerMsg, ref Reply);
+				}
+			} catch (Exception ex) {
+				Reply = new PmlDictionary();
+				((PmlDictionary)Reply).Add("EXCEPTION", new PmlString(ex.ToString()));
+				Console.WriteLine(ex.ToString());
+			}
+			WriteSyncMessage(SID, true, Reply);
+		}
+
+		public PmlElement SyncRequest(PmlElement Request) {
+			return SyncRequest(Request, 30000);
+		}
+		public PmlElement SyncRequest(PmlElement Request, int Timeout) {
+			UInt32 SID = default(UInt32);
+			CSyncRequest SyncEvent = new CSyncRequest();
+			SID = GetNextSessionId(false);
+			lock (pSyncRequests) pSyncRequests.Add(SID, SyncEvent);
+			WriteSyncMessage(SID, false, Request);
+			if (!SyncEvent.ResetEvent.WaitOne(Timeout, false)) {
+				Console.WriteLine("UCIS.PML.Connection.SyncRequest Timeout: " + SID.ToString());
+				lock (pSyncRequests) pSyncRequests.Remove(SID);
+				throw new TimeoutException();
+			}
+			return SyncEvent.Reply;
+		}
+
+		public void SendMessage(PmlElement Message) {
+			PmlDictionary Msg = new PmlDictionary();
+			Msg.Add("CMD", new PmlString("MSG"));
+			Msg.Add("MSG", Message);
+			_WriteMessage(Msg);
+		}
+
+		public PmlElement ReadMessage() {
+			return _ReadMessage();
+		}
+		public void SendRawMessage(PmlElement Message) {
+			_WriteMessage(Message);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/IPmlRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,10 @@
+namespace UCIS.Pml {
+	public interface IPmlReader {
+		PmlElement ReadMessage();
+	}
+	public interface IPmlWriter {
+		void WriteMessage(PmlElement Message);
+	}
+	public interface IPmlRW : IPmlReader, IPmlWriter {
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/PmlAmfRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,282 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+using UCIS.Pml;
+
+namespace UCIS.Pml {
+	internal enum AmfDataType : byte {
+		Number = 0,
+		Boolean = 1,
+		String = 2,
+		UntypedObject = 3,
+		MovieClip = 4,
+		Null = 5,
+		Undefined = 6,
+		ReferencedObject = 7,
+		MixedArray = 8,
+		End = 9,
+		Array = 10,
+		Date = 11,
+		LongString = 12,
+		TypeAsObject = 13,
+		Recordset = 14,
+		Xml = 15,
+		TypedObject = 16
+	}
+	public class PmlAmfWriter : IPmlWriter {
+		private BinaryWriter pWriter;
+
+		public PmlAmfWriter(BinaryWriter Writer) {
+			pWriter = Writer;
+		}
+		public PmlAmfWriter(Stream Stream) {
+			pWriter = new BinaryWriter(Stream, Encoding.UTF8);
+		}
+
+		public BinaryWriter BaseWriter {
+			get { return pWriter; }
+			set { pWriter = value; }
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			WriteMessageTo(Message, pWriter);
+		}
+
+		public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) {
+			lock (Writer) {
+				WriteElementTo(Message, Writer);
+				Writer.Flush();
+			}
+		}
+
+		private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) {
+			if (Element == null) {
+				Writer.Write((byte)AmfDataType.Null);
+				return;
+			}
+			switch (Element.Type) {
+				case PmlType.Null:
+					Writer.Write((byte)AmfDataType.Null);
+					break;
+				case PmlType.Dictionary:
+					Writer.Write((byte)AmfDataType.UntypedObject);
+					//WriteDictionary(Writer, (PmlDictionary)Element);
+					WriteUntypedObject(Writer, (PmlDictionary)Element);
+					break;
+				case PmlType.Collection:
+					Writer.Write((byte)AmfDataType.Array);
+					WriteCollection(Writer, (PmlCollection)Element);
+					break;
+				case PmlType.Binary:
+					Writer.Write((byte)AmfDataType.String);
+					byte[] bytes = Element.ToByteArray();
+					if (bytes.Length > UInt16.MaxValue) {
+						Writer.Write((byte)AmfDataType.String);
+						WriteString(Writer, bytes);
+					} else {
+						Writer.Write((byte)AmfDataType.LongString);
+						WriteLongString(Writer, bytes);
+					}
+					break;
+				case PmlType.String:
+					string str = Element.ToString();
+					if (str.Length < UInt16.MaxValue) {
+						Writer.Write((byte)AmfDataType.String);
+						WriteString(Writer, str);
+					} else {
+						Writer.Write((byte)AmfDataType.LongString);
+						WriteLongString(Writer, str);
+					}
+					break;
+				case PmlType.Integer:
+					Writer.Write((byte)AmfDataType.Number);
+					WriteDouble(Writer, (Element as PmlInteger).ToDouble());
+					break;
+			}
+		}
+		private static void WriteEnd(BinaryWriter w) {
+			WriteUInt16(w, 0);
+			w.Write((byte)AmfDataType.End);
+		}
+		private static void WriteUntypedObject(BinaryWriter w, PmlDictionary value) {
+			foreach (KeyValuePair<String, PmlElement> kvp in value) {
+				WriteString(w, kvp.Key);
+				WriteElementTo(kvp.Value, w);
+			}
+			WriteEnd(w);
+		}
+		private static void WriteDictionary(BinaryWriter w, PmlDictionary value) {
+			WriteUInt32(w, (UInt32)value.Count);
+			foreach (KeyValuePair<String, PmlElement> kvp in value) {
+				WriteString(w, kvp.Key);
+				WriteElementTo(kvp.Value, w);
+			}
+		}
+		private static void WriteCollection(BinaryWriter w, PmlCollection value) {
+			WriteUInt32(w,(UInt32)value.Count);
+			foreach (PmlElement o in value) {
+				WriteElementTo(o, w);
+			}
+		}
+		private static void WriteDouble(BinaryWriter w, double value) {
+			WriteReverse(w, BitConverter.GetBytes(value));
+		}
+		private static void WriteUInt32(BinaryWriter w, UInt32 value) {
+			WriteReverse(w, BitConverter.GetBytes(value));
+		}
+		private static void WriteUInt16(BinaryWriter w, UInt16 value) {
+			WriteReverse(w, BitConverter.GetBytes(value));
+		}
+		private static void WriteString(BinaryWriter w, string value) {
+			WriteString(w, Encoding.UTF8.GetBytes(value));
+		}
+		private static void WriteLongString(BinaryWriter w, string value) {
+			WriteLongString(w, Encoding.UTF8.GetBytes(value));
+		}
+		private static void WriteString(BinaryWriter w, byte[] buffer) {
+			WriteUInt16(w, (UInt16)buffer.Length);
+			w.Write(buffer, 0, buffer.Length);
+		}
+		private static void WriteLongString(BinaryWriter w, byte[] buffer) {
+			WriteUInt32(w, (UInt32)buffer.Length);
+			w.Write(buffer, 0, buffer.Length);
+		}
+		private static void WriteReverse(BinaryWriter w, byte[] value) {
+			Array.Reverse(value);
+			w.Write(value);
+		}
+	}
+
+	public class PmlAmfReader : IPmlReader {
+		private BinaryReader pReader;
+
+		public PmlAmfReader(BinaryReader Reader) {
+			pReader = Reader;
+		}
+		public PmlAmfReader(Stream Stream) {
+			pReader = new BinaryReader(Stream, Encoding.UTF8);
+		}
+
+		public BinaryReader BaseReader {
+			get { return pReader; }
+			set { pReader = value; }
+		}
+
+		public PmlElement ReadMessage() {
+			return ReadMessageFrom(pReader);
+		}
+
+		public static PmlElement ReadMessageFrom(BinaryReader Reader) {
+			PmlElement Element = null;
+			lock (Reader) {
+				Element = ReadElementFrom(Reader);
+			}
+			return Element;
+		}
+
+
+		private static PmlElement ReadElementFrom(BinaryReader Reader) {
+			AmfDataType EType = (AmfDataType)Reader.ReadByte();
+			return ReadData(Reader, EType);
+		}
+		private static PmlElement ReadData(BinaryReader Reader, AmfDataType EType) {
+			switch (EType) {
+				case AmfDataType.Number:
+					Double d = ReadDouble(Reader);
+					if (d == (double)(Int64)d) {
+						return new PmlInteger((Int64)d);
+					} else if (d == (double)(UInt64)d) {
+						return new PmlInteger((UInt64)d);
+					} else {
+						return new PmlString(d.ToString());
+					}
+				case AmfDataType.Boolean:
+					return new PmlInteger(Reader.ReadByte());
+				case AmfDataType.String:
+					return new PmlString(ReadShortString(Reader));
+				case AmfDataType.Array:
+					PmlCollection ElementC = new PmlCollection();
+					int size = ReadInt32(Reader);
+					for (int i = 0; i < size; ++i) {
+						ElementC.Add(ReadElementFrom(Reader));
+					}
+					return ElementC;
+				case AmfDataType.Date:
+					return new PmlString(ReadDate(Reader).ToString());
+				case AmfDataType.LongString:
+					return new PmlString(ReadLongString(Reader));
+				case AmfDataType.TypedObject:
+					ReadShortString(Reader);
+					return ReadUntypedObject(Reader);
+				case AmfDataType.MixedArray:
+					return ReadDictionary(Reader);
+				case AmfDataType.Null:
+				case AmfDataType.Undefined:
+				case AmfDataType.End:
+					return new PmlNull();
+				case AmfDataType.UntypedObject:
+					return ReadUntypedObject(Reader);
+				case AmfDataType.Xml:
+					return new PmlString(ReadLongString(Reader));
+				case AmfDataType.MovieClip:
+				case AmfDataType.ReferencedObject:
+				case AmfDataType.TypeAsObject:
+				case AmfDataType.Recordset:
+				default:
+					throw new NotSupportedException("The AMF type is not supported: " + EType.ToString());
+			}
+		}
+
+		private static PmlDictionary ReadUntypedObject(BinaryReader Reader) {
+			PmlDictionary ElementD = new PmlDictionary();
+			string key = ReadShortString(Reader);
+			for (byte type = Reader.ReadByte(); type != 9; type = Reader.ReadByte()) {
+				ElementD.Add(key, ReadData(Reader, (AmfDataType)type));
+				key = ReadShortString(Reader);
+			}
+			return ElementD;
+		}
+		private static PmlDictionary ReadDictionary(BinaryReader Reader) {
+			PmlDictionary ElementD = new PmlDictionary();
+			int size = ReadInt32(Reader);
+			return ReadUntypedObject(Reader);
+		}
+
+		private static DateTime ReadDate(BinaryReader r) {
+			double ms = ReadDouble(r);
+			DateTime date = (new DateTime(1970, 1, 1)).AddMilliseconds(ms);
+			ReadUInt16(r); //gets the timezone
+			return date;
+		}
+		private static double ReadDouble(BinaryReader r) {
+			return BitConverter.ToDouble(ReadReverse(r, 8), 0);
+		}
+
+		private static int ReadInt32(BinaryReader r) {
+			return BitConverter.ToInt32(ReadReverse(r, 4), 0);
+		}
+
+		private static ushort ReadUInt16(BinaryReader r) {
+			return BitConverter.ToUInt16(ReadReverse(r, 2), 0);
+		}
+
+		private static byte[] ReadReverse(BinaryReader r, int size) {
+			byte[] buffer = r.ReadBytes(size);
+			Array.Reverse(buffer);
+			return buffer;
+		}
+		private static string ReadLongString(BinaryReader r) {
+			int length = ReadInt32(r);
+			return ReadString(r, length);
+		}
+		private static string ReadShortString(BinaryReader r) {
+			int length = ReadUInt16(r);
+			return ReadString(r, length);
+		}
+		private static string ReadString(BinaryReader r, int length) {
+			byte[] buffer = r.ReadBytes(length);
+			return Encoding.UTF8.GetString(buffer);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/PmlBinaryRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,223 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
+
+namespace UCIS.Pml {
+	public class PmlBinaryRW : IPmlRW {
+		private PmlBinaryReader pReader;
+		private PmlBinaryWriter pWriter;
+
+		public PmlBinaryRW(Stream Stream) {
+			pReader = new PmlBinaryReader(Stream);
+			pWriter = new PmlBinaryWriter(Stream);
+		}
+		public PmlBinaryRW(Stream Stream, Encoding Encoding) {
+			pReader = new PmlBinaryReader(Stream, Encoding);
+			pWriter = new PmlBinaryWriter(Stream, Encoding);
+		}
+
+		public PmlElement ReadMessage() {
+			return pReader.ReadMessage();
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			pWriter.WriteMessage(Message);
+		}
+
+		public PmlBinaryReader Reader {
+			get { return pReader; }
+		}
+		public PmlBinaryWriter Writer {
+			get { return pWriter; }
+		}
+	}
+
+	public class PmlBinaryWriter : IPmlWriter {
+		//private BinaryWriter pWriter;
+		private Stream pStream;
+		private Encoding pEncoding;
+
+		/*public PmlBinaryWriter(BinaryWriter Writer) {
+			pWriter = Writer;
+		}*/
+		public PmlBinaryWriter(Stream Stream) {
+			//pWriter = new BinaryWriter(Stream);
+			pStream = Stream;
+			pEncoding = Encoding.UTF8;
+		}
+		public PmlBinaryWriter(Stream Stream, Encoding Encoding) {
+			//pWriter = new BinaryWriter(Stream, Encoding);
+			pStream = Stream;
+			pEncoding = Encoding;
+		}
+
+		/*public BinaryWriter BaseWriter {
+			get { return pWriter; }
+			set { pWriter = value; }
+		}*/
+
+		public void WriteMessage(PmlElement Message) {
+			MemoryStream stream = new MemoryStream();
+			BinaryWriter writer = new BinaryWriter(stream, pEncoding);
+			WriteMessageTo(Message, writer);
+			lock (pStream) {
+				stream.WriteTo(pStream);
+				pStream.Flush();
+			}
+		}
+
+		public static void WriteMessageTo(PmlElement Message, BinaryWriter Writer) {
+			lock (Writer) {
+				Writer.Write((byte)255);
+				WriteElementTo(Message, Writer);
+				Writer.Write((byte)255);
+				Writer.Flush();
+			}
+		}
+
+		private static void WriteElementTo(PmlElement Element, BinaryWriter Writer) {
+			//byte[] Buffer = null;
+			if (Element == null) {
+				//Writer.Write((byte)PmlElementType.Null);
+				Writer.Write((byte)0);
+				return;
+			}
+			//Writer.Write((byte)Element.Type);
+			switch (Element.Type) {
+				case PmlType.Null:
+					Writer.Write((byte)0);
+					break;
+				case PmlType.Dictionary:
+					Writer.Write((byte)1);
+					foreach (KeyValuePair<string, PmlElement> Item in (PmlDictionary)Element) {
+						Writer.Write((byte)1);
+						Writer.Write(Item.Key);
+						WriteElementTo(Item.Value, Writer);
+					}
+					Writer.Write((byte)0);
+					break;
+				case PmlType.Collection:
+					Writer.Write((byte)2);
+					foreach (PmlElement Item in (PmlCollection)Element) {
+						Writer.Write((byte)1);
+						WriteElementTo(Item, Writer);
+					}
+					Writer.Write((byte)0);
+					break;
+				case PmlType.Binary: {
+						Writer.Write((byte)10);
+						Byte[] Buffer = Element.ToByteArray();
+						if (Buffer == null) {
+							Writer.Write((int)0);
+						} else {
+							Writer.Write((int)Buffer.Length);
+							Writer.Write(Buffer);
+						}
+					} break;
+				case PmlType.String:
+					Writer.Write((byte)11);
+					string Str = Element.ToString();
+					if (Str == null) {
+						Writer.Write("");
+					} else {
+						Writer.Write(Str);
+					}
+
+					break;
+				case PmlType.Integer:
+					Writer.Write((byte)20);
+					PmlInteger RMInt = (PmlInteger)Element;
+					if (RMInt.IsSigned) {
+						Writer.Write((byte)1);
+						Writer.Write((long)RMInt);
+					} else {
+						Writer.Write((byte)0);
+						Writer.Write((ulong)RMInt);
+					}
+					break;
+				default:
+					Writer.Write((byte)0);
+					Console.WriteLine("PmlBinaryRW: Can not encode PML type {0}", Element.Type);
+					break;
+			}
+		}
+	}
+
+	public class PmlBinaryReader : IPmlReader {
+		private BinaryReader pReader;
+
+		public PmlBinaryReader(BinaryReader Reader) {
+			pReader = Reader;
+		}
+		public PmlBinaryReader(Stream Stream) {
+			pReader = new BinaryReader(Stream);
+		}
+		public PmlBinaryReader(Stream Stream, Encoding Encoding) {
+			pReader = new BinaryReader(Stream, Encoding);
+		}
+
+		public BinaryReader BaseReader {
+			get { return pReader; }
+			set { pReader = value; }
+		}
+
+		public PmlElement ReadMessage() {
+			return ReadMessageFrom(pReader);
+		}
+
+		public static PmlElement ReadMessageFrom(BinaryReader Reader) {
+			PmlElement Element = null;
+			lock (Reader) {
+				if (Reader.ReadByte() != 255) {
+					return null;
+				}
+				Element = ReadElementFrom(Reader);
+				if (Reader.ReadByte() != 255) {
+					return null;
+				}
+			}
+			return Element;
+		}
+
+		private static PmlElement ReadElementFrom(BinaryReader Reader) {
+			Byte EType = Reader.ReadByte();
+			switch (EType) {
+				case 0: return new PmlNull();
+				case 1:
+					PmlDictionary ElementD = new PmlDictionary();
+					do {
+						byte B = Reader.ReadByte();
+						if (B == 0) return ElementD;
+						else if (B == 1) ElementD.Add(Reader.ReadString(), ReadElementFrom(Reader));
+						else return null;
+					}
+					while (true);
+				case 2:
+					PmlCollection ElementC = new PmlCollection();
+					do {
+						byte B = Reader.ReadByte();
+						if (B == 0) return ElementC;
+						else if (B == 1) ElementC.Add(ReadElementFrom(Reader));
+						else return null;
+					}
+					while (true);
+				case 10:
+					int Len = 0;
+					Len = Reader.ReadInt32();
+					return new PmlBinary(Reader.ReadBytes(Len));
+				case 11:
+					return new PmlString(Reader.ReadString());
+				case 20: {
+						byte B = Reader.ReadByte();
+						if (B == 0) return new PmlInteger(Reader.ReadUInt64());
+						else if (B == 1) return new PmlInteger(Reader.ReadInt64());
+						else return null;
+
+					}
+				default:
+					throw new Exception("Unknown PML type code " + EType.ToString());
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/PmlPHPRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,238 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace UCIS.Pml {
+	public class PmlPHPWriter : IPmlWriter {
+		private TextWriter pWriter;
+
+		public static string GetMessageString(PmlElement Message) {
+			StringWriter Buffer = new StringWriter();
+			WriteMessageTo(Message, Buffer);
+			return Buffer.ToString();
+		}
+
+		public PmlPHPWriter(TextWriter Writer) {
+			pWriter = Writer;
+		}
+		public PmlPHPWriter(Stream Writer, Encoding Encoding) {
+			pWriter = new StreamWriter(Writer, Encoding);
+		}
+		public PmlPHPWriter(StringBuilder StringBuilder) {
+			pWriter = new StringWriter(StringBuilder);
+		}
+
+		public TextWriter BaseWriter {
+			get { return pWriter; }
+			set { pWriter = value; }
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			WriteMessageTo(Message, pWriter);
+		}
+
+		public static void WriteMessageTo(PmlElement Message, TextWriter Writer) {
+			lock (Writer) {
+				WriteElementTo(Message, Writer);
+				Writer.Flush();
+			}
+		}
+
+		private static void WriteElementTo(PmlElement Element, TextWriter Writer) {
+			string Str;
+			if (Element == null) {
+				Writer.Write("N;");
+				return;
+			}
+			switch (Element.Type) {
+				case PmlType.Null:
+					Writer.Write("N;");
+					break;
+				case PmlType.String:
+				case PmlType.Binary:
+					Str = Element.ToString();
+					Writer.Write("s:");
+					Writer.Write(Encoding.UTF8.GetByteCount(Str).ToString());
+					Writer.Write(":\"");
+					Writer.Write(Str);
+					Writer.Write("\";");
+					break;
+				case PmlType.Integer:
+					Writer.Write("i:");
+					Writer.Write(Element.ToString());
+					Writer.Write(";");
+					break;
+				case PmlType.Dictionary:
+					Writer.Write("a:");
+					Writer.Write(((IDictionary<string, PmlElement>)Element).Count.ToString());
+					Writer.Write(":{");
+					foreach (KeyValuePair<string, PmlElement> Child in (IDictionary<string, PmlElement>)Element) {
+						Str = Child.Key;
+						Writer.Write("s:");
+						Writer.Write(Encoding.UTF8.GetByteCount(Str).ToString());
+						Writer.Write(":\"");
+						Writer.Write(Str);
+						Writer.Write("\";");
+						WriteElementTo(Child.Value, Writer);
+					}
+
+					Writer.Write("}");
+					break;
+				case PmlType.Collection:
+					int I = 0;
+					Writer.Write("a:");
+					Writer.Write(((ICollection<PmlElement>)Element).Count.ToString());
+					Writer.Write(":{");
+					foreach (PmlElement Child in (ICollection<PmlElement>)Element) {
+						Writer.Write("i:");
+						Writer.Write(I.ToString());
+						Writer.Write(";");
+						WriteElementTo(Child, Writer);
+						I += 1;
+					}
+
+					Writer.Write("}");
+					break;
+				default:
+					Writer.Write("N;");
+					break;
+			}
+		}
+	}
+	public class PmlPHPReader : IPmlReader {
+		private TextReader pReader;
+
+		public static PmlElement GetMessageFromString(string Data) {
+			StringReader Buffer = new StringReader(Data);
+			return ReadMessageFrom(Buffer);
+		}
+
+		public PmlPHPReader(TextReader Reader) {
+			pReader = Reader;
+		}
+		public PmlPHPReader(Stream Reader, Encoding Encoding) {
+			pReader = new StreamReader(Reader, Encoding);
+		}
+		public PmlPHPReader(string Data) {
+			pReader = new StringReader(Data);
+		}
+
+		public TextReader BaseReader {
+			get { return pReader; }
+			set { pReader = value; }
+		}
+
+		public PmlElement ReadMessage() {
+			return ReadMessageFrom(pReader);
+		}
+
+		public static PmlElement ReadMessageFrom(TextReader Reader) {
+			lock (Reader) {
+				return ReadElementFrom(Reader);
+			}
+		}
+
+		public class PhpSerializerException : Exception {
+
+			public PhpSerializerException(int Position, char Read, char Expected)
+				: base("At position " + Position.ToString() + " expected " + Expected + " but got " + Read) {
+			}
+		}
+
+		private static char ReadChar(TextReader Reader) {
+			char[] Buffer = new char[1];
+			if (Reader.Read(Buffer, 0, 1) != 1) throw new EndOfStreamException();
+			return Buffer[0];
+		}
+
+		private static string ReadNumber(TextReader Reader, char TerminatedBy) {
+			char Buffer = '\0';
+			string S = "";
+			do {
+				Buffer = ReadChar(Reader);
+				if (Buffer == TerminatedBy) break;
+				if (Buffer < '0' && Buffer > '9' && Buffer != '.' && Buffer != ',' && Buffer != '-' && Buffer != 'e')
+					throw new PhpSerializerException(0, Buffer, TerminatedBy);
+				S += Buffer;
+			}
+			while (true);
+			return S;
+		}
+
+		private static void ReadExpect(TextReader Reader, char Expect) {
+			char Read = '\0';
+			Read = ReadChar(Reader);
+			if (Read != Expect) throw new PhpSerializerException(0, Read, Expect);
+		}
+
+		private static PmlElement ReadElementFrom(TextReader Reader) {
+			char Type = '\0';
+			char Read = '\0';
+			int KL;
+			Type = ReadChar(Reader);
+			switch (Type) {
+				case 'N':
+					ReadExpect(Reader, ';');
+					return new PmlNull();
+				case 'i':
+					ReadExpect(Reader, ':');
+					return new PmlInteger(ReadNumber(Reader, ';'));
+				case 'd':
+					ReadExpect(Reader, ':');
+					return new PmlString(ReadNumber(Reader, ';'));
+				//Return New PML.PMLNumber(ReadNumber(Reader, ";"c))
+				case 's':
+					KL = 0;
+					char[] Buffer = null;
+					ReadExpect(Reader, ':');
+					KL = int.Parse(ReadNumber(Reader, ':'));
+					Buffer = new Char[KL];
+					ReadExpect(Reader, '"');
+					Reader.ReadBlock(Buffer, 0, KL);
+					ReadExpect(Reader, '"');
+					ReadExpect(Reader, ';');
+					return new PmlString(new String(Buffer));
+				case 'a':
+					PmlDictionary D = new PmlDictionary();
+					int I = 0;
+					int L = 0;
+					KL = 0;
+					char[] K = null;
+					ReadExpect(Reader, ':');
+					L = int.Parse(ReadNumber(Reader, ':'));
+					ReadExpect(Reader, '{');
+					for (I = 1; I <= L; I++) {
+						Read = ReadChar(Reader);
+						switch (Read) {
+							case 'i':
+								ReadExpect(Reader, ':');
+								K = ReadNumber(Reader, ';').ToCharArray();
+								break;
+							case 's':
+								ReadExpect(Reader, ':');
+								KL = int.Parse(ReadNumber(Reader, ':'));
+								K = new char[KL];
+								ReadExpect(Reader, '"');
+								Reader.ReadBlock(K, 0, KL);
+								ReadExpect(Reader, '"');
+								ReadExpect(Reader, ';');
+								break;
+							case 'd':
+								ReadExpect(Reader, ':');
+								K = ReadNumber(Reader, ';').ToCharArray();
+								break;
+							default:
+								throw new NotSupportedException("Only integer and string keys are supported, got: " + Read);
+						}
+						D.Add(new String(K), ReadElementFrom(Reader));
+					}
+
+					ReadExpect(Reader, '}');
+					return D;
+				default:
+					throw new NotSupportedException("Unknown type: " + Type);
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/PmlTextRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace UCIS.Pml {
+	public class PmlTextWriter : IPmlWriter {
+		private TextWriter pWriter;
+
+		public static string GetMessageString(PmlElement Message) {
+			StringWriter Buffer = new StringWriter();
+			WriteMessageTo(Message, Buffer);
+			return Buffer.ToString();
+		}
+
+		public PmlTextWriter(TextWriter Writer) {
+			pWriter = Writer;
+		}
+		public PmlTextWriter(Stream Writer, Encoding Encoding) {
+			pWriter = new StreamWriter(Writer, Encoding);
+		}
+		public PmlTextWriter(StringBuilder StringBuilder) {
+			pWriter = new StringWriter(StringBuilder);
+		}
+
+		public TextWriter BaseWriter {
+			get { return pWriter; }
+			set { pWriter = value; }
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			WriteElementTo(Message, "", pWriter);
+		}
+
+		public static void WriteMessageTo(PmlElement Message, TextWriter Writer) {
+			lock (Writer) {
+				WriteElementTo(Message, "", Writer);
+				Writer.Flush();
+			}
+		}
+
+		private static void WriteElementTo(PmlElement Element, string Indent, TextWriter Writer) {
+			if (Element == null) {
+				Console.WriteLine("NULL");
+				return;
+			}
+			switch (Element.Type) {
+				case PmlType.Null:
+					Writer.WriteLine("NULL");
+					break;
+				case PmlType.Collection:
+					Writer.WriteLine("COLLECTION {");
+					foreach (PmlElement Child in (PmlCollection)Element) {
+						Writer.Write(Indent + " ");
+						WriteElementTo(Child, Indent + " ", Writer);
+					}
+
+					Writer.WriteLine(Indent + "}");
+					break;
+				case PmlType.Dictionary:
+					Writer.WriteLine("DICTIONARY {");
+					foreach (KeyValuePair<string, PmlElement> Child in (PmlDictionary)Element) {
+						Writer.Write(Indent + " " + Uri.EscapeDataString(Child.Key) + " ");
+						WriteElementTo(Child.Value, Indent + " ", Writer);
+					}
+
+					Writer.WriteLine(Indent + "}");
+					break;
+				case PmlType.Binary:
+					Writer.WriteLine("BINARY " + Convert.ToBase64String(Element.ToByteArray()));
+					break;
+				case PmlType.Integer:
+					Writer.WriteLine("INT " + Element.ToString());
+					break;
+				case PmlType.String:
+					Writer.WriteLine("STRING " + Uri.EscapeDataString(Element.ToString()));
+					break;
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Pml/RW/PmlXmlRW.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Xml;
+using System.IO;
+using UCIS.Pml;
+
+namespace UCIS.Pml {
+	public class PmlXmlRW : IPmlRW {
+		private PmlXmlReader pReader;
+		private PmlXmlWriter pWriter;
+
+		public PmlXmlRW(Stream Stream) {
+			pReader = new PmlXmlReader(Stream);
+			pWriter = new PmlXmlWriter(Stream);
+		}
+		public PmlXmlRW(Stream Stream, Encoding Encoding) {
+			pReader = new PmlXmlReader(Stream);
+			pWriter = new PmlXmlWriter(Stream, Encoding);
+		}
+
+		public PmlElement ReadMessage() {
+			return pReader.ReadMessage();
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			pWriter.WriteMessage(Message);
+		}
+	}
+
+	public class PmlXmlWriter : IPmlWriter {
+		private Stream pStream;
+		private XmlWriterSettings pXMLConfig;
+
+		public PmlXmlWriter(Stream Stream, Encoding Encoding) {
+			pXMLConfig = CreateXMLSettings(Encoding);
+
+			pStream = Stream;
+		}
+		public PmlXmlWriter(Stream Stream)
+			: this(Stream, Encoding.UTF8) {
+		}
+
+		private static XmlWriterSettings CreateXMLSettings() {
+			return CreateXMLSettings(null);
+		}
+		private static XmlWriterSettings CreateXMLSettings(Encoding Encoding) {
+			XmlWriterSettings XMLConfig = new XmlWriterSettings();
+			if (Encoding == null) Encoding = Encoding.UTF8;
+			XMLConfig.ConformanceLevel = ConformanceLevel.Document;
+			XMLConfig.NewLineHandling = NewLineHandling.Entitize;
+			XMLConfig.OmitXmlDeclaration = true;
+			XMLConfig.CheckCharacters = true;
+			XMLConfig.Encoding = Encoding;
+			XMLConfig.CloseOutput = false;
+			return XMLConfig;
+		}
+
+		public void WriteMessage(PmlElement Message) {
+			WriteMessageToStream(Message, pStream);
+			pStream.WriteByte(0);
+			pStream.Flush();
+		}
+
+		public static void WriteMessageToFile(PmlElement Message, string Filename) {
+			FileStream F = File.Create(Filename);
+			WriteMessageToStream(Message, F);
+			F.Close();
+		}
+
+		public static void WriteMessageToStream(PmlElement Message, Stream Stream) {
+			WriteMessageToStream(Message, Stream, CreateXMLSettings());
+		}
+
+		public static void WriteMessageToStream(PmlElement Message, Stream Stream, XmlWriterSettings Settings) {
+			XmlWriter Writer = System.Xml.XmlWriter.Create(Stream, Settings);
+			Writer.WriteStartDocument();
+			Writer.WriteStartElement("msg");
+			WriteElementTo(Message, Writer);
+			Writer.WriteEndElement();
+			Writer.WriteEndDocument();
+			Writer.Flush();
+			Writer.Close();
+		}
+
+		private static void WriteElementTo(PmlElement Element, System.Xml.XmlWriter Writer) {
+			switch (Element.Type) {
+				case PmlType.Binary:
+					Writer.WriteAttributeString("type", "binary");
+					byte[] Bytes = Element.ToByteArray();
+					Writer.WriteBase64(Bytes, 0, Bytes.Length);
+					break;
+				case PmlType.Collection:
+					Writer.WriteAttributeString("type", "collection");
+					foreach (PmlElement Child in (PmlCollection)Element) {
+						Writer.WriteStartElement("item");
+						WriteElementTo(Child, Writer);
+						Writer.WriteEndElement();
+					}
+
+					break;
+				case PmlType.Dictionary:
+					Writer.WriteAttributeString("type", "dictionary");
+					foreach (KeyValuePair<string, PmlElement> Child in (PmlDictionary)Element) {
+						Writer.WriteStartElement(Child.Key);
+						WriteElementTo(Child.Value, Writer);
+						Writer.WriteEndElement();
+					}
+
+					break;
+				case PmlType.Integer:
+					Writer.WriteAttributeString("type", "integer");
+					Writer.WriteString(Element.ToString());
+					break;
+				case PmlType.Null:
+					Writer.WriteAttributeString("type", "null");
+					break;
+				case PmlType.String:
+					Writer.WriteAttributeString("type", "string");
+					Writer.WriteString(Element.ToString());
+					break;
+			}
+		}
+	}
+
+	public class PmlXmlReader : IPmlReader {
+		private BinaryReader pReader;
+		private System.Xml.XmlReaderSettings pXMLSettings;
+
+		public PmlXmlReader(Stream Stream)
+			: this(new BinaryReader(Stream)) {
+		}
+
+		public PmlXmlReader(BinaryReader Reader) {
+			pReader = Reader;
+			pXMLSettings = new System.Xml.XmlReaderSettings();
+			pXMLSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;
+			pXMLSettings.CloseInput = true;
+			pXMLSettings.IgnoreComments = true;
+			pXMLSettings.IgnoreProcessingInstructions = true;
+			pXMLSettings.IgnoreWhitespace = true;
+			pXMLSettings.ValidationType = System.Xml.ValidationType.None;
+			pXMLSettings.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None;
+			pXMLSettings.CheckCharacters = true;
+		}
+
+		public BinaryReader BaseReader {
+			get { return pReader; }
+			set { pReader = value; }
+		}
+
+		private XmlDocument ReadXMLDocument() {
+			System.Xml.XmlDocument Doc = new System.Xml.XmlDocument();
+			MemoryStream Buffer = default(MemoryStream);
+			System.Xml.XmlReader XMLReader = default(System.Xml.XmlReader);
+			byte B = 0;
+			Buffer = new MemoryStream();
+			do {
+				B = pReader.ReadByte();
+				if (B == 0) break;
+				Buffer.WriteByte(B);
+			}
+			while (true);
+			Buffer.Flush();
+			Buffer.Seek(0, SeekOrigin.Begin);
+
+			XMLReader = System.Xml.XmlReader.Create(Buffer, pXMLSettings);
+			Doc.Load(XMLReader);
+			XMLReader.Close();
+			return Doc;
+		}
+
+		public PmlElement ReadMessage() {
+			System.Xml.XmlDocument Doc = default(System.Xml.XmlDocument);
+			Doc = ReadXMLDocument();
+			if (Doc == null) return null;
+			return ReadElement(Doc.FirstChild);
+		}
+
+		public static PmlElement ReadElement(System.Xml.XmlNode X) {
+			PmlType pType;
+			bool pTypeFound = false;
+			pType = PmlType.Null;
+			pTypeFound = true;
+			if (X.Attributes != null && X.Attributes.Count > 0 && X.Attributes["type"] != null) {
+				switch (X.Attributes["type"].Value.ToLowerInvariant()) {
+					case "binary":
+						pType = PmlType.Binary;
+						break;
+					case "collection":
+						pType = PmlType.Collection;
+						break;
+					case "dictionary":
+						pType = PmlType.Dictionary;
+						break;
+					case "string":
+						pType = PmlType.String;
+						break;
+					case "null":
+						pType = PmlType.Null;
+						break;
+					case "integer":
+						pType = PmlType.Integer;
+						break;
+					default:
+						pTypeFound = false;
+						break;
+				}
+			} else {
+				pTypeFound = false;
+			}
+
+			if (!pTypeFound) {
+				if (X.HasChildNodes) {
+					if (X.ChildNodes.Count == 1 && X.FirstChild.NodeType == System.Xml.XmlNodeType.Text) {
+						Int64 dummy;
+						UInt64 dummyu;
+						if (Int64.TryParse(X.FirstChild.Value, out dummy) || UInt64.TryParse(X.FirstChild.Value, out dummyu)) {
+							pType = PmlType.Integer;
+						} else {
+							pType = PmlType.String;
+						}
+					} else if (X.FirstChild.Name == "item") {
+						pType = PmlType.Collection;
+					} else {
+						pType = PmlType.Dictionary;
+					}
+				} else {
+					pType = PmlType.Null;
+				}
+			}
+
+			switch (pType) {
+				case PmlType.Null:
+					return new PmlNull();
+				case PmlType.Binary:
+					if (X.FirstChild == null) {
+						return new PmlBinary(new byte[0]);
+					} else {
+						return new PmlBinary(Convert.FromBase64String(X.FirstChild.Value));
+					}
+				case PmlType.Integer:
+					return new PmlInteger(X.FirstChild.Value);
+				case PmlType.String:
+					if (X.FirstChild == null) {
+						return new PmlString("");
+					} else {
+						return new PmlString(X.FirstChild.Value);
+					}
+				case PmlType.Collection:
+					PmlCollection C = new PmlCollection();
+					foreach (XmlNode N in X.ChildNodes) {
+						C.Add(ReadElement(N));
+					}
+
+					return C;
+				case PmlType.Dictionary:
+					PmlDictionary D = new PmlDictionary();
+					foreach (XmlNode N in X.ChildNodes) {
+						D.Add(N.Name, ReadElement(N));
+					}
+
+					return D;
+				default:
+					return null;
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Properties/AssemblyInfo.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 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("UCIS")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("UCIS")]
+[assembly: AssemblyCopyright("Copyright ©  2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5ed5657c-523a-4e07-a993-662200f08b42")]
+
+// 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 Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Radio/Tuner.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,262 @@
+using System;
+using System.Collections.Generic;
+
+namespace UCIS.Radio {
+	public struct TunerFrequencyRange {
+		public TunerFrequencyRange(ulong Begin, ulong End) {
+			this.Begin = Begin;
+			this.End = End;
+		}
+
+		public ulong Begin;
+		public ulong End;
+	}
+	public struct TunerMode {
+		public TunerMode(int Index, string Name) {
+			this.Index = Index;
+			this.Name = Name;
+		}
+
+		public int Index;
+		public string Name;
+	}
+	public struct TunerFilter {
+		public TunerFilter(int Index, string Name) {
+			this.Index = Index;
+			this.Name = Name;
+		}
+
+		public int Index;
+		public string Name;
+	}
+
+	public class TunerCapabilities {
+		public TunerFrequencyRange[] Bands = new TunerFrequencyRange[0];
+		public IDictionary<byte, string> Modes = new Dictionary<byte, string>();
+		public IDictionary<byte, string> Filters = new Dictionary<byte, string>();
+		public IList<TunerOption> Options = new List<TunerOption>();
+		public byte[] AvailableModes;
+		public byte[] AvailableFilters;
+	}
+
+	public enum TunerOption : byte {
+		//R/W 0-255 value
+		Volume = 1,
+		Squelch = 2,
+		IfShift = 3,
+
+		//Not accessible (feature indication only)
+		Frequency = 50,
+		Mode = 51,
+		Filter = 52,
+
+		//Read only
+		Signal = 70,
+		Online = 71,
+
+		//R/W On/Off
+		Attenuator = 100,
+		AGC = 101,
+		NoiseBlanker = 102,
+		VSC = 103,
+		StereoMono = 104,
+
+		//W Execute
+		Poll = 151,
+		RadioText = 200,
+
+		//200+: reserved for personal use
+	}
+
+	public class TunerOptionChangedEventArgs : EventArgs {
+		public TunerOptionChangedEventArgs(TunerOption option) { Option = option; }
+		public TunerOption Option;
+	}
+
+	public interface ITuner {
+		event EventHandler TuningChanged;
+		event EventHandler<TunerOptionChangedEventArgs> OptionChanged;
+		void Open();
+		void Close();
+		void Poll();
+		TunerCapabilities Capabilities { get; }
+		ulong Frequency { get; set; }
+		byte Mode { get; set; }
+		byte Filter { get; set; }
+		bool SetTuning(ulong frequency, byte mode, byte filter);
+		bool SetOption(TunerOption Option, byte Value);
+		byte GetOption(TunerOption Option);
+	}
+
+	public abstract class Tuner : ITuner {
+		private ulong _frequency;
+		private byte _mode, _filter;
+		private TunerCapabilities _capabilities = new TunerCapabilities();
+		private byte[] _options = new byte[256];
+
+		public event EventHandler TuningChanged;
+		public event EventHandler AvailableModesChanged;
+		public event EventHandler<TunerOptionChangedEventArgs> OptionChanged;
+
+		protected Tuner() {
+			//AcceptOption(ReceiverOptions.IfShift, 127);
+			//AcceptOption(ReceiverOptions.Online, 1);
+		}
+
+		public virtual void Open() { }
+		public virtual void Close() { }
+		public virtual void Poll() { }
+
+		public TunerCapabilities Capabilities { get { return _capabilities; } }
+
+		public ulong Frequency {
+			get { return _frequency; }
+			set {SetTuning(value, 0, 0); }
+		}
+		public byte Mode {
+			get { return _mode; }
+			set { SetTuning(0, value, 0); }
+		}
+		public byte Filter {
+			get { return _mode; }
+			set { SetTuning(0, 0, value); }
+		}
+		public virtual bool SetTuning(ulong frequency, byte mode, byte filter) {
+			return SetTuning(ref frequency, ref mode, ref filter);
+		}
+		public virtual bool SetTuning(ref ulong frequency, ref byte mode, ref byte filter) {
+			bool notexact = false;
+			CheckFrequency(ref frequency, ref notexact);
+			CheckMode(ref mode, ref notexact);
+			CheckFilter(ref filter, ref notexact);
+			AcceptTuning(frequency, mode, filter);
+			return !notexact;
+		}
+
+		public virtual bool SetOption(TunerOption Option, byte Value) {
+			return SetOption(Option, ref Value);
+		}
+		public virtual bool SetOption(TunerOption Option, ref byte Value) {
+			bool notexact = false;
+			CheckOption(Option, ref Value, ref notexact);
+			AcceptOption(Option, Value);
+			return !notexact;
+		}
+		public virtual byte GetOption(TunerOption Option) {
+			return _options[(int)Option];
+		}
+		protected bool CheckOption(TunerOption Option, ref byte Value, ref bool notexact) {
+			switch (Option) {
+				case TunerOption.Filter:
+				case TunerOption.Frequency:
+				case TunerOption.Mode:
+				case TunerOption.Signal:
+					Value = 0;
+					notexact = true;
+					return false;
+				case TunerOption.AGC:
+				case TunerOption.Attenuator:
+				case TunerOption.NoiseBlanker:
+				case TunerOption.StereoMono:
+				case TunerOption.VSC:
+					if (Value > 1) Value = 1;
+					return (Value != _options[(int)Option]);
+				case TunerOption.IfShift:
+				case TunerOption.Squelch:
+				case TunerOption.Volume:
+					return (Value != _options[(int)Option]);
+				case TunerOption.RadioText:
+					Value = 1;
+					return true;
+				default:
+					return true;
+			}
+		}
+		protected void AcceptOption(TunerOption Option, byte Value) {
+			if (_options[(int)Option] != Value) {
+				_options[(int)Option] = Value;
+				if (OptionChanged != null) OptionChanged(this, new TunerOptionChangedEventArgs(Option));
+			}
+		}
+
+		protected bool CheckFrequency(ref ulong frequency, ref bool notexact) {
+			ulong closest = 0;
+			ulong diff = ulong.MaxValue;
+			if (frequency == 0 || frequency == _frequency) { //Frequency was not changed, return current mode
+				frequency = _mode;
+				return false;
+			}
+			foreach (TunerFrequencyRange f in _capabilities.Bands) {
+				if (frequency >= f.Begin && frequency <= f.End) return true;
+				if (frequency < f.Begin && diff > f.Begin - frequency) {
+					closest = f.Begin;
+					diff = closest - frequency;
+				} else if (frequency > f.End && diff > frequency - f.End) {
+					closest = f.End;
+					diff = frequency - closest;
+				}
+			}
+			if (closest != 0 && closest != _frequency) {
+				notexact = true;
+				frequency = closest;
+				return true;
+			} else {
+				return false;
+			}
+		}
+		protected bool CheckMode(ref byte mode, ref bool notexact) {
+			if (mode == 0 || mode == _mode) { //Mode was not changed, return current mode
+				mode = _mode;
+				return false;
+			}
+			foreach (byte b in _capabilities.AvailableModes) { //Mode was changed, accept if allowed
+				if (mode == b) return true;
+			}
+			mode = _mode; //Mode was changed but not allowed, keep current mode
+			return false;
+		}
+		protected bool CheckFilter(ref byte filter, ref bool notexact) {
+			byte closest = 0;
+			int diff = int.MaxValue;
+			//Filter has to be checked against AvailableFilters, in case AvailableFilters was changed
+			/*if (filter == 0 || filter == _filter) { //Filter was not changed, return current filter
+				filter = _filter;
+				return false;
+			}*/
+			foreach (byte b in _capabilities.AvailableFilters) { //Filter was changed, find closest one
+				if (filter == b) return true;
+				if (filter < b && diff > b - filter) {
+					closest = b;
+					diff = closest - filter;
+				} else if (filter > b && diff > filter - b) {
+					closest = b;
+					diff = filter - closest;
+				}
+			}
+			if (closest != 0 && closest != _filter) {
+				notexact = true;
+				filter = closest;
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+		protected void AcceptTuning(ulong frequency, byte mode, byte filter) {
+			bool changed = false;
+			if (frequency != 0 && frequency != _frequency) { changed = true; _frequency = frequency; }
+			if (mode != 0 && mode != _mode) { changed = true; _mode = mode; }
+			if (filter != 0 && filter != _filter) { changed = true; _filter = filter; }
+			if (changed && TuningChanged != null) TuningChanged(this, new EventArgs());
+		}
+
+		protected void AcceptAvailableFilters(byte[] Filters) {
+			AcceptAvailableModes(null, Filters);
+		}
+		protected void AcceptAvailableModes(byte[] Modes, byte[] Filters) {
+			if (Modes != null) _capabilities.AvailableModes = Modes;
+			if (Filters != null) _capabilities.AvailableFilters = Filters;
+			if (AvailableModesChanged != null) AvailableModesChanged(this, new EventArgs());
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ThreadPool.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,281 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace UCIS {
+	public class ThreadPool {
+		private static ThreadPool pManager = null;
+
+		public static ThreadPool DefaultPool {
+			get {
+				if (pManager == null) pManager = new ThreadPool();
+				return pManager;
+			}
+		}
+
+		//Starts a long-term background task
+		public static WorkItem RunTask(WaitCallback Callback, object State) {
+			return DefaultPool.QueueWorkItem(Callback, State);
+		}
+		//Starts a short-term background task
+		public static WorkItem RunCall(WaitCallback Callback, object State) {
+			return DefaultPool.QueueWorkItem(Callback, State);
+		}
+
+
+		public class WorkItem {
+			public WaitCallback Callback { get; internal set; }
+			public object State { get; internal set; }
+			public ThreadInfo Thread { get; internal set; }
+		}
+		public class ThreadInfo {
+			public Thread Thread { get; internal set; }
+			internal AutoResetEvent WaitHandle = new AutoResetEvent(false);
+			public WorkItem WorkItem { get; internal set; }
+			public bool Busy { get; internal set; }
+			public bool Abort { get; internal set; }
+			public DateTime LastActive { get; internal set; }
+		}
+
+		public class ExceptionEventArgs : EventArgs {
+			public ExceptionEventArgs(WorkItem Item, Exception Exception, bool ThrowError) {
+				this.Item = Item;
+				this.Exception = Exception;
+				this.ThrowError = ThrowError;
+			}
+			public WorkItem Item;
+			public Exception Exception;
+			public bool ThrowError;
+		}
+
+		private List<ThreadInfo> pThreads = new List<ThreadInfo>();
+		private List<ThreadInfo> pBusyThreads = new List<ThreadInfo>();
+		private Queue<ThreadInfo> pIdleThreads = new Queue<ThreadInfo>();
+		private int pThreadsMax;
+		private int pThreadsMinIdle;
+		private int pThreadsMaxIdle;
+
+		public event OnExceptionEventHandler OnException;
+		public delegate void OnExceptionEventHandler(ThreadPool sender, ExceptionEventArgs e);
+
+		public System.Collections.ObjectModel.ReadOnlyCollection<ThreadInfo> Threads {
+			get {
+				return new System.Collections.ObjectModel.ReadOnlyCollection<ThreadInfo>(pThreads);
+			}
+		}
+
+		public ThreadPool() : this(250, 1, 5) { }
+
+		public ThreadPool(int MaxThreads, int MinIdle, int MaxIdle) {
+			int I = 0;
+			if (MaxThreads < 0) {
+				throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than 0");
+			} else if (MaxThreads < MaxIdle) {
+				throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle");
+			} else if (MaxIdle < 0) {
+				throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0");
+			} else if (MinIdle < 0) {
+				throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must greater than or equal to 0");
+			} else if (MinIdle > MaxIdle) {
+				throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle");
+			}
+			pThreadsMax = MaxThreads;
+			pThreadsMinIdle = MinIdle;
+			pThreadsMaxIdle = MaxIdle;
+			for (I = 1; I <= pThreadsMinIdle; I++) {
+				StartThread(false);
+			}
+		}
+
+		public int ThreadsIdle {
+			get { return pIdleThreads.Count; }
+		}
+		public int ThreadsBusy {
+			get { return pBusyThreads.Count; }
+		}
+		public int ThreadsAlive {
+			get { return pThreads.Count; }
+		}
+		public int ThreadsMinIdle {
+			get { return pThreadsMinIdle; }
+			set {
+				if (value > pThreadsMaxIdle) {
+					throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must be smaller than ThreadsMaxIdle");
+				} else if (value < 0) {
+					throw new ArgumentOutOfRangeException("ThreadsMinIdle", "ThreadsMinIdle must greater than or equal to 0");
+				} else {
+					int I = 0;
+					int C = 0;
+					C = pIdleThreads.Count;
+					if (value > C) {
+						for (I = C; I <= value - 1; I++) {
+							StartThread(false);
+						}
+					}
+					pThreadsMinIdle = value;
+				}
+			}
+		}
+		public int ThreadsMaxIdle {
+			get { return pThreadsMaxIdle; }
+			set {
+				if (pThreadsMinIdle > value) {
+					throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must be greater than or equal to ThreadsMinIdle");
+				} else if (value < 0) {
+					throw new ArgumentOutOfRangeException("ThreadsMaxIdle", "ThreadsMaxIdle must greater than or equal to 0");
+				} else {
+					int I = 0;
+					int C = 0;
+					ThreadInfo T = default(ThreadInfo);
+					lock (pIdleThreads) {
+						C = pIdleThreads.Count;
+						if (value < C) {
+							for (I = value; I <= C - 1; I++) {
+								T = pIdleThreads.Dequeue();
+								T.Abort = true;
+								T.WaitHandle.Set();
+							}
+						}
+					}
+					pThreadsMaxIdle = value;
+				}
+			}
+		}
+		public int ThreadsMax {
+			get { return pThreadsMax; }
+			set {
+				if (pThreadsMaxIdle > value) {
+					throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must be greater than or equal to ThreadsMaxIdle");
+				} else if (value <= 0) {
+					throw new ArgumentOutOfRangeException("ThreadsMax", "ThreadsMax must greater than 0");
+				} else {
+					pThreadsMax = value;
+				}
+			}
+		}
+
+		public WorkItem QueueWorkItem(WaitCallback Callback, object State) {
+			WorkItem WorkItem = new WorkItem();
+			ThreadInfo Thread = null;
+			WorkItem.Callback = Callback;
+			WorkItem.State = State;
+			lock (pIdleThreads) {
+				while (pIdleThreads.Count > 0) {
+					Thread = pIdleThreads.Dequeue();
+					if (!Thread.Abort) {
+						break;
+					} else {
+						Thread = null;
+					}
+				}
+			}
+			if (Thread == null)  {
+				if (pThreads.Count < pThreadsMax) {
+					Thread = StartThread(true);
+				} else {
+					throw new ThreadStateException("Thread limit exceeded");
+				}
+			}
+			Thread.LastActive = DateTime.Now;
+			WorkItem.Thread = Thread;
+			Thread.WorkItem = WorkItem;
+			Thread.WaitHandle.Set();
+			return WorkItem;
+		}
+
+		private ThreadInfo StartThread(bool Reserved) {
+			ThreadInfo Thread = new ThreadInfo();
+			Thread.Thread = new Thread(pWorker);
+			lock (pThreads) {
+				pThreads.Add(Thread);
+				if (!Reserved) pIdleThreads.Enqueue(Thread);
+			}
+			Thread.LastActive = DateTime.Now;
+			Thread.Thread.Start(Thread);
+			return Thread;
+		}
+
+		public void AbortAllThreads() {
+			lock (pIdleThreads) {
+				while (pIdleThreads.Count > 0) {
+					ThreadInfo Thread = pIdleThreads.Dequeue();
+					Thread.Abort = true;
+					Thread.WaitHandle.Set();
+				}
+			}
+			foreach (ThreadInfo Thread in pThreads.ToArray()) {
+				if (Thread != null && !Thread.Abort) {
+					Thread.Thread.Abort();
+					Thread.Abort = true;
+					Thread.WaitHandle.Set();
+				}
+			}
+			pIdleThreads.Clear();
+		}
+
+		//ToDo: add timer to kill old threads periodically
+		public void KillOldThreads() {
+			ThreadInfo Thread;
+			lock (pIdleThreads) {
+				if (pIdleThreads.Count == 0) return;
+				Thread = pIdleThreads.Dequeue();
+			}
+			if (DateTime.Now.Subtract(Thread.LastActive).TotalMinutes > 1) {
+				Thread.Abort = true;
+				Thread.WaitHandle.Set();
+			} else {
+				lock (pIdleThreads) pIdleThreads.Enqueue(Thread);
+			}
+		}
+
+		private void pWorker(object state) {
+			ThreadInfo Thread = (ThreadInfo)state;
+			if (Thread == null) throw new ArgumentNullException("state");
+			try {
+				while (true) {
+					if (Thread.WaitHandle == null) throw new ArgumentNullException("WaitHandle");
+					if (!Thread.WaitHandle.WaitOne(1000, false)) {
+						if (pBusyThreads.Count == 0) {
+							return;
+						} else {
+							continue;
+						}
+					}					
+					if (Thread.Abort) break;
+
+					Thread.Busy = true;
+					lock (pBusyThreads) pBusyThreads.Add(Thread);
+					try {
+						if (Thread.WorkItem == null) throw new ArgumentNullException("WorkItem");
+						if (Thread.WorkItem.Callback == null) throw new ArgumentNullException("WorkItem.Callback");
+						Thread.WorkItem.Callback.Invoke(Thread.WorkItem.State);
+					} catch (ThreadAbortException ex) {
+						ExceptionEventArgs e = new ExceptionEventArgs(Thread.WorkItem, ex, false);
+						if (OnException != null) OnException(this, e);
+						if (e.ThrowError) Console.WriteLine("ThreadAbortException in ThreadPool thread: " + e.Exception.ToString());
+						return;
+					} catch (Exception ex) {
+						ExceptionEventArgs e = new ExceptionEventArgs(Thread.WorkItem, ex, true);
+						if (OnException != null) OnException(this, e);
+						if (e.ThrowError) {
+							Console.WriteLine("Exception in ThreadPool thread: " + e.Exception.ToString());
+							throw new Exception("Unhandled exception in work item", e.Exception);
+						}
+					} finally {
+						lock (pBusyThreads) pBusyThreads.Remove(Thread);
+					}
+					Thread.WorkItem.Thread = null;
+					Thread.WorkItem = null;
+					Thread.Busy = false;
+					lock (pIdleThreads) {
+						if (pIdleThreads.Count >= pThreadsMaxIdle) break;
+						pIdleThreads.Enqueue(Thread);
+					}
+				}
+			} finally {
+				Thread.Abort = true;
+				lock (pThreads) pThreads.Remove(Thread);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UCIS.csproj	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{3200885C-E36B-400B-BE21-6209B47832E6}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>UCIS</RootNamespace>
+    <AssemblyName>UCIS</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\lib\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\lib\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Management" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Cache.cs" />
+    <Compile Include="Cci\CciCommand.cs" />
+    <Compile Include="Database.cs" />
+    <None Include="DBReader.cs" />
+    <Compile Include="Net\ConnectionList.cs" />
+    <Compile Include="Net\HTTP.cs" />
+    <Compile Include="Net\INetworkConnection.cs" />
+    <Compile Include="Net\TCPServer.cs" />
+    <Compile Include="Net\TCPStream.cs" />
+    <Compile Include="Pml\Channels\ActivePmlChannel.cs" />
+    <Compile Include="Pml\Channels\PassivePmlChannel.cs" />
+    <Compile Include="Pml\Channels\PmlChannel.cs" />
+    <None Include="Pml\Elements\Array.cs" />
+    <Compile Include="Pml\Elements\Binary.cs" />
+    <Compile Include="Pml\Elements\Collection.cs" />
+    <Compile Include="Pml\Elements\Dictionary.cs" />
+    <Compile Include="Pml\Elements\Element.cs" />
+    <Compile Include="Pml\Elements\Integer.cs" />
+    <None Include="Pml\Elements\Number.cs" />
+    <Compile Include="Pml\Elements\PmlNull.cs" />
+    <Compile Include="Pml\Elements\PmlString.cs" />
+    <Compile Include="Pml\Channels\IPmlChannel.cs" />
+    <Compile Include="Pml\IPmlCommunicator.cs" />
+    <Compile Include="Pml\IPmlRpc.cs" />
+    <None Include="Pml\LegacyPmlCommunicator.cs" />
+    <Compile Include="Pml\PmlBuilder.cs" />
+    <None Include="Pml\PmlCommunicator.cs" />
+    <Compile Include="Pml\PmlCommunicator2.cs" />
+    <Compile Include="Pml\RW\PmlAmfRW.cs" />
+    <Compile Include="Pml\RW\PmlPHPRW.cs" />
+    <Compile Include="Pml\RW\PmlBinaryRW.cs" />
+    <Compile Include="Pml\RW\IPmlRW.cs" />
+    <Compile Include="Pml\PmlConnection.cs" />
+    <Compile Include="Pml\RW\PmlTextRW.cs" />
+    <Compile Include="Pml\RW\PmlXmlRW.cs" />
+    <Compile Include="Pml\Channels\TCPPmlChannel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Radio\Tuner.cs" />
+    <Compile Include="ThreadPool.cs" />
+    <Compile Include="UTF8NoPreamble.cs" />
+    <Compile Include="Util\ArrayUtil.cs" />
+    <Compile Include="Util\AsyncStream.cs" />
+    <Compile Include="Util\CrossStream.cs" />
+    <Compile Include="Util\HoldStream.cs" />
+    <Compile Include="Util\PipeStream.cs" />
+    <Compile Include="Windows\ServiceManager.cs" />
+    <Compile Include="Xml\PolicyFile.cs" />
+    <Compile Include="Xml\Server.cs" />
+    <Compile Include="Xml\Socket.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UTF8NoPreamble.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,7 @@
+namespace UCIS {
+	public class UTF8NoPreamble : System.Text.UTF8Encoding {
+		public override byte[] GetPreamble() {
+			return new byte[] { };
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Util/ArrayUtil.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+
+namespace UCIS.Util {
+	public class ArrayUtil {
+		public static T[] Slice<T>(T[] input, int offset) {
+			if (offset < 0) offset = input.Length + offset;
+			return Slice(input, offset, input.Length - offset);
+		}
+		public static T[] Slice<T>(T[] input, int offset, int count) {
+			if (offset < 0) offset = input.Length + offset;
+			if (count < 0) count = input.Length + count - offset;
+			T[] output = new T[count];
+			Array.Copy(input, offset, output, 0, count);
+			return output;
+		}
+		public static T[] ToArray<T>(ICollection<T> input) {
+			T[] output = new T[input.Count];
+			input.CopyTo(output, 0);
+			return output;
+		}
+		public static IList<T> ToList<T>(IEnumerable<T> input) {
+			return new List<T>(input);
+		}
+		public static void GnomeSort<T>(IList<T> a, Comparison<T> comparer) {
+			int pos = 1;
+			while (pos < a.Count) {
+				if (comparer(a[pos], a[pos - 1]) >= 0) {
+					pos++;
+				} else {
+					T tmp = a[pos];
+					a[pos] = a[pos - 1];
+					a[pos - 1] = tmp;
+					if (pos > 1) pos--; else pos++;
+				}
+			}
+		}
+		//Array shuffle
+		//Array unique
+		public static T[] Merge<T>(params ArraySegment<T>[] parts) {
+			int count = 0;
+			foreach (ArraySegment<T> segment in parts) count += segment.Count;
+			T[] ret = new T[count];
+			int offset = 0;
+			foreach (ArraySegment<T> segment in parts) {
+				Array.Copy(segment.Array, segment.Offset, ret, offset, segment.Count);
+				offset += segment.Count;
+			}
+			return ret;
+		}
+		public static T[] Merge<T>(params T[][] parts) {
+			int count = 0;
+			foreach (T[] segment in parts) count += segment.Length;
+			T[] ret = new T[count];
+			int offset = 0;
+			foreach (T[] segment in parts) {
+				segment.CopyTo(ret, offset);
+				offset += segment.Length;
+			}
+			return ret;
+		}
+		public static Boolean Equal<T>(T[] a, T[] b, IEqualityComparer<T> comparer) {
+			if (ReferenceEquals(a, b)) return true;
+			if (a == null || b == null) return false;
+			if (a.Length != b.Length) return false;
+			for (int i = 0; i < a.Length; i++) if (!comparer.Equals(a[i], b[i])) return false;
+			return true;
+		}
+		public static Boolean Equal<T>(T[] a, T[] b) where T : IEquatable<Byte> {
+			if (ReferenceEquals(a, b)) return true;
+			if (a == null || b == null) return false;
+			if (a.Length != b.Length) return false;
+			for (int i = 0; i < a.Length; i++) {
+				if (ReferenceEquals(a[i], b[i])) continue;
+				if (ReferenceEquals(a[i], null) || ReferenceEquals(b[i], null)) continue;
+				if (!a[i].Equals(b[i])) return false;
+			}
+			return true;
+		}
+		public static Boolean Equal(Byte[] a, Byte[] b) {
+			if (ReferenceEquals(a, b)) return true;
+			if (a == null || b == null) return false;
+			if (a.Length != b.Length) return false;
+			for (int i = 0; i < a.Length; i++) if (a[i] != b[i]) return false;
+			return true;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Util/AsyncStream.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,88 @@
+using System;
+using System.IO;
+
+namespace UCIS.Util {
+	public class AsyncStreamWrapper : Stream {
+		ReadDelegate readDelegate;
+		WriteDelegate writeDelegate;
+
+		public Stream BaseStream { get; private set; }
+
+		public AsyncStreamWrapper(Stream stream) {
+			BaseStream = stream;
+			readDelegate = (ReadDelegate)Read;
+			writeDelegate = (WriteDelegate)Write;
+		}
+
+		public override int Read(byte[] buffer, int offset, int count) { return BaseStream.Read(buffer, offset, count); }
+		public override void Write(byte[] buffer, int offset, int count) { BaseStream.Write(buffer, offset, count); }
+		public override void Close() { BaseStream.Close(); }
+
+		public override bool CanRead { get { return BaseStream.CanRead; } }
+		public override bool CanSeek { get { return BaseStream.CanSeek; } }
+		public override bool CanTimeout { get { return BaseStream.CanTimeout ; } }
+		public override bool CanWrite { get { return BaseStream.CanWrite ; } }
+
+		public override int ReadTimeout {
+			get { return BaseStream.ReadTimeout; }
+			set { BaseStream.ReadTimeout = value; }
+		}
+		public override int WriteTimeout {
+			get { return BaseStream.WriteTimeout; }
+			set { BaseStream.WriteTimeout = value; }
+		}
+
+		public override void Flush() { BaseStream.Flush(); }
+		public override long Length { get { return BaseStream.Length; } }
+		public override long Position {
+			get { return BaseStream.Position; }
+			set { BaseStream.Position = value; }
+		}
+		public override long Seek(long offset, SeekOrigin origin) { return BaseStream.Seek(offset, origin); }
+		public override void SetLength(long value) { BaseStream.SetLength(value); }
+
+		public override int ReadByte() { return base.ReadByte(); }
+		public override void WriteByte(byte value) { BaseStream.WriteByte(value); }
+
+		private delegate int ReadDelegate(byte[] buffer, int offset, int count);
+		private delegate void WriteDelegate(byte[] buffer, int offset, int count);
+
+		public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			return readDelegate.BeginInvoke(buffer, offset, count, callback, state);
+		}
+		public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			return writeDelegate.BeginInvoke(buffer, offset, count, callback, state);
+		}
+		public override int EndRead(IAsyncResult asyncResult) {
+			return readDelegate.EndInvoke(asyncResult);
+		}
+		public override void EndWrite(IAsyncResult asyncResult) {
+			writeDelegate.EndInvoke(asyncResult);
+		}
+	}
+	public abstract class AsyncStream : Stream {
+		ReadDelegate readDelegate;
+		WriteDelegate writeDelegate;
+
+		public AsyncStream() {
+			readDelegate = (ReadDelegate)Read;
+			writeDelegate = (WriteDelegate)Write;
+		}
+
+		private delegate int ReadDelegate(byte[] buffer, int offset, int count);
+		private delegate void WriteDelegate(byte[] buffer, int offset, int count);
+
+		public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			return readDelegate.BeginInvoke(buffer, offset, count, callback, state);
+		}
+		public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			return writeDelegate.BeginInvoke(buffer, offset, count, callback, state);
+		}
+		public override int EndRead(IAsyncResult asyncResult) {
+			return readDelegate.EndInvoke(asyncResult);
+		}
+		public override void EndWrite(IAsyncResult asyncResult) {
+			writeDelegate.EndInvoke(asyncResult);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Util/CrossStream.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+
+namespace UCIS.Util {
+	public class CrossStream : Stream {
+		private Queue<byte[]> queue = new Queue<byte[]>();
+		private byte[] currentBuffer = null;
+		private int currentBufferIndex;
+		private CrossStream otherPart;
+		private AutoResetEvent resetEvent = new AutoResetEvent(false);
+
+		public static CrossStream CreatePair(out CrossStream stream1, out CrossStream stream2) {
+			stream1 = new CrossStream();
+			stream2 = new CrossStream(stream1);
+			stream1.otherPart = stream2;
+			return stream1;
+		}
+		public static CrossStream CreatePair(out CrossStream stream2) {
+			CrossStream stream1 = new CrossStream();
+			stream2 = new CrossStream(stream1);
+			stream1.otherPart = stream2;
+			return stream1;
+		}
+
+		private CrossStream() { }
+		public CrossStream(CrossStream other) {
+			this.otherPart = other;
+		}
+
+		public override bool CanRead { get { return true; } }
+		public override bool CanWrite { get { return true; } }
+		public override bool CanSeek { get { return false; } }
+		public override bool CanTimeout { get { return true; } }
+		public override long Length { get { throw new NotSupportedException(); } }
+		public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
+		public override void Flush() { }
+		public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+		public override void SetLength(long value) { throw new NotSupportedException(); }
+		public override int Read(byte[] buffer, int offset, int count) {
+			if (currentBuffer == null) {
+				//if (queue.Count == 0) if (!resetEvent.WaitOne(this.ReadTimeout)) throw new TimeoutException();
+				if (queue.Count == 0 && !resetEvent.WaitOne()) throw new TimeoutException();
+				//while (queue.Count == 0) Thread.Sleep(100);
+				resetEvent.Reset();
+				currentBuffer = queue.Dequeue();
+				currentBufferIndex = 0;
+			}
+			if (count > currentBuffer.Length - currentBufferIndex) count = currentBuffer.Length - currentBufferIndex;
+			Buffer.BlockCopy(currentBuffer, currentBufferIndex, buffer, offset, count);
+			currentBufferIndex += count;
+			if (currentBufferIndex == currentBuffer.Length) currentBuffer = null;
+			return count;
+		}
+		public override void Write(byte[] buffer, int offset, int count) {
+			byte[] tostore;
+			if (count == 0) return;
+			tostore = new byte[count];
+			Buffer.BlockCopy(buffer, offset, tostore, 0, count);
+			otherPart.queue.Enqueue(tostore);
+			otherPart.resetEvent.Set();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Util/HoldStream.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+
+namespace UCIS.Util {
+	public class HoldStream : Stream {
+		private Stream baseStream;
+		private MemoryStream buffer;
+
+		public HoldStream(Stream baseStream) {
+			this.baseStream = baseStream;
+			this.buffer = new MemoryStream(4096);
+		}
+
+		public override bool CanRead {
+			get { return baseStream.CanRead; }
+		}
+		public override bool CanSeek {
+			get { return buffer.CanSeek; }
+		}
+		public override bool CanTimeout {
+			get { return baseStream.CanTimeout; }
+		}
+		public override bool CanWrite {
+			get { return buffer.CanWrite; }
+		}
+		public override void Close() {
+			buffer.Close();
+			baseStream.Close();
+		}
+		public override void Flush() {
+			buffer.WriteTo(baseStream);
+			buffer.SetLength(0);
+			buffer.Seek(0, SeekOrigin.Begin);
+		}
+		public override void Write(byte[] buffer, int offset, int count) {
+			this.buffer.Write(buffer, offset, count);
+		}
+		public override int Read(byte[] buffer, int offset, int count) {
+			return baseStream.Read(buffer, offset, count);
+		}
+		public override void SetLength(long value) {
+			buffer.SetLength(value);
+		}
+		public override long Seek(long offset, SeekOrigin origin) {
+			return buffer.Seek(offset, origin);
+		}
+		public override long Position {
+			get { return buffer.Position; }
+			set { buffer.Position = value; }
+		}
+		public override long Length {
+			get { return buffer.Length; }
+		}
+		public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) {
+			return baseStream.BeginRead(buffer, offset, count, callback, state);
+		}
+		public override int EndRead(IAsyncResult asyncResult) {
+			return baseStream.EndRead(asyncResult);
+		}
+		public override void WriteByte(byte value) {
+			buffer.WriteByte(value);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Util/PipeStream.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+
+namespace UCIS.Util {
+	public class PipeStream : Stream {
+		private Queue<byte[]> queue = new Queue<byte[]>();
+		private byte[] currentBuffer = null;
+		private int currentBufferIndex;
+		private AutoResetEvent resetEvent = new AutoResetEvent(false);
+		private Boolean closed = false;
+
+		public PipeStream() {
+			ReadTimeout = Timeout.Infinite;
+		}
+
+		public override int ReadTimeout { get; set; }
+		public override bool CanRead { get { return !closed; } }
+		public override bool CanWrite { get { return !closed; } }
+		public override bool CanSeek { get { return false; } }
+		public override bool CanTimeout { get { return !closed; } }
+		public override long Length { get { throw new NotSupportedException(); } }
+		public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
+		public override void Flush() { }
+		public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+		public override void SetLength(long value) { throw new NotSupportedException(); }
+		public override int Read(byte[] buffer, int offset, int count) {
+			if (closed) throw new ObjectDisposedException("PipeStream");
+			if (currentBuffer == null) {
+				//if (queue.Count == 0) if (!resetEvent.WaitOne(this.ReadTimeout)) throw new TimeoutException();
+				if (queue.Count == 0 && (ReadTimeout == 0 || !resetEvent.WaitOne(ReadTimeout))) throw new TimeoutException();
+				//while (queue.Count == 0) Thread.Sleep(100);
+				resetEvent.Reset();
+				currentBuffer = queue.Dequeue();
+				currentBufferIndex = 0;
+			}
+			if (count > currentBuffer.Length - currentBufferIndex) count = currentBuffer.Length - currentBufferIndex;
+			Buffer.BlockCopy(currentBuffer, currentBufferIndex, buffer, offset, count);
+			currentBufferIndex += count;
+			if (currentBufferIndex == currentBuffer.Length) currentBuffer = null;
+			return count;
+		}
+		public override void Write(byte[] buffer, int offset, int count) {
+			byte[] tostore;
+			if (closed) throw new ObjectDisposedException("PipeStream");
+			if (count == 0) return;
+			tostore = new byte[count];
+			Buffer.BlockCopy(buffer, offset, tostore, 0, count);
+			queue.Enqueue(tostore);
+			resetEvent.Set();
+		}
+		public override void Close() {
+			closed = true;
+			resetEvent.Set();
+			base.Close();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Windows/ServiceManager.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,116 @@
+using System;
+using System.Management;
+using System.IO;
+
+namespace UCIS.Windows {
+	public class ServiceManager {
+		private ManagementObject _serviceObject;
+
+		public const string StartMode_Automatic = "Automatic";
+		public const string StartMode_Manual = "Manual";
+		public const string StartMode_Disabled = "Disabled";
+
+		private ServiceManager(ManagementObject ob) {
+			_serviceObject = ob;
+		}
+
+		public static ServiceManager GetServiceByPath(string FileName) {
+			ManagementClass mc = new ManagementClass("Win32_Service");
+			foreach (ManagementObject ob in mc.GetInstances()) {
+				string Value = (string)ob.GetPropertyValue("PathName");
+				if (Value == null) continue;
+				int Position = Value.IndexOf(FileName);
+				if (Position == 0 || Position == 1) { //Either <filepath> or <"filepath">
+					return new ServiceManager(ob);
+				}
+			}
+			return null;
+		}
+		public static ServiceManager GetServiceByName(string Name) {
+			ManagementClass mc = new ManagementClass("Win32_Service");
+			foreach (ManagementObject ob in mc.GetInstances()) {
+				string Value = (string)ob.GetPropertyValue("Name");
+				if (Value == null) continue;
+				if (Value.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) return new ServiceManager(ob);
+			}
+			return null;
+		}
+		public static ServiceManager Create(string Name, string DisplayName, string PathName, string StartMode, bool DesktopInteract, string StartName, string StartPassword) {
+			ManagementClass mc = new ManagementClass("Win32_Service");
+			UInt32 ret;
+			ret = (UInt32)mc.InvokeMethod("Create", new Object[] {
+					Name, //Name
+					DisplayName, //DisplayName
+					PathName, //PathName
+					16, //ServiceType (16 = own process)
+					1, //ErrorControl (1 = user is notified)
+					StartMode, //StartMode
+					DesktopInteract, //DesktopInteract
+					StartName, //StartName (null = LocalSystem)
+					StartPassword, //StartPassword
+					null, //LoadOrderGroup
+					null, //LoadOrderGroupDependencies
+					null //ServiceDependencies
+				});
+			if (ret != 0) throw new ManagementException("Could not create service (code " + ret.ToString() + ")");
+			return GetServiceByName(Name);
+		}
+
+		public string Name { get { return (string)_serviceObject.GetPropertyValue("Name"); } }
+		public string DisplayName { get { return (string)_serviceObject.GetPropertyValue("DisplayName"); } }
+		public string PathName { get { return (string)_serviceObject.GetPropertyValue("PathName"); } }
+		public string StartMode {
+			get { return (string)_serviceObject.GetPropertyValue("StartMode"); }
+			set { _serviceObject.InvokeMethod("ChangeStartMode", new Object[] { value }); Refresh(); }
+		}
+		public bool DesktopInteract { get { return (bool)_serviceObject.GetPropertyValue("DesktopInteract"); } }
+		public string StartName { get { return (string)_serviceObject.GetPropertyValue("StartName"); } }
+		public string StartPassword { get { return (string)_serviceObject.GetPropertyValue("StartPassword"); } }
+
+		public void Change(string DisplayName, string PathName, string StartMode, bool DesktopInteract, string StartName, string StartPassword) {
+			UInt32 ret;
+			ret = (UInt32)_serviceObject.InvokeMethod("Change", new Object[] {
+					DisplayName, //DisplayName
+					PathName, //PathName
+					16, //ServiceType (16 = own process)
+					1, //ErrorControl (1 = user is notified)
+					StartMode, //StartMode
+					DesktopInteract, //DesktopInteract
+					StartName, //StartName (null = LocalSystem)
+					StartPassword, //StartPassword
+					null, //LoadOrderGroup
+					null, //LoadOrderGroupDependencies
+					null //ServiceDependencies
+				});
+			if (ret != 0) throw new ManagementException("Could not change service (code " + ret.ToString() + ")");
+			Refresh();
+		}
+
+		public void Refresh() {
+			_serviceObject.Get();
+		}
+
+		public void Start() {
+			_serviceObject.InvokeMethod("StartService", null);
+			Refresh();
+		}
+		public void Stop() {
+			_serviceObject.InvokeMethod("StopService", null);
+			Refresh();
+		}
+
+		public bool Running {
+			get {
+				Refresh();
+				return (bool)_serviceObject.GetPropertyValue("Started");
+			}
+		}
+
+		public String State {
+			get {
+				Refresh();
+				return (String)_serviceObject.GetPropertyValue("State");
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Xml/PolicyFile.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using UCIS.Net;
+
+namespace UCIS.Xml {
+	public class XmlPolicyFile : XmlServer.IModule {
+		private string[] pHosts;
+		private string pPorts;
+
+		public XmlPolicyFile(string[] Hosts) : this(Hosts, null) { }
+		public XmlPolicyFile(string[] Hosts, int[] Ports) {
+			pHosts = Hosts;
+			if (Ports != null) {
+				pPorts = "";
+				foreach (int Port in Ports) {
+					pPorts += "," + Port.ToString();
+				}
+				pPorts = pPorts.Substring(1);
+			} else {
+				pPorts = null;
+			}
+		}
+
+		public void Accept(XmlSocket Socket, System.Xml.XmlDocument FirstMessage) {
+			Socket.WriterSettings.OmitXmlDeclaration = false;
+
+			Socket.WriteStartDocument();
+			Socket.WriteDocType("cross-domain-policy", null, "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd", null);
+			Socket.WriteStartElement("cross-domain-policy");
+
+			foreach (string Host in pHosts) {
+				Socket.WriteStartElement("allow-access-from");
+				Socket.WriteAttributeString("domain", Host);
+				if (pPorts != null) Socket.WriteAttributeString("to-ports", pPorts);
+				Socket.WriteEndElement();
+			}
+
+			Socket.WriteEndElement();
+			Socket.WriteEndDocument();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Xml/Server.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Xml;
+using UCIS.Net;
+
+namespace UCIS.Xml {
+	public class XmlServer : TCPServer.IModule {
+		public Dictionary<string, IModule> Modules = new Dictionary<string, IModule>(StringComparer.OrdinalIgnoreCase);
+
+		public bool Accept(TCPStream Stream) {
+			XmlSocket XSocket = new XmlSocket(Stream);
+			Stream.ReadTimeout = 5000;
+			XmlDocument FirstMessage = XSocket.ReadDocument();
+			if (FirstMessage == null) return true;
+			IModule module;
+			if (Modules.TryGetValue(FirstMessage.FirstChild.Name, out module)) {
+				module.Accept(XSocket, FirstMessage);
+			} else {
+				Console.WriteLine("XMLServer.Accept: Module not found: " + FirstMessage.FirstChild.Name);
+			}
+			return true;
+		}
+
+		public interface IModule {
+			void Accept(XmlSocket Socket, XmlDocument FirstMessage);
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Xml/Socket.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,197 @@
+using System;
+using System.Text;
+using System.IO;
+using System.Xml;
+
+namespace UCIS.Xml {
+	public class XmlSocket : XmlWriter {
+		protected Stream pStream;
+		protected XmlWriter pWriter;
+		protected XmlReaderSettings pXMLReaderSettings;// = new XmlReaderSettings();
+
+		public Stream BaseStream { get { return pStream; } }
+
+		public override XmlWriterSettings Settings { get { return WriterSettings; } }
+		public XmlWriterSettings WriterSettings { get; private set; }
+		public XmlReaderSettings ReaderSettings { get { return pXMLReaderSettings; } }
+
+		public XmlSocket(Stream Stream, Encoding Encoding) {
+			WriterSettings = new XmlWriterSettings();
+			WriterSettings.ConformanceLevel = ConformanceLevel.Document;
+			WriterSettings.NewLineHandling = NewLineHandling.Entitize;
+			WriterSettings.OmitXmlDeclaration = true;
+			WriterSettings.CheckCharacters = false;
+			WriterSettings.Encoding = Encoding;
+			WriterSettings.CloseOutput = false;
+
+			pXMLReaderSettings = new XmlReaderSettings();
+			pXMLReaderSettings.ConformanceLevel = ConformanceLevel.Document;
+			pXMLReaderSettings.CloseInput = true;
+			pXMLReaderSettings.IgnoreComments = true;
+			pXMLReaderSettings.IgnoreProcessingInstructions = true;
+			pXMLReaderSettings.IgnoreWhitespace = true;
+			pXMLReaderSettings.ValidationType = ValidationType.None;
+			pXMLReaderSettings.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None;
+			pXMLReaderSettings.CheckCharacters = false;
+
+			pStream = Stream;
+		}
+		public XmlSocket(Stream Stream) : this(Stream, new UTF8NoPreamble()) { }
+
+		public virtual MemoryStream ReadRawDocument() {
+			MemoryStream Buffer = new MemoryStream();
+			byte[] ByteBuffer = new byte[1];
+			int ByteCount = 0;
+			while (true) {
+				ByteCount = pStream.Read(ByteBuffer, 0, 1);
+				if (ByteCount == 0) {
+					throw new EndOfStreamException();
+				} else if (ByteBuffer[0] == 0) {
+					if (Buffer.Length > 0) break;
+				} else {
+					Buffer.WriteByte(ByteBuffer[0]);
+				}
+			}
+			Buffer.Flush();
+			Buffer.Seek(0, SeekOrigin.Begin);
+
+			return Buffer;
+		}
+		public virtual XmlDocument ReadDocument() {
+				MemoryStream Buffer = ReadRawDocument();
+				try {
+					XmlDocument Doc = new XmlDocument();
+					XmlReader XMLReader = XmlReader.Create(Buffer, pXMLReaderSettings);
+					Doc.Load(XMLReader);
+					XMLReader.Close();
+					return Doc;
+				} catch (Exception ex) {
+					Buffer.Seek(0, SeekOrigin.Begin);
+					throw new IOException("Could not parse XML document: \"" + Encoding.UTF8.GetString(Buffer.ToArray()) + "\"", ex);
+				}
+			}
+
+		protected virtual void CreateWriter() {
+			pWriter = XmlWriter.Create(pStream, WriterSettings);
+		}
+		protected virtual void CloseWriter() {
+			pWriter.Flush();
+			pWriter.Close();
+			pStream.WriteByte(0);
+			pStream.Flush();
+		}
+		public override void Flush() {
+			if (pWriter != null) {
+				pWriter.Flush();
+			} else {
+				pStream.Flush();
+			}
+		}
+		public override void Close() {
+			if (pWriter != null) {
+				pWriter.Close();
+				pWriter = null;
+			}
+			pStream.Close();
+		}
+
+		public void WriteDocument(XmlDocument Document) {
+			CreateWriter();
+			Document.WriteTo(pWriter);
+			CloseWriter();
+		}
+
+		public virtual void WriteRawDocument(string data) {
+			byte[] Buffer = WriterSettings.Encoding.GetBytes(data);
+			pStream.Write(Buffer, 0, Buffer.Length);
+			pStream.WriteByte(0);
+			pStream.Flush();
+		}
+
+		public override void WriteStartDocument() {
+			CreateWriter();
+			pWriter.WriteStartDocument();
+		}
+		public override void WriteStartDocument(bool standalone) {
+			CreateWriter();
+			pWriter.WriteStartDocument(standalone);
+		}
+		public override void WriteEndDocument() {
+			pWriter.WriteEndDocument();
+			CloseWriter();
+		}
+		public void WriteDocumentString(string localName, string value) {
+			WriteStartDocument();
+			WriteElementString(localName, value);
+			WriteEndDocument();
+		}
+
+		public override System.Xml.WriteState WriteState {
+			get {
+				if (pWriter != null) {
+					return pWriter.WriteState;
+				} else {
+					return WriteState.Start;
+				}
+			}
+		}
+
+		public override string LookupPrefix(string ns) {
+			return pWriter.LookupPrefix(ns);
+		}
+		public override void WriteBase64(byte[] buffer, int index, int count) {
+			pWriter.WriteBase64(buffer, index, count);
+		}
+		public override void WriteCData(string text) {
+			pWriter.WriteCData(text);
+		}
+		public override void WriteCharEntity(char ch) {
+			pWriter.WriteCharEntity(ch);
+		}
+		public override void WriteChars(char[] buffer, int index, int count) {
+			pWriter.WriteChars(buffer, index, count);
+		}
+		public override void WriteComment(string text) {
+			pWriter.WriteComment(text);
+		}
+		public override void WriteDocType(string name, string pubid, string sysid, string subset) {
+			pWriter.WriteDocType(name, pubid, sysid, subset);
+		}
+		public override void WriteEndAttribute() {
+			pWriter.WriteEndAttribute();
+		}
+		public override void WriteEndElement() {
+			pWriter.WriteEndElement();
+		}
+		public override void WriteEntityRef(string name) {
+			pWriter.WriteEntityRef(name);
+		}
+		public override void WriteFullEndElement() {
+			pWriter.WriteFullEndElement();
+		}
+		public override void WriteProcessingInstruction(string name, string text) {
+			pWriter.WriteProcessingInstruction(name, text);
+		}
+		public override void WriteRaw(char[] buffer, int index, int count) {
+			pWriter.WriteRaw(buffer, index, count);
+		}
+		public override void WriteRaw(string data) {
+			pWriter.WriteRaw(data);
+		}
+		public override void WriteStartAttribute(string prefix, string localName, string ns) {
+			pWriter.WriteStartAttribute(prefix, localName, ns);
+		}
+		public override void WriteStartElement(string prefix, string localName, string ns) {
+			pWriter.WriteStartElement(prefix, localName, ns);
+		}
+		public override void WriteString(string text) {
+			pWriter.WriteString(text);
+		}
+		public override void WriteSurrogateCharEntity(char lowChar, char highChar) {
+			pWriter.WriteSurrogateCharEntity(lowChar, highChar);
+		}
+		public override void WriteWhitespace(string ws) {
+			pWriter.WriteWhitespace(ws);
+		}
+	}
+}