protected virtual void AgentWorker( AgentWorkerStartInfo startInfo ) {
			if (object.ReferenceEquals(startInfo, null)) { throw new ArgumentNullException("startInfo"); }

			var agent = startInfo.Agent;
			if (object.ReferenceEquals(agent, null)) { throw new ArgumentNullException("startInfo.Agent"); }
			var agentInfo = startInfo.AgentUpdateInfo;
			if (object.ReferenceEquals(agent, null)) { throw new ArgumentNullException("startInfo.AgentUpdateInfo"); }
			var thread = startInfo.Thread;
			if (object.ReferenceEquals(agent, null)) { throw new ArgumentNullException("startInfo.Thread"); }

			var mainReset = thread.MainReset;
			var workerReset = thread.AgentReset;

			var currThreadName = System.Threading.Thread.CurrentThread.Name;

			Debug.WriteLine(string.Format("THREAD {0} STARTED", currThreadName));
			while (agentInfo.Stack > 0) {
				Debug.WriteLine(string.Format("THREAD {0} WAITS for reset event", currThreadName));
				workerReset.WaitOne();
				workerReset.Reset();

				System.Diagnostics.Debug.WriteLine(string.Format("Tick ({0}:{1}) >>>", agentInfo.Owner.DisplayHandle, agent.GetType().FullName));
				agent.Tick(agentInfo);
				System.Diagnostics.Debug.WriteLine(string.Format("<<< Tick ({0}:{1})", agentInfo.Owner.DisplayHandle, agent.GetType().FullName));

				workerReset.Reset();
				mainReset.Set();
			}
			this.CrashAgent(agent);

			System.Diagnostics.Debug.WriteLine(string.Format("THREAD {0} FINISHED", currThreadName));
		}
		public virtual void ProcessTick() {
			this.TickNumber++;
			foreach (DeckBase deck in this.Players.Values) {
				deck.TickNumber = this.TickNumber;
			}

			var newlyLaunchedAgents = this.Agents.Keys.Except(this.Processes.Keys).ToList();
			foreach (var __newlyLaunchedAgent in newlyLaunchedAgents) {
				var newlyLaunchedAgent = __newlyLaunchedAgent;
				var agentInfo = this.Agents[newlyLaunchedAgent];

				var thread = new System.Threading.Thread(this.AgentWorker);
				thread.IsBackground = true;
				thread.Priority = System.Threading.ThreadPriority.Lowest;
				thread.Name = string.Format("{0}({1}({2}))"
					, agentInfo.Owner.DisplayHandle
					, newlyLaunchedAgent.GetType().FullName
					, agentInfo.Level);

				var threadEx = new AgentThreadInfo(thread);
				this.Processes.Add(newlyLaunchedAgent, threadEx);
			}

			var rnd = new Random();
			foreach (var kpProc in this.Processes.OrderBy(p => rnd.Next())) {
				var agent = kpProc.Key;
				var thread = kpProc.Value;
				IAgentUpdateInfo agentInfo;
				this.Agents.TryGetValue(agent, out agentInfo);
				if (null == agentInfo) { continue; /* agent crashed or was recalled */ }

				var mainReset = thread.MainReset;
				var workerReset = thread.AgentReset;

				if (false == thread.Thread.IsAlive) {
					workerReset.Reset();
					var startInfo = new AgentWorkerStartInfo(agent, agentInfo, thread);
					thread.Thread.Start(startInfo);
				}

				mainReset.Reset();
				workerReset.Set();
				mainReset.WaitOne();
			}
		}