void Run ()
		{
			var m = new Message ();

			for (; ; ) {
				try {
					m.Read (stream);
					ProcessMessage (m);
				}
				catch (Exception ex) {
					DebugPrint ("!! " + ex + "\n");
					throw;
				}
			}
		}
		void ProcessMessage (Message m)
		{

			//HACK
			DebugPrint ("Received message: " + ((ControlOp)m.Operation).ToString ());
			//DebugPrint ("Received message: " + (ControlOp)m.Operation);

			switch ((ControlOp)m.Operation) {
			case ControlOp.GetVariables:
				foreach (Variable v in variables) {
					SendVariable (v);
					DebugPrint ("Sent Variable " + v.Name);
					#if MF_FRAMEWORK_VERSION_V4_3                        
					Thread.Sleep (10); // Throttle
					#endif
				}
				break;
			case ControlOp.SetVariableValue: {
					var id = (int)m.Arguments[0];
					var val = m.Arguments[1];
					foreach (ServerVariable v in variables) {
						if (v.Id == id) {
							v.Value = val;
							DebugPrint ("Set " + v.Name + " = " + val);
							break;
						}
					}
				}
				break;
			case ControlOp.GetCommands:
				foreach (Command c in commands) {
					SendCommand (c);
					DebugPrint ("Sent Command " + c.Name);
					#if MF_FRAMEWORK_VERSION_V4_3
					Thread.Sleep (10); // Throttle
					#endif
				}
				break;
			case ControlOp.ExecuteCommand: {
					var id = (int)m.Arguments[0];
					var executionId = (int)m.Arguments[1];
					foreach (ServerCommand c in commands) {
						if (c.Id == id) {
							var result = c.Function ();
							SendCommandResult (c, executionId, result);
							DebugPrint ("Executed Command " + c.Name);
						}
					}
				}
				break;
			}
		}
		public async Task RunAsync (CancellationToken cancellationToken)
		{
			await GetVariablesAsync ();
			await GetCommandsAsync ();

			var m = new Message ();

			while (!cancellationToken.IsCancellationRequested) {

				await m.ReadAsync (stream);

				Debug.WriteLine ("Got message: " + (ControlOp)m.Operation + "(" + string.Join (", ", m.Arguments.Select (x => x.ToString ())) + ")");

				switch ((ControlOp)m.Operation) {
				case ControlOp.Variable:
					{
						var id = (int)m.Arguments [0];
						var v = variables.FirstOrDefault (x => x.Id == id);
						if (v == null) {
							var cv = new ClientVariable {
								Client = this,
								Id = id,
								Name = (string)m.Arguments [1],
								IsWriteable = (bool)m.Arguments [2],
							};
							cv.SetValue (m.Arguments [3]);
							v = cv;
							Schedule (() => variables.Add (v));
						}
					}
					break;
				case ControlOp.VariableValue:
					{
						var id = (int)m.Arguments [0];
						var cv = variables.FirstOrDefault (x => x.Id == id) as ClientVariable;
						if (cv != null) {
							var newVal = m.Arguments [1];
							Schedule (() => cv.SetValue (newVal));
						} else {
							await GetVariablesAsync ();
						}
					}
					break;
				case ControlOp.Command:
					{
						var id = (int)m.Arguments [0];
						var c = commands.FirstOrDefault (x => x.Id == id);
						if (c == null) {
							var cc = new Command {
								Id = id,
								Name = (string)m.Arguments [1],
							};
							c = cc;
							Schedule (() => commands.Add (c));
						}
					}
					break;
					//				default:
					//					Debug.WriteLine ("Ignoring message: " + m.Operation);
					//					break;
				}
			}
		}