← Back to team overview

nrtb-core team mailing list archive

[Merge] lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb

 

Rick Stovall has proposed merging lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb.

Requested reviews:
  NRTB Core (nrtb-core): code

For more details, see:
https://code.launchpad.net/~fpstovall/nrtb/D_tech_demos/+merge/149745

This branch includes the tech demos we agreed were needed before proceeding with the main alpha thrust in D. All are complete and functional now.
-- 
https://code.launchpad.net/~fpstovall/nrtb/D_tech_demos/+merge/149745
Your team NRTB Core is requested to review the proposed merge of lp:~fpstovall/nrtb/D_tech_demos into lp:nrtb.
=== added directory 'D_lang/testing/candidate_libs'
=== added file 'D_lang/testing/candidate_libs/splat.d'
--- D_lang/testing/candidate_libs/splat.d	1970-01-01 00:00:00 +0000
+++ D_lang/testing/candidate_libs/splat.d	2013-02-21 03:06:20 +0000
@@ -0,0 +1,1754 @@
+/*
+	Copyright (C) 2006-2007 Christopher E. Miller
+	
+	This software is provided 'as-is', without any express or implied
+	warranty.  In no event will the authors be held liable for any damages
+	arising from the use of this software.
+	
+	Permission is granted to anyone to use this software for any purpose,
+	including commercial applications, and to alter it and redistribute it
+	freely, subject to the following restrictions:
+	
+	1. The origin of this software must not be misrepresented; you must not
+	   claim that you wrote the original software. If you use this software
+	   in a product, an acknowledgment in the product documentation would be
+	   appreciated but is not required.
+	2. Altered source versions must be plainly marked as such, and must not be
+	   misrepresented as being the original software.
+	3. This notice may not be removed or altered from any source distribution.
+*/
+
+/** $(B ) Splat: the socket platform with the lame name. It's full of puns, but it runs!
+	<a href="http://www.dprogramming.com/splat.php";>Download Splat</a>.
+	Version 0.7.
+	For both Phobos and Tango; tested with Phobos and Tango 0.99.2.
+**/
+module splat;
+
+
+private
+{
+	version(Windows)
+	{
+		version(Tango)
+		{
+			import tango.sys.win32.UserGdi;
+		}
+		else
+		{
+			import std.c.windows.windows;
+		}
+	}
+	
+	
+	version(Tango)
+	{
+		import tango.core.Type;
+		
+		alias tango.core.Type.Time spdTime;
+		alias tango.core.Type.Time.TicksPerSecond spdTICKS_PER_SECOND;
+		
+		
+		import tango.util.time.Clock;
+		
+		alias Clock.now spdGetCurrentUtcTime;
+		
+		
+		import tango.net.Socket;
+		
+		alias tango.net.Socket.NetHost spdInternetHost;
+		
+		alias tango.net.Socket.IPv4Address spdInternetAddress;
+		
+		alias tango.net.Socket.timeval spdTimeval;
+		
+		struct spdMyTimeval
+		{
+			int seconds;
+			int microseconds;
+		}
+		
+		
+		import tango.core.Thread;
+	}
+	else
+	{
+		import std.date;
+		
+		alias std.date.d_time spdTime;
+		alias std.date.TicksPerSecond spdTICKS_PER_SECOND;
+		alias std.date.getUTCtime spdGetCurrentUtcTime;
+		
+		
+		import std.socket;
+		
+		alias std.socket.InternetHost spdInternetHost;
+		
+		alias std.socket.InternetAddress spdInternetAddress;
+		
+		alias std.socket.timeval spdMyTimeval;
+		
+		alias std.socket.timeval spdTimeval;
+		
+		
+		import std.thread;
+	}
+	
+	
+	debug(splat)
+	{
+		version(Tango)
+			import tango.stdc.stdio;
+		else
+			import std.c.stdio;
+	}
+}
+
+static assert(spdMyTimeval.sizeof == spdTimeval.sizeof);
+
+
+/**
+	Run the event loop; wait for timer and socket events.
+	Exceptions that occur in event callbacks break out of run.
+**/
+// It is NOT safe to call run() before a previous call to run() returns.
+void run()
+{
+	/+
+	static bool _running = false;
+	if(_running)
+		return; // ?
+	_running = true;
+	scope(exit)
+		_running = false;
+	+/
+	
+	_texit = false;
+	
+	Timer tn;
+	spdMyTimeval* ptv;
+	spdMyTimeval tv;
+	spdTime dnow;
+	SocketSet reads = new SocketSet();
+	SocketSet writes = new SocketSet();
+	int i;
+	bool dotimer = false;
+	
+	for(;;)
+	{
+		tn = _tnext();
+		
+		version(Windows)
+		{
+			if(!_tallEvents.length)
+			{
+				no_socket_events:
+				DWORD ms = INFINITE;
+				if(tn)
+				{
+					dnow = spdGetCurrentUtcTime();
+					if(tn._talarm <= dnow)
+						goto timedout;
+					ms = _tticksToMs(cast(spdTime)(tn._talarm - dnow));
+				}
+				
+				if(INFINITE == ms)
+				{
+					if(_areHosts())
+						ms = 200;
+				}
+				
+				debug(splat)
+				{
+					if(INFINITE != ms)
+						printf("  {SLEEP} %lu ms\n", cast(uint)ms);
+					//else
+					//	printf("  {SLEEP} infinite\n");
+				}
+				
+				Sleep(ms);
+				goto timedout;
+			}
+		}
+		
+		ptv = null;
+		if(tn)
+		{
+			debug(splattimer)
+				printf("splattimer: diff = %d; dotimer = %s\n",
+					cast(int)(dnow - tn._talarm),
+					dotimer ? "true".ptr : "false".ptr);
+			
+			if(tn._talarm <= dnow)
+			{
+				version(Windows)
+				{
+					assert(_tallEvents.length);
+				}
+				else
+				{
+					if(!_tallEvents.length)
+						goto timedout;
+				}
+				if(dotimer)
+					goto timedout;
+				dotimer = true; // Do timer next time around.
+				tv.seconds = 0;
+				tv.microseconds = 0;
+			}
+			else
+			{
+				dnow = spdGetCurrentUtcTime();
+				_tticksToTimeval(tn._talarm - dnow, &tv);
+				if(tv.microseconds < 0)
+					tv.microseconds = 0;
+				//if(tv.microseconds > 32767)
+				//	tv.microseconds = 32767;
+				if(tv.seconds < 0)
+					tv.seconds = 0;
+				if(tv.seconds > 60)
+					tv.seconds = 60;
+				
+				if(_areHosts())
+				{
+					if(tv.seconds || tv.microseconds > 200_000)
+					{
+						tv.seconds = 0;
+						tv.microseconds = 200_000;
+					}
+				}
+			}
+			ptv = &tv;
+		}
+		else
+		{
+			debug(splattimer)
+				printf("splattimer: no timers\n");
+			
+			if(_areHosts())
+			{
+				tv.seconds = 0;
+				tv.microseconds = 200_000;
+				ptv = &tv;
+			}
+		}
+		
+		reads.reset();
+		writes.reset();
+		
+		uint numadds = 0;
+		foreach(AsyncSocket sock; _tallEvents)
+		{
+			//debug
+			debug(splat)
+			{
+				if(!sock.isAlive())
+				{
+					debug(splat)
+					{
+						printf("Splat warning: dead socket still waiting for events\n");
+						fflush(stdout);
+					}
+					//continue;
+				}
+			}
+			
+			if(((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ))
+				|| ((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT))
+				|| ((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE)))
+			{
+				reads.add(sock);
+				numadds++;
+			}
+			
+			if(((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE))
+				|| ((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT)))
+			{
+				writes.add(sock);
+				numadds++;
+			}
+		}
+		
+		if(_texit)
+			return;
+		
+		version(Windows)
+		{
+			if(!numadds)
+				goto no_socket_events;
+			
+			//assert(reads.count || writes.count);
+		}
+		
+		debug(splat)
+		{
+			if(ptv)
+			{
+				if(0 != ptv.seconds || 0 != ptv.microseconds)
+					printf("  {SELECT} %lu secs, %lu microsecs\n", cast(uint)ptv.seconds, cast(uint)ptv.microseconds);
+				//else
+				//	printf("  {SELECT} 0\n");
+			}
+			//else
+			//{
+			//	printf("  {SELECT} infinite\n");
+			//}
+		}
+		
+		debug(splatselect)
+			printf("Socket.select(%u sockets%s)\n", numadds,
+				ptv ? (((0 != ptv.seconds || 0 != ptv.microseconds)) ? ", timeout".ptr : ", 0 timeout") : ", infinite-wait".ptr);
+		i = Socket.select(reads, writes, null, cast(spdTimeval*)ptv);
+		switch(i)
+		{
+			case -1: // Interruption.
+				continue; // ?
+			
+			case 0: // Timeout.
+				goto timedout;
+			
+			default: // Socket event(s).
+				foreach(AsyncSocket sock; _tallEvents)
+				{
+					if(_texit)
+						return;
+					
+					//if(!sock.isAlive())
+					//	continue;
+					
+					if(reads.isSet(sock))
+					{
+						if((sock._events & EventType.READ) && !(sock._events & EventType._CANNOT_READ))
+						{
+							switch(sock._peekreceiveclose())
+							{
+								case 0: // Close.
+									if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+									{
+										goto got_close;
+									}
+									else
+									{
+										//sock._events |= EventType._CANNOT_READ;
+										sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+										//sock._tgotEvent(EventType.READ, 0); // Should this be an error?
+									}
+									break;
+								case -1: // Error.
+									if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+									{
+										//sock._events |= EventType._CANNOT_READ;
+										sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+										sock._tgotEvent(EventType.CLOSE, -1); // ?
+									}
+									else
+									{
+										//sock._events |= EventType._CANNOT_READ;
+										sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+										sock._tgotEvent(EventType.READ, -1);
+									}
+									break;
+								default: // Good.
+									sock._events |= EventType._CANNOT_READ;
+									sock._tgotEvent(EventType.READ, 0);
+							}
+						}
+						else if((sock._events & EventType.CLOSE) && !(sock._events & EventType._CANNOT_CLOSE))
+						{
+							switch(sock._peekreceiveclose())
+							{
+								case 0: // Close.
+									got_close:
+									//sock._events |= EventType._CANNOT_CLOSE;
+									sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+									//writes.remove(sock); // ?
+									sock._tgotEvent(EventType.CLOSE, 0);
+									break;
+								case -1: // Error.
+									//sock._events |= EventType._CANNOT_CLOSE;
+									sock._events |= EventType._CANNOT_CLOSE | EventType._CANNOT_READ; // ?
+									//writes.remove(sock); // ?
+									sock._tgotEvent(EventType.CLOSE, -1);
+									break;
+								default: ;
+							}
+						}
+						
+						if((sock._events & EventType.ACCEPT) && !(sock._events & EventType._CANNOT_ACCEPT))
+						{
+							sock._events |= EventType._CANNOT_ACCEPT;
+							sock._tgotEvent(EventType.ACCEPT, 0);
+						}
+						
+						continue; // Checking for writability (otherwise next) on a closed socket (from any above event) is problematic.
+					}
+					
+					//if(_texit)
+					//	return;
+					
+					if(writes.isSet(sock))
+					{
+						if((sock._events & EventType.CONNECT) && !(sock._events & EventType._CANNOT_CONNECT))
+						{
+							sock._events |= EventType._CANNOT_CONNECT;
+							sock._tgotEvent(EventType.CONNECT, 0);
+						}
+						
+						if((sock._events & EventType.WRITE) && !(sock._events & EventType._CANNOT_WRITE))
+						{
+							sock._events |= EventType._CANNOT_WRITE;
+							sock._tgotEvent(EventType.WRITE, 0);
+						}
+					}
+				}
+				//continue;
+				goto do_hosts;
+		}
+		
+		// Check timers..
+		timedout: ;
+		dotimer = false;
+		_tdotimers();
+		
+		// Check resolved hosts..
+		do_hosts:
+		GetHost gh;
+		while(null !is (gh = _tnextDoneHost()))
+		{
+			gh._tgotEvent();
+			
+			if(_texit)
+				return;
+		}
+		
+		if(_texit)
+			return;
+	}
+}
+
+
+/// Causes run() to return as soon as it can.
+void exitLoop()
+{
+	_texit = true;
+}
+
+
+private void _tdotimers()
+{
+	size_t nalarms;
+	Timer[4] talarms;
+	spdTime dnow;
+	Timer tn;
+	dnow = spdGetCurrentUtcTime();
+	for(tn = _tfirst; tn; tn = tn._tnext)
+	{
+		if(dnow >= tn._talarm)
+		{
+			if(nalarms < talarms.length)
+				talarms[nalarms] = tn;
+			nalarms++;
+		}
+	}
+	Timer[] nowalarm;
+	if(nalarms <= talarms.length)
+	{
+		nowalarm = talarms[0 .. nalarms];
+	}
+	else
+	{
+		nowalarm = new Timer[nalarms];
+		nalarms = 0;
+		for(tn = _tfirst; tn; tn = tn._tnext)
+		{
+			if(dnow >= tn._talarm)
+			{
+				nowalarm[nalarms] = tn;
+				nalarms++;
+			}
+		}
+		assert(nowalarm.length == nalarms);
+	}
+	
+	foreach(Timer t; nowalarm)
+	{
+		if(_texit)
+			return;
+		
+		if(t._talarm != t._TALARM_INIT) // Make sure not removed by some other timer event.
+		{
+			t._talarm = cast(spdTime)(dnow + t._ttimeout); // Also update alarm time BEFORE in case of exception (could cause rapid fire otherwise).
+			t._tgotAlarm();
+			if(t._talarm != t._TALARM_INIT) // Maybe removed itself.
+			{
+				// Set new alarm after this alarm due to possible delay AND possible updated timeout/interval.
+				dnow = spdGetCurrentUtcTime(); // In case time lapses in some other timer event.
+				t._talarm = cast(spdTime)(dnow + t._ttimeout);
+			}
+		}
+	}
+}
+
+
+/// Timers; alarms (timeout events) depend on run().
+class Timer
+{
+	/// Property: get and set the timer _interval in milliseconds.
+	final void interval(uint iv) // setter
+	{
+		iv = cast(uint)_tmsToTicks(iv);
+		if(!iv)
+			iv = 1;
+		if(iv != _ttimeout)
+		{
+			_ttimeout = iv;
+			
+			if(_talarm != _TALARM_INIT)
+			{
+				stop();
+				start();
+			}
+		}
+	}
+	
+	/// ditto
+	final uint interval() // getter
+	{
+		return _tticksToMs(cast(spdTime)_ttimeout);
+	}
+	
+	
+	/// Start this timer.
+	final void start()
+	{
+		if(_talarm)
+			return;
+		
+		assert(_ttimeout > 0);
+		
+		_tadd(this);
+		
+		debug(splat)
+		{
+			printf("  {ADDTIMER:%p} %lu ms\n", cast(void*)this, interval);
+		}
+	}
+	
+	
+	/// Stop this timer.
+	final void stop()
+	{
+		if(_talarm)
+		{
+			_tremove(this);
+			
+			debug(splat)
+			{
+				printf("  {DELTIMER:%p} %lu ms\n", cast(void*)this, interval);
+			}
+		}
+	}
+	
+	
+	/// Override to be notified when the time expires. Alarms continue until stop().
+	void onAlarm()
+	{
+		if(_tick)
+			_tick(this);
+	}
+	
+	
+	/// Construct a timer; can take a delegate that is called back automatically on an alarm.
+	this()
+	{
+		_ttimeout = cast(uint)_tmsToTicks(100);
+	}
+	
+	/// ditto
+	this(void delegate(Timer) dg)
+	{
+		this();
+		this._tick = dg;
+	}
+	
+	
+	private:
+	const spdTime _TALARM_INIT = cast(spdTime)0;
+	spdTime _talarm = _TALARM_INIT; // Time when next event is alarmed.
+	//spdTime _ttimeout; // Ticks per timeout.
+	uint _ttimeout; // Ticks per timeout.
+	Timer _tprev, _tnext;
+	void delegate(Timer) _tick;
+	
+	
+	void _tgotAlarm()
+	{
+		debug(splat)
+		{
+			printf("  {TIMER:%p}\n", cast(void*)this);
+		}
+		
+		onAlarm();
+	}
+}
+
+
+// Can be OR'ed.
+/// Socket event flags.
+enum EventType
+{
+	NONE = 0, ///
+	
+	READ =       0x1, ///
+	WRITE =      0x2, /// ditto
+	//OOB =        0x4, /// ditto
+	ACCEPT =     0x8, /// ditto
+	CONNECT =    0x10, /// ditto
+	CLOSE =      0x20, /// ditto
+	
+	_CANNOT_READ = READ << 16, // package
+	_CANNOT_WRITE = WRITE << 16, // package
+	//_CANNOT_OOB = OOB << 16, // package
+	_CANNOT_ACCEPT = ACCEPT << 16, // package
+	_CANNOT_CONNECT = CONNECT << 16, // package
+	_CANNOT_CLOSE = CLOSE << 16, // package
+}
+
+private EventType _tEventType_ALL = EventType.READ | EventType.WRITE /+ | EventType.OOB +/
+	| EventType.ACCEPT | EventType.CONNECT | EventType.CLOSE;
+private EventType _tEventType_ALLREADS = EventType.READ | EventType.ACCEPT | EventType.CLOSE;
+private EventType _tEventType_ALLWRITES = EventType.WRITE | EventType.CONNECT;
+
+
+/**
+	Callback type for socket events.
+	Params:
+		sock = the socket
+		type = which event; will be only one of the event flags.
+		err = an error code, or 0 if successful.
+**/
+alias void delegate(Socket sock, EventType type, int err) RegisterEventCallback;
+
+
+/// Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket.
+class AsyncSocket: Socket
+{
+	version(Tango)
+	{
+		this(AddressFamily family, SocketType type, ProtocolType protocol, bool create = true)
+		{
+			super(family, type, protocol, create);
+			super.blocking = false;
+		}
+	}
+	else
+	{
+		this(AddressFamily af, SocketType type, ProtocolType protocol)
+		{
+			super(af, type, protocol);
+			super.blocking = false;
+		}
+		
+		
+		this(AddressFamily af, SocketType type)
+		{
+			super(af, type);
+			super.blocking = false;
+		}
+		
+		
+		this(AddressFamily af, SocketType type, char[] protocolName)
+		{
+			super(af, type, protocolName);
+			super.blocking = false;
+		}
+	}
+	
+	
+	/**
+		Registers a callback for specified socket events.
+		One or more type flags may be used, or NONE to cancel all.
+		Calling this twice on the same socket cancels out previously registered events for the socket.
+	**/
+	// Requires run() loop.
+	void event(EventType events, RegisterEventCallback callback)
+	{
+		this.blocking = false;
+		
+		this._events = EventType.NONE;
+		
+		if(!(events & (_tEventType_ALLREADS | _tEventType_ALLWRITES)))
+			return;
+		
+		if(isAlive()) // Alive socket already connected or never will.
+			this._events |= EventType._CANNOT_CONNECT;
+		
+		if(events & EventType.ACCEPT)
+			events &= ~(EventType.READ | EventType.CLOSE); // Issues in select() if accept and these set.
+		
+		this._events = events | _tEventType_ALL;
+		this._callback = callback;
+		
+		_tallEvents[this.handle] = this;
+	}
+	
+	
+	version(Tango)
+	{
+		alias fileHandle handle;
+	}
+	
+	
+	// For use with accepting().
+	protected this()
+	{
+	}
+	
+	
+	version(Tango)
+	{
+		override Socket accept()
+		{
+			return accept(new AsyncSocket());
+		}
+		
+		// Overload.
+		//alias Socket.accept accept; // Don't overload since I override this one below..
+	}
+	else
+	{
+		protected override AsyncSocket accepting()
+		{
+			return new AsyncSocket();
+		}
+	}
+	
+	
+	version(Tango)
+		private const bool _IS_TANGO = true;
+	else
+		private const bool _IS_TANGO = false;
+	
+	static if(_IS_TANGO && is(typeof(&this.detach)))
+	{
+		override void detach()
+		{
+			_events = EventType.NONE;
+			_tallEvents.remove(this.handle);
+			return super.detach();
+		}
+	}
+	else
+	{
+		override void close()
+		{
+			_events = EventType.NONE;
+			_tallEvents.remove(this.handle);
+			return super.close();
+		}
+	}
+	
+	
+	override bool blocking() // getter
+	{
+		return false;
+	}
+	
+	
+	override void blocking(bool byes) // setter
+	{
+		if(byes)
+			assert(0);
+	}
+	
+	
+	version(Tango)
+	{
+		override int receive(void[] buf, SocketFlags flags = SocketFlags.NONE)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receive(buf, flags);
+		}
+		
+		override int receiveFrom(void[] buf, SocketFlags flags, Address from)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, flags, from);
+		}
+		
+		override int receiveFrom(void[] buf, Address from)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, from);
+		}
+		
+		override int receiveFrom(void[] buf, SocketFlags flags = SocketFlags.NONE)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, flags);
+		}
+		
+		
+		override int send(void[] buf, SocketFlags flags = SocketFlags.NONE)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.send(buf, flags);
+		}
+		
+		override int sendTo(void[] buf, SocketFlags flags, Address to)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, flags, to);
+		}
+		
+		override int sendTo(void[] buf, Address to)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, to);
+		}
+		
+		override int sendTo(void[] buf, SocketFlags flags = SocketFlags.NONE)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, flags);
+		}
+	}
+	else
+	{
+		override int receive(void[] buf, SocketFlags flags)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receive(buf, flags);
+		}
+		
+		override int receive(void[] buf)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receive(buf);
+		}
+		
+		override int receiveFrom(void[] buf, SocketFlags flags, out Address from)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, flags, from);
+		}
+		
+		override int receiveFrom(void[] buf, out Address from)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, from);
+		}
+		
+		override int receiveFrom(void[] buf, SocketFlags flags)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf, flags);
+		}
+		
+		override int receiveFrom(void[] buf)
+		{
+			_events &= ~EventType._CANNOT_READ;
+			return super.receiveFrom(buf);
+		}
+		
+		
+		override int send(void[] buf, SocketFlags flags)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.send(buf, flags);
+		}
+		
+		override int send(void[] buf)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.send(buf);
+		}
+		
+		override int sendTo(void[] buf, SocketFlags flags, Address to)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, flags, to);
+		}
+		
+		override int sendTo(void[] buf, Address to)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, to);
+		}
+		
+		override int sendTo(void[] buf, SocketFlags flags)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf, flags);
+		}
+		
+		override int sendTo(void[] buf)
+		{
+			_events &= ~EventType._CANNOT_WRITE;
+			return super.sendTo(buf);
+		}
+	}
+	
+	
+	version(Tango)
+	{
+		override Socket accept(Socket s)
+		{
+			_events &= ~EventType._CANNOT_ACCEPT;
+			return super.accept(s);
+		}
+	}
+	else
+	{
+		override Socket accept()
+		{
+			_events &= ~EventType._CANNOT_ACCEPT;
+			return super.accept();
+		}
+	}
+	
+	
+	private:
+	
+	EventType _events;
+	RegisterEventCallback _callback;
+	
+	
+	void _cando(EventType can)
+	{
+		_events &= ~(can << 16);
+	}
+	
+	void _cannotdo(EventType cannot)
+	{
+		_events |= (cannot << 16);
+	}
+	
+	bool _ifcando(EventType ifcan)
+	{
+		return !(_events & (ifcan << 16));
+	}
+	
+	
+	int _peekreceiveclose()
+	{
+		byte[1] onebyte;
+		return Socket.receive(onebyte, SocketFlags.PEEK);
+	}
+	
+	
+	void _tgotEvent(EventType type, int err)
+	{
+		debug(splat)
+		{
+			if(type == EventType.READ)
+				printf("  {READ:%p}\n", cast(void*)this);
+			else if(type == EventType.WRITE)
+				printf("  {WRITE:%p}\n", cast(void*)this);
+			else if(type == EventType.CONNECT)
+				printf("  {CONNECT:%p}\n", cast(void*)this);
+			else if(type == EventType.CLOSE)
+				printf("  {CLOSE:%p}\n", cast(void*)this);
+			else if(type == EventType.ACCEPT)
+				printf("  {ACCEPT:%p}\n", cast(void*)this);
+		}
+		
+		if(_callback)
+			_callback(this, type, err);
+	}
+}
+
+
+/// Asynchronous TCP socket shortcut.
+class AsyncTcpSocket: AsyncSocket
+{
+	///
+	this(AddressFamily family)
+	{
+		super(family, SocketType.STREAM, ProtocolType.TCP);
+	}
+	
+	/// ditto
+	this()
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+	}
+	
+	/// ditto
+	// Shortcut.
+	this(EventType events, RegisterEventCallback eventCallback)
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+		event(events, eventCallback);
+	}
+	
+	/// ditto
+	// Shortcut.
+	this(Address connectTo, EventType events, RegisterEventCallback eventCallback)
+	{
+		this(connectTo.addressFamily());
+		event(events, eventCallback);
+		connect(connectTo);
+	}
+}
+
+
+/// Asynchronous UDP socket shortcut.
+class AsyncUdpSocket: AsyncSocket
+{
+	///
+	this(AddressFamily family)
+	{
+		super(family, SocketType.DGRAM, ProtocolType.UDP);
+	}
+	
+	/// ditto
+	this()
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+	}
+	
+	/// ditto
+	// Shortcut.
+	this(EventType events, RegisterEventCallback eventCallback)
+	{
+		this(cast(AddressFamily)AddressFamily.INET);
+		event(events, eventCallback);
+	}
+}
+
+
+private void _tgetHostErr()
+{
+	throw new Exception("Get host failure");
+}
+
+
+/**
+	Callback type for host resolve event.
+	Params:
+		inetHost = the InternetHost/NetHost of the resolved host, or null.
+		err = an error code, or 0 if successful; if 0, inetHost will be null.
+**/
+alias void delegate(spdInternetHost inetHost, int err) GetHostCallback;
+
+
+/// Returned from asyncGetHost functions.
+class GetHost
+{
+	/// Cancel the get-host operation.
+	void cancel()
+	{
+		_tcallback = null;
+	}
+	
+	
+	private:
+	GetHostCallback _tcallback;
+	GetHost _tnext;
+	spdInternetHost _tinetHost;
+	
+	bool _tbyname; // false == by addr
+	union
+	{
+		uint _taddr;
+		char[] _tname;
+	}
+	
+	
+	void _tgotEvent()
+	{
+		if(!_tcallback) // If cancel().
+			return;
+		
+		if(!_tinetHost)
+		{
+			_tcallback(null, -1); // ?
+			return;
+		}
+		
+		_tcallback(_tinetHost, 0);
+	}
+	
+	
+	this()
+	{
+	}
+}
+
+
+/// Asynchronously resolve host information from a hostname; the callback depends on run().
+GetHost asyncGetHostByName(char[] name, GetHostCallback callback)
+{
+	GetHost gh;
+	gh = new GetHost;
+	version(NO_THREADS)
+	{
+		spdInternetHost ih;
+		ih = new spdInternetHost;
+		if(ih.getHostByName(name))
+		{
+			gh.inetHost = ih;
+		}
+	}
+	else
+	{
+		gh._tcallback = callback;
+		gh._tbyname = true;
+		gh._tname = name;
+		_tgethost(gh);
+	}
+	return gh;
+}
+
+
+/// Asynchronously resolve host information from an IPv4 address; the callback depends on run().
+GetHost asyncGetHostByAddr(uint addr, GetHostCallback callback)
+{
+	GetHost gh;
+	gh = new GetHost;
+	version(NO_THREADS)
+	{
+		spdInternetHost ih;
+		ih = new spdInternetHost;
+		if(ih.getHostByAddr(addr))
+		{
+			gh.inetHost = ih;
+		}
+	}
+	else
+	{
+		gh._tcallback = callback;
+		gh._tbyname = false;
+		gh._taddr = addr;
+		_tgethost(gh);
+	}
+	return gh;
+}
+
+/// ditto
+GetHost asyncGetHostByAddr(char[] addr, GetHostCallback callback)
+{
+	uint uiaddr;
+	uiaddr = spdInternetAddress.parse(addr);
+	if(spdInternetAddress.ADDR_NONE == uiaddr)
+		_tgetHostErr();
+	return asyncGetHostByAddr(uiaddr, callback);
+}
+
+
+version = THSLEEP;
+
+
+version(THSLEEP)
+{
+	version(Windows)
+	{
+		private void _tthsleep()
+		{
+			Sleep(200); // 0.2 secs.
+		}
+	}
+	else
+	{
+		private extern(C) int usleep(uint microseconds);
+		
+		private void _tthsleep()
+		{
+			usleep(200_000); // 0.2 secs.
+		}
+	}
+}
+
+
+private void _tgethost(GetHost gh)
+{
+	debug(splat)
+	{
+		printf("  {GETHOST:%p}\n", cast(void*)gh);
+	}
+	
+	//synchronized
+	{
+		gh._tnext = null;
+		
+		if(!_ththread)
+		{
+			//printf("GETHOST:newthread\n");
+			version(Tango)
+				_ththread = new Thread(&_ththreadproc);
+			else
+				_ththread = new Thread(&_ththreadproc, null);
+			_thnext = _thaddto = gh;
+			_ththread.start();
+			return;
+		}
+		
+		synchronized(_ththread)
+		{
+			if(!_thaddto)
+			{
+				//printf("GETHOST:!_thaddto\n");
+				version(SPLAT_HACK_PRINTF)
+					printf(""); // Without this, the thread never sees this host.
+				_thnext = _thaddto = gh;
+				
+				version(THSLEEP)
+				{
+				}
+				else
+				{
+					debug(splat)
+					{
+						printf("  {RESUMING:_ththreadproc}\n");
+					}
+					
+					_ththread.resume();
+				}
+			}
+			else
+			{
+				//printf("GETHOST:_thaddto\n");
+				_thaddto._tnext = gh;
+				_thaddto = gh;
+			}
+		}
+	}
+}
+
+
+private void _dothreadproc()
+{
+	GetHost gh;
+	spdInternetHost ih;
+	for(;;)
+	{
+		//synchronized(_ththread)
+		volatile
+		{
+			gh = _thnext;
+		}
+		
+		if(!gh)
+		{
+			version(THSLEEP)
+			{
+				_tthsleep();
+			}
+			else
+			{
+				debug(splat)
+				{
+					printf("  {PAUSE:_ththreadproc}\n");
+				}
+				
+				_ththread.pause();
+				
+				debug(splat)
+				{
+					printf("  {RESUMED:_ththreadproc}\n");
+				}
+			}
+			continue;
+		}
+		
+		if(gh._tcallback) // If not cancel()..
+		{
+			try
+			{
+				ih = new spdInternetHost;
+				if(gh._tbyname)
+				{
+					if(ih.getHostByName(gh._tname))
+						gh._tinetHost = ih;
+				}
+				else // byaddr
+				{
+					if(ih.getHostByAddr(gh._taddr))
+						gh._tinetHost = ih;
+				}
+				
+				debug(splat)
+				{
+					printf("  {GOTHOST:%p} %s\n", cast(void*)gh, gh._tinetHost ? "true".ptr : "false".ptr);
+				}
+			}
+			catch
+			{
+			}
+		}
+		
+		_thpn(gh);
+	}
+}
+
+
+version(Tango)
+{
+	/+
+	private _ththreadproc()
+	{
+		_dothreadproc();
+	}
+	+/
+	alias _dothreadproc _ththreadproc;
+}
+else
+{
+	private int _ththreadproc(void* foo)
+	{
+		_dothreadproc();
+		return 0;
+	}
+}
+
+
+// GDC 0.19 segfaults if this isn't in a function; might have to do with synchronized() in a loop.
+private void _thpn(GetHost gh)
+{
+	synchronized(_ththread)
+	{
+		assert(gh is _thnext);
+		
+		debug(splat)
+		{
+			printf("  {DONEHOST:%p}\n", cast(void*)gh);
+		}
+		
+		_thnext = _thnext._tnext;
+		if(!_thnext)
+			_thaddto = null;
+		
+		gh._tnext = null;
+		if(_thfinlast)
+			_thfinlast._tnext = gh;
+		else
+			_thfinnext = gh;
+		_thfinlast = gh;
+	}
+}
+
+
+private GetHost _tnextDoneHost()
+{
+	GetHost gh;
+	
+	volatile gh = _thfinnext;
+	if(!gh)
+		return null;
+	
+	synchronized(_ththread)
+	{
+		gh = _thfinnext;
+		if(gh)
+		{
+			_thfinnext = _thfinnext._tnext;
+			if(!_thfinnext)
+				_thfinlast = null;
+			gh._tnext = null;
+		}
+	}
+	
+	return gh;
+}
+
+
+private bool _areHosts()
+{
+	return _thnext || _thfinnext;
+}
+
+
+/// Buffering socket I/O.
+class SocketQueue
+{
+	///
+	this(Socket sock)
+	in
+	{
+		assert(sock !is null);
+	}
+	body
+	{
+		this.sock = sock;
+	}
+	
+	
+	/// Property: get the socket of this queue.
+	final Socket socket() // getter
+	{
+		return sock;
+	}
+	
+	
+	/// Resets the buffers.
+	void reset()
+	{
+		writebuf = null;
+		readbuf = null;
+	}
+	
+	
+	/+
+	// DMD 0.92 says error: function toString overrides but is not covariant with toString
+	override char[] toString()
+	{
+		return cast(char[])peek();
+	}
+	+/
+	
+	
+	/// Peek at some or all of the received data but leave it in the queue. May return less than requested.
+	void[] peek()
+	{
+		return readbuf[0 .. rpos];
+	}
+	
+	/// ditto
+	void[] peek(uint len)
+	{
+		if(len >= rpos)
+			return peek();
+		
+		return readbuf[0 .. len];
+	}
+	
+	
+	/// Returns: some or all of the received data and removes this amount from the queue. May return less than requested.
+	void[] receive()
+	{
+		ubyte[] result;
+		
+		result = readbuf[0 .. rpos];
+		readbuf = null;
+		rpos = 0;
+		
+		return result;
+	}
+	
+	/// ditto
+	void[] receive(uint len)
+	{
+		if(len >= rpos)
+			return receive();
+		
+		ubyte[] result;
+		
+		result = readbuf[0 .. len];
+		readbuf = readbuf[len .. readbuf.length];
+		rpos -= len;
+		
+		return result;
+	}
+	
+	
+	/// Add data to the queue and send it over this socket.
+	void send(void[] buf)
+	{
+		if(canwrite)
+		{
+			assert(!writebuf.length);
+			
+			int st;
+			if(buf.length > 4096)
+				st = 4096;
+			else
+				st = buf.length;
+			
+			st = sock.send(buf[0 .. st]);
+			if(st > 0)
+			{
+				if(buf.length - st)
+				{
+					// dup so it can be appended to.
+					writebuf = (cast(ubyte[])buf)[st .. buf.length].dup;
+				}
+			}
+			else
+			{
+				// dup so it can be appended to.
+				writebuf = (cast(ubyte[])buf).dup;
+			}
+			
+			//canwrite = false;
+		}
+		else
+		{
+			writebuf ~= cast(ubyte[])buf;
+		}
+	}
+	
+	
+	/// Property: get the number of bytes in send buffer.
+	uint sendBytes()
+	{
+		return writebuf.length;
+	}
+	
+	
+	/// Property: get the number of bytes in recv buffer.
+	uint receiveBytes()
+	{
+		return rpos;
+	}
+	
+	
+	/// Call on a read event so that incoming data may be buffered.
+	void readEvent()
+	{
+		if(readbuf.length - rpos < 1024)
+			readbuf.length = readbuf.length + 2048;
+		
+		int rd = sock.receive(readbuf[rpos .. readbuf.length]);
+		if(rd > 0)
+			rpos += cast(uint)rd;
+	}
+	
+	
+	/// Call on a write event so that buffered outgoing data may be sent.
+	void writeEvent()
+	{
+		if(writebuf.length)
+		{
+			ubyte[] buf;
+			
+			if(writebuf.length > 4096)
+				buf = writebuf[0 .. 4096];
+			else
+				buf = writebuf;
+			
+			int st = sock.send(buf);
+			if(st > 0)
+				writebuf = writebuf[st .. writebuf.length];
+		}
+		else
+		{
+			//canwrite = true;
+		}
+	}
+	
+	
+	/**
+		Shortcut function for AsyncSocket.
+		Automatically calls readEvent and writeEvent as needed.
+		Same signature as RegisterEventCallback for simplicity.
+	**/
+	void event(Socket _sock, EventType type, int err)
+	in
+	{
+		assert(_sock is sock);
+	}
+	body
+	{
+		switch(type)
+		{
+			case EventType.READ:
+				readEvent();
+				break;
+			
+			case EventType.WRITE:
+				writeEvent();
+				break;
+			
+			default: ;
+		}
+	}
+	
+	
+	deprecated
+	{
+		alias receiveBytes recvBytes;
+		alias receive recv;
+	}
+	
+	
+	private:
+	ubyte[] writebuf;
+	ubyte[] readbuf;
+	uint rpos;
+	Socket sock;
+	//bool canwrite = false;
+	
+	
+	bool canwrite() // getter
+	{
+		return writebuf.length == 0;
+	}
+}
+
+
+/// Returns the number of asynchronous sockets waiting for events.
+size_t getNumberOfAsyncSockets()
+{
+	return _tallEvents.length;
+}
+
+
+/// Returns the number of active timers.
+size_t getNumberOfTimers()
+{
+	return _tcount;
+}
+
+
+private:
+
+Timer _tfirst, _tlast;
+size_t _tcount = 0;
+
+
+Timer _tnext()
+{
+	//spdTime lowest = spdTime.max; // Wrong in Tango 0.99.2.
+	spdTime lowest = cast(spdTime)((spdTime.init + 0).max); // + 1 converts to the underlying arithmetic type to get the real max.
+	Timer t, tlowest;
+	for(t = _tfirst; t; t = t._tnext)
+	{
+		if(t._talarm < lowest)
+		{
+			tlowest = t;
+			lowest = t._talarm;
+		}
+	}
+	return tlowest;
+}
+
+
+void _tadd(Timer t)
+in
+{
+	assert(t !is null);
+	assert(t._ttimeout);
+	assert(t._tprev is null);
+	assert(t._tnext is null);
+	assert(t._talarm == t._TALARM_INIT);
+}
+body
+{
+	t._talarm = cast(spdTime)(spdGetCurrentUtcTime() + t._ttimeout);
+	
+	t._tprev = _tlast;
+	_tlast = t;
+	if(!_tfirst)
+		_tfirst = t;
+	else
+		t._tprev._tnext = t;
+	
+	_tcount++;
+}
+
+
+void _tremove(Timer t)
+in
+{
+	assert(t !is null);
+	assert(t._talarm != t._TALARM_INIT);
+}
+body
+{
+	t._talarm = t._TALARM_INIT;
+	
+	if(t._tprev)
+		t._tprev._tnext = t._tnext;
+	else
+		_tfirst = t._tnext;
+	
+	if(t._tnext)
+		t._tnext._tprev = t._tprev;
+	else
+		_tlast = t._tprev;
+	
+	t._tprev = null;
+	t._tnext = null;
+	
+	if(_tcount)
+		_tcount--;
+}
+
+
+template _tTicks()
+{
+	static if(spdTICKS_PER_SECOND == 1_000)
+	{
+		uint _tticksToSecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND); }
+		uint _tticksToMs(spdTime ticks) { return cast(uint)ticks; }
+		//uint _tticksToNs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000_000); }
+		//uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); }
+		//uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(ticks / spdTICKS_PER_SECOND * 1_000_000); }
+		uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); }
+		spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(secs * spdTICKS_PER_SECOND); }
+		spdTime _tmsToTicks(uint ms) { return cast(spdTime)ms; }
+	}
+	else
+	{
+		uint _tticksToSecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND); }
+		uint _tticksToMs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000); }
+		//uint _tticksToNs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000_000); }
+		uint _tticksToMicrosecs(spdTime ticks) { return cast(uint)(cast(double)ticks / cast(double)spdTICKS_PER_SECOND * cast(double)1_000_000); }
+		spdTime _tsecsToTicks(uint secs) { return cast(spdTime)(cast(double)secs * cast(double)spdTICKS_PER_SECOND); }
+		spdTime _tmsToTicks(uint ms) { return cast(spdTime)(cast(double)spdTICKS_PER_SECOND / cast(double)1_000 * cast(double)ms); }
+	}
+}
+
+alias _tTicks!()._tticksToSecs _tticksToSecs;
+alias _tTicks!()._tticksToMs _tticksToMs;
+//alias _tTicks!()._tticksToNs _tticksToNs;
+alias _tTicks!()._tticksToMicrosecs _tticksToMicrosecs;
+alias _tTicks!()._tsecsToTicks _tsecsToTicks;
+alias _tTicks!()._tmsToTicks _tmsToTicks;
+
+
+unittest
+{
+	assert(_tsecsToTicks(_tticksToSecs(543253)) == _tsecsToTicks(_tticksToSecs(543253)));
+	assert(_tmsToTicks(_tticksToMs(3445723)) == _tmsToTicks(_tticksToMs(3445723)));
+}
+
+
+void _tticksToTimeval(spdTime ticks, spdMyTimeval* tv)
+{
+	tv.seconds = _tticksToSecs(ticks);
+	ticks -= _tsecsToTicks(tv.seconds);
+	tv.microseconds = _tticksToMicrosecs(ticks);
+}
+
+
+//_tEventInfo[socket_t] _tallEvents;
+AsyncSocket[socket_t] _tallEvents;
+
+Thread _ththread;
+GetHost _thnext, _thaddto;
+GetHost _thfinnext, _thfinlast;
+
+bool _texit = false;
+
+
+/+
+// Test.
+void main()
+{
+	new class Timer { this() { interval = 1000; start(); } override void onAlarm() { printf(" * ALARM * \n"); } };
+	new class Timer { this() { interval = 5000; start(); } override void onAlarm() { printf(" &die 5 spawn 2 & \n"); stop();
+			new class Timer { this() { interval = 2000; start(); } override void onAlarm() { printf(" x spawn x \n"); } };
+		} };
+	new class Timer { this() { interval = 3000; start(); } override void onAlarm() { printf(" &die 3& \n"); stop(); } };
+	new class Timer { this() { interval = 2500; start(); } override void onAlarm()
+			{
+				stop();
+				asyncGetHostByName("www.google.com", (spdInternetHost ih, int err) { if(!err) { printf(" gGot host %.*s\n", ih.name); } });
+			}
+		};
+	new class Timer { this() { interval = 500; start(); } override void onAlarm()
+			{
+				printf(" (slower and slower %lu \n", interval);
+				interval = interval + 500;
+			}
+		};
+	
+	asyncGetHostByName("www.yahoo.com", (spdInternetHost ih, int err) { if(!err) { printf(" yGot host %.*s\n", ih.name); } });
+	asyncGetHostByName("www.ask.com", (spdInternetHost ih, int err) { if(!err) { printf(" aGot host %.*s\n", ih.name); } });
+	
+	run();
+}
++/
+

=== added file 'D_lang/testing/candidate_libs/splat.html'
--- D_lang/testing/candidate_libs/splat.html	1970-01-01 00:00:00 +0000
+++ D_lang/testing/candidate_libs/splat.html	2013-02-21 03:06:20 +0000
@@ -0,0 +1,269 @@
+<html><head>
+	<META http-equiv="content-type" content="text/html; charset=utf-8">
+	<title>splat</title>
+	</head><body>
+	<h1>splat</h1>
+	<!-- Generated by Ddoc from splat.d -->
+<b></b> Splat: the socket platform with the lame name. It's full of puns, but it runs!
+	<a href="http://www.dprogramming.com/splat.php";>Download Splat</a>.
+	Version 0.7.
+	For both Phobos and Tango; tested with Phobos and Tango 0.99.2.
+<br><br>
+
+<dl><dt><big>void <u>run</u>();
+</big></dt>
+<dd>Run the event loop; wait for timer and socket events.
+	Exceptions that occur in event callbacks break out of <u>run</u>.
+<br><br>
+
+</dd>
+<dt><big>void <u>exitLoop</u>();
+</big></dt>
+<dd>Causes run() to return as soon as it can.
+<br><br>
+
+</dd>
+<dt><big>class <u>Timer</u>;
+</big></dt>
+<dd>Timers; alarms (timeout events) depend on run().
+<br><br>
+
+<dl><dt><big>final void <u>interval</u>(uint <i>iv</i>);
+<br>final uint <u>interval</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get and set the timer interval in milliseconds.
+<br><br>
+
+</dd>
+<dt><big>final void <u>start</u>();
+</big></dt>
+<dd>Start this timer.
+<br><br>
+
+</dd>
+<dt><big>final void <u>stop</u>();
+</big></dt>
+<dd>Stop this timer.
+<br><br>
+
+</dd>
+<dt><big>void <u>onAlarm</u>();
+</big></dt>
+<dd>Override to be notified when the time expires. Alarms continue until stop().
+<br><br>
+
+</dd>
+<dt><big>this();
+<br>this(void delegate(Timer) <i>dg</i>);
+</big></dt>
+<dd>Construct a timer; can take a delegate that is called back automatically on an alarm.
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>enum <u>EventType</u>;
+</big></dt>
+<dd>Socket event flags.
+<br><br>
+
+<dl><dt><big><u>NONE</u></big></dt>
+<dd><br><br>
+</dd>
+<dt><big><u>READ</u><br><u>WRITE</u><br><u>ACCEPT</u><br><u>CONNECT</u><br><u>CLOSE</u></big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>alias <u>RegisterEventCallback</u>;
+</big></dt>
+<dd>Callback type for socket events.
+<br><br>
+<b>Params:</b><br>
+<table><tr><td>sock</td>
+<td>the socket</td></tr>
+<tr><td>type</td>
+<td>which event; will be only one of the event flags.</td></tr>
+<tr><td>err</td>
+<td>an error code, or 0 if successful.</td></tr>
+</table><br>
+
+</dd>
+<dt><big>class <u>AsyncSocket</u>: std.socket.Socket;
+</big></dt>
+<dd>Asynchronous sockets; socket events depend on run(). Mostly the same as std.socket.Socket.
+<br><br>
+
+<dl><dt><big>void <u>event</u>(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>callback</i>);
+</big></dt>
+<dd>Registers a <i>callback</i> for specified socket <i>events</i>.
+		One or more type flags may be used, or NONE to cancel all.
+		Calling this twice on the same socket cancels out previously registered <i>events</i> for the socket.
+	
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>class <u>AsyncTcpSocket</u>: splat.AsyncSocket;
+</big></dt>
+<dd>Asynchronous TCP socket shortcut.
+<br><br>
+
+<dl><dt><big>this(AddressFamily <i>family</i>);
+<br>this();
+<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+<br>this(Address <i>connectTo</i>, EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>class <u>AsyncUdpSocket</u>: splat.AsyncSocket;
+</big></dt>
+<dd>Asynchronous UDP socket shortcut.
+<br><br>
+
+<dl><dt><big>this(AddressFamily <i>family</i>);
+<br>this();
+<br>this(EventType <i>events</i>, void delegate(Socket sock, EventType type, int err) <i>eventCallback</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+</dl>
+</dd>
+<dt><big>alias <u>GetHostCallback</u>;
+</big></dt>
+<dd>Callback type for host resolve event.
+<br><br>
+<b>Params:</b><br>
+<table><tr><td>inetHost</td>
+<td>the InternetHost/NetHost of the resolved host, or <b>null</b>.</td></tr>
+<tr><td>err</td>
+<td>an error code, or 0 if successful; if 0, inetHost will be <b>null</b>.</td></tr>
+</table><br>
+
+</dd>
+<dt><big>class <u>GetHost</u>;
+</big></dt>
+<dd>Returned from asyncGetHost functions.
+<br><br>
+
+<dl><dt><big>void <u>cancel</u>();
+</big></dt>
+<dd>Cancel the get-host operation.
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>GetHost <u>asyncGetHostByName</u>(char[] <i>name</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+</big></dt>
+<dd>Asynchronously resolve host information from a hostname; the <i>callback</i> depends on run().
+<br><br>
+
+</dd>
+<dt><big>GetHost <u>asyncGetHostByAddr</u>(uint <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+<br>GetHost <u>asyncGetHostByAddr</u>(char[] <i>addr</i>, void delegate(InternetHost inetHost, int err) <i>callback</i>);
+</big></dt>
+<dd>Asynchronously resolve host information from an IPv4 address; the <i>callback</i> depends on run().
+<br><br>
+
+</dd>
+<dt><big>class <u>SocketQueue</u>;
+</big></dt>
+<dd>Buffering socket I/O.
+<br><br>
+
+<dl><dt><big>this(Socket <i>sock</i>);
+</big></dt>
+<dd><br><br>
+</dd>
+<dt><big>final Socket <u>socket</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the <u>socket</u> of this queue.
+<br><br>
+
+</dd>
+<dt><big>void <u>reset</u>();
+</big></dt>
+<dd>Resets the buffers.
+<br><br>
+
+</dd>
+<dt><big>void[] <u>peek</u>();
+<br>void[] <u>peek</u>(uint <i>len</i>);
+</big></dt>
+<dd>Peek at some or all of the received data but leave it in the queue. May return less than requested.
+<br><br>
+
+</dd>
+<dt><big>void[] <u>receive</u>();
+<br>void[] <u>receive</u>(uint <i>len</i>);
+</big></dt>
+<dd><b>Returns:</b><br>
+some or all of the received data and removes this amount from the queue. May return less than requested.
+<br><br>
+
+</dd>
+<dt><big>void <u>send</u>(void[] <i>buf</i>);
+</big></dt>
+<dd>Add data to the queue and <u>send</u> it over this socket.
+<br><br>
+
+</dd>
+<dt><big>uint <u>sendBytes</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the number of bytes in send buffer.
+<br><br>
+
+</dd>
+<dt><big>uint <u>receiveBytes</u>();
+</big></dt>
+<dd><b>Property:</b><br>
+get the number of bytes in recv buffer.
+<br><br>
+
+</dd>
+<dt><big>void <u>readEvent</u>();
+</big></dt>
+<dd>Call on a read event so that incoming data may be buffered.
+<br><br>
+
+</dd>
+<dt><big>void <u>writeEvent</u>();
+</big></dt>
+<dd>Call on a write event so that buffered outgoing data may be sent.
+<br><br>
+
+</dd>
+<dt><big>void <u>event</u>(Socket <i>_sock</i>, EventType <i>type</i>, int <i>err</i>);
+</big></dt>
+<dd>Shortcut function for AsyncSocket.
+		Automatically calls readEvent and writeEvent as needed.
+		Same signature as RegisterEventCallback for simplicity.
+	
+<br><br>
+
+</dd>
+</dl>
+</dd>
+<dt><big>uint <u>getNumberOfAsyncSockets</u>();
+</big></dt>
+<dd>Returns the number of asynchronous sockets waiting for events.
+<br><br>
+
+</dd>
+<dt><big>uint <u>getNumberOfTimers</u>();
+</big></dt>
+<dd>Returns the number of active timers.
+<br><br>
+
+</dd>
+</dl>
+
+	<hr><small>Page generated by <a href="http://www.digitalmars.com/d/ddoc.html";>Ddoc</a>. </small>
+	</body></html>

=== added file 'D_lang/testing/candidate_libs/splat07.zip'
Binary files D_lang/testing/candidate_libs/splat07.zip	1970-01-01 00:00:00 +0000 and D_lang/testing/candidate_libs/splat07.zip	2013-02-21 03:06:20 +0000 differ
=== added directory 'D_lang/testing/str_socket'
=== added file 'D_lang/testing/str_socket/Makefile'
--- D_lang/testing/str_socket/Makefile	1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/Makefile	2013-02-21 03:06:20 +0000
@@ -0,0 +1,30 @@
+#***********************************************
+# This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+#    NRTB is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    NRTB is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with NRTB.  If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+lib:	socket_test
+	@./socket_test
+	@echo build complete
+
+socket_test: socket_test.d Makefile
+	@rm -f socket_test
+	@dmd socket_test.d
+
+clean:
+	@rm -vf *.o socket_test
+	@echo all objects and executables have been erased.
+

=== added file 'D_lang/testing/str_socket/SocketStringTransciever.mm'
--- D_lang/testing/str_socket/SocketStringTransciever.mm	1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/SocketStringTransciever.mm	2013-02-21 03:06:20 +0000
@@ -0,0 +1,49 @@
+<map version="0.9.0">
+<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
+<node CREATED="1353288395487" ID="ID_1403329192" MODIFIED="1353512093507" TEXT="Socket string transciever.">
+<node CREATED="1353288596251" ID="ID_1636926895" MODIFIED="1353512095611" POSITION="right" TEXT="Connect(address)">
+<node CREATED="1353289092215" ID="ID_1097805018" MODIFIED="1353289099292" TEXT="Resolves address"/>
+<node CREATED="1353289100126" ID="ID_912894431" MODIFIED="1353289144348" TEXT="Connects to address"/>
+<node CREATED="1353289145245" ID="ID_1737995458" MODIFIED="1353289159019" TEXT="Starts reciever thread"/>
+<node CREATED="1353290958729" ID="ID_1494063472" MODIFIED="1353291040119" TEXT="Expects the callbacks to set at call time"/>
+<node CREATED="1353289166189" ID="ID_244950625" MODIFIED="1353289174227" TEXT="throws on any error"/>
+</node>
+<node CREATED="1353288616481" ID="ID_845783483" MODIFIED="1353512095614" POSITION="right" TEXT="close()">
+<node CREATED="1353289189501" ID="ID_142698792" MODIFIED="1353289197939" TEXT="Shutdown reciever thread"/>
+<node CREATED="1353289198757" ID="ID_771780490" MODIFIED="1353289263410" TEXT="close socket"/>
+<node CREATED="1353289271773" ID="ID_357264070" MODIFIED="1353289293595" TEXT="discard any other resources allocated"/>
+</node>
+<node CREATED="1353288702488" ID="ID_1885052703" MODIFIED="1353512095619" POSITION="right" TEXT="regeister_receiver(funtion(newStr))">
+<node CREATED="1353289372692" ID="ID_1797818997" MODIFIED="1353289421498" TEXT="Replace existing reciever callback"/>
+<node CREATED="1353289422811" ID="ID_716021446" MODIFIED="1353289467577" TEXT="The callback has the signiture function(string)"/>
+<node CREATED="1353289476939" ID="ID_1689880619" MODIFIED="1353290199100" TEXT="The callback will be called whenever an ASCII 10 is recieved."/>
+<node CREATED="1353290138311" ID="ID_48990930" MODIFIED="1353290251764" TEXT="The argument &quot;newStr&quot; will contain any bytes recieved before the ASCII 10"/>
+<node CREATED="1353289528395" ID="ID_1457236482" MODIFIED="1353290179636" TEXT="ASCII 10s and 13s will be discarded"/>
+</node>
+<node CREATED="1353288756648" ID="ID_1776338151" MODIFIED="1353288803357" POSITION="right" TEXT="register_event_hander(funciton(event))">
+<node CREATED="1353289687346" ID="ID_146527388" MODIFIED="1353289714640" TEXT="Replace existing event handler"/>
+<node CREATED="1353289715586" ID="ID_1957454409" MODIFIED="1353289748151" TEXT="The callback has the signiture function(string)"/>
+<node CREATED="1353289749753" ID="ID_1524918841" MODIFIED="1353289768918" TEXT="The callback will be called whenever an event occurs"/>
+<node CREATED="1353289775721" ID="ID_698482207" MODIFIED="1353289785327" TEXT="Available events">
+<node CREATED="1353495351509" ID="ID_1988403096" MODIFIED="1353495373615" TEXT="connect"/>
+<node CREATED="1353495374592" ID="ID_1082092706" MODIFIED="1353495385858" TEXT="overflow"/>
+<node CREATED="1353495387001" ID="ID_1818531252" MODIFIED="1353495391356" TEXT="underflow"/>
+<node CREATED="1353495392662" ID="ID_236107112" MODIFIED="1353495399980" TEXT="dropped"/>
+<node CREATED="1353495400962" ID="ID_909770107" MODIFIED="1353495403143" TEXT="disconnect"/>
+</node>
+</node>
+<node CREATED="1353288811903" ID="ID_1354285471" MODIFIED="1353512095621" POSITION="right" TEXT="send(string)">
+<node CREATED="1353289903920" ID="ID_293305230" MODIFIED="1353290032885" TEXT="Sends the argument on the socket"/>
+<node CREATED="1353290036647" ID="ID_1916879506" MODIFIED="1353290061148" TEXT="An ASCII 10 will be postixed to the string"/>
+<node CREATED="1353290092071" ID="ID_1214127336" MODIFIED="1353290125572" TEXT="Blocks until the send is complete."/>
+</node>
+<node CREATED="1353290448717" ID="ID_1736651166" MODIFIED="1353512095625" POSITION="right" TEXT="worker_thread()">
+<node CREATED="1353290466204" ID="ID_1117113952" MODIFIED="1353290517609" TEXT="Responible for incoming bytes"/>
+<node CREATED="1353290741723" ID="ID_910559431" MODIFIED="1353290766920" TEXT="discards ASCII 10 and 13"/>
+<node CREATED="1353290769963" ID="ID_1282285823" MODIFIED="1353290798568" TEXT="places all other bytes in the buffer"/>
+<node CREATED="1353290518900" ID="ID_216777552" MODIFIED="1353291656818" TEXT="calls the receiver callback with the buffer on recept of an EOM  (ASCII 10)"/>
+<node CREATED="1353290869346" ID="ID_823816252" MODIFIED="1353290886168" TEXT="Clears the buffer when the callback returns"/>
+<node CREATED="1353291445518" ID="ID_578045982" MODIFIED="1353291464356" TEXT="Loops infinitely until closed."/>
+</node>
+</node>
+</map>

=== added file 'D_lang/testing/str_socket/socket_test.d'
--- D_lang/testing/str_socket/socket_test.d	1970-01-01 00:00:00 +0000
+++ D_lang/testing/str_socket/socket_test.d	2013-02-21 03:06:20 +0000
@@ -0,0 +1,43 @@
+/*********************
+Multithreaded message passing example in D
+*********************/
+
+// import the concurrency and standard IO modules
+import std.concurrency, std.stdio;
+import std.string, std.conv, std.stream, std.stdio;
+import std.socket, std.socketstream;
+
+// main is just like main in C++
+void main(string[] args)
+{
+  writeln("D Socket Send/Receive Test.");
+
+  if (args.length < 2)
+  {
+    writeln("Usage:");
+    writeln("      ",args[0]," httpd_IP");
+    return;
+  } 
+
+  string IP = args[1];
+  ushort port = 80;
+  
+  writefln("  Connecting to host %s:%d....",IP,port);
+  
+  // connect to the server
+  Socket sock = new TcpSocket(new InternetAddress(IP, port));
+  scope(exit) sock.close();
+  Stream ss   = new SocketStream(sock);
+  
+  ss.writeString("GET / HTTP/1.0\r\nHost: " ~ IP ~ "\r\n\r\n");
+  
+  while (!ss.eof())
+  {
+    auto line = ss.readLine();
+    writeln(line);
+  }
+  
+  writeln("** main() is complete **");
+
+}
+

=== added directory 'D_lang/testing/thread_pool'
=== added file 'D_lang/testing/thread_pool/Makefile'
--- D_lang/testing/thread_pool/Makefile	1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/Makefile	2013-02-21 03:06:20 +0000
@@ -0,0 +1,30 @@
+#***********************************************
+# This file is part of the NRTB project (https://launchpad.net/nrtb).
+#
+#    NRTB is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    NRTB is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with NRTB.  If not, see <http://www.gnu.org/licenses/>.
+#
+#***********************************************
+
+lib:	thread_pool
+	@./thread_pool
+	@echo build complete
+
+thread_pool: thread_pool.d Makefile
+	@rm -f thread_pool
+	@dmd thread_pool.d
+
+clean:
+	@rm -vf *.o thread_pool
+	@echo all objects and executables have been erased.
+

=== added file 'D_lang/testing/thread_pool/thread_pool.d'
--- D_lang/testing/thread_pool/thread_pool.d	1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/thread_pool.d	2013-02-21 03:06:20 +0000
@@ -0,0 +1,81 @@
+/*********************
+Multithreaded message passing example in D
+*********************/
+
+// import the concurrency and standard IO modules
+import std.concurrency, std.stdio, core.thread;
+
+struct thread_pool(wp_t, alias task)
+{
+  // Housekeeping variables  
+  private Tid listener_tid;
+  
+  // Does nothing but start the listener.
+  public this(int queue_size) {
+    listener_tid = spawn(&listener_thread!(wp_t,task),queue_size);
+  };
+    
+  // submit a work, packet for processing.
+  public void submit(wp_t wp) {
+    listener_tid.send(thisTid, wp);
+  };
+      
+}
+
+void worker_thread(wpt, alias task)() {
+  bool running = true;
+  while (running) {
+    receive (
+      (Tid t, wpt d) { task(t,d); },
+      (OwnerTerminated e) { running = false; }
+    );
+  };
+}
+
+void listener_thread(wpt, alias task)(int queue_size) {
+  
+  Tid worker_list[];
+  ulong next = 0;
+  
+  void submit(Tid t, wpt d) {
+    worker_list[next].send(t,d);
+    next = (++next) % worker_list.length;
+  }
+  
+  // initial setup.
+  for(int i = 0; i< queue_size; i++) {
+    worker_list ~= spawn(&worker_thread!(wpt,task));
+  }
+    
+  // service loop
+  bool running = true;
+  while (running) {
+    receive ( 
+      (Tid t, wpt d) { submit(t,d); },
+      (OwnerTerminated e) { running = false; }
+    );
+  };
+};
+
+//==== code starts here
+
+void mytask(Tid t, int i) {
+  writeln("Task ",thisTid," processed ",i);
+  Thread.sleep(dur!("msecs") (20));
+};
+
+
+// main is just like main in C++
+void main()
+{
+  writeln("D Message Driven Work Queue Example.");
+  auto myqueue = thread_pool!(int,mytask)(10);
+  
+  for (auto i=0; i<100; i++) {
+    myqueue.submit(i);
+  };
+  
+  Thread.sleep(dur!("seconds") (3));
+  writeln("Run complete");
+  
+};
\ No newline at end of file

=== added file 'D_lang/testing/thread_pool/thread_pool.mm'
--- D_lang/testing/thread_pool/thread_pool.mm	1970-01-01 00:00:00 +0000
+++ D_lang/testing/thread_pool/thread_pool.mm	2013-02-21 03:06:20 +0000
@@ -0,0 +1,47 @@
+<map version="0.9.0">
+<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
+<node CREATED="1199190455281" ID="ID_1574918623" MODIFIED="1199190480522" TEXT="thread_pool">
+<node CREATED="1360253779843" ID="ID_432711866" MODIFIED="1360261129036" POSITION="right" TEXT="class task_pool(t)">
+<node CREATED="1360267525267" ID="ID_760440288" MODIFIED="1360267533846" TEXT="this()">
+<node CREATED="1360268024517" ID="ID_1334050998" MODIFIED="1360328468829" TEXT="starts task_pool_manager(t)(low,high,,increment,task)"/>
+</node>
+<node CREATED="1360081590643" ID="ID_1324728" MODIFIED="1360081668955" TEXT="struct work_packet(t)"/>
+<node CREATED="1360081723340" ID="ID_1492950840" MODIFIED="1360081762970" TEXT="struct limits"/>
+<node CREATED="1360081739372" ID="ID_452972575" MODIFIED="1360081747882" TEXT="struct run_ctl"/>
+<node CREATED="1360254280681" ID="ID_778719726" MODIFIED="1360261274927" TEXT="void submit(t data)"/>
+<node CREATED="1360254367731" ID="ID_1043224962" MODIFIED="1360261286496" TEXT="uint set_limits(low, high, increment)"/>
+</node>
+<node CREATED="1360082136187" ID="ID_181135344" MODIFIED="1360328486894" POSITION="right" TEXT="task pool manager(t)(low, high, increment,task)">
+<node CREATED="1360254670685" ID="ID_1823995507" MODIFIED="1360254677048" TEXT="Free running thread"/>
+<node CREATED="1360254680507" ID="ID_291925315" MODIFIED="1360255051860" TEXT="On startup">
+<node CREATED="1360254687714" ID="ID_415174674" MODIFIED="1360254704683" TEXT="Registers with the global pool manager"/>
+<node CREATED="1360254714285" ID="ID_1841317578" MODIFIED="1360544160805" TEXT="starts default set of task_thread(t)(thisTid,task)"/>
+</node>
+<node CREATED="1360254933031" ID="ID_683968420" MODIFIED="1360255382530" TEXT="Service loop">
+<node CREATED="1360255079468" ID="ID_1559510237" MODIFIED="1360255176424" TEXT="rcv Tid, t">
+<node CREATED="1360255261482" ID="ID_29306120" MODIFIED="1360255307209" TEXT="Verify there spare thread count"/>
+<node CREATED="1360255312567" ID="ID_662023772" MODIFIED="1360255333731" TEXT="submit Tid, t to next task thread"/>
+</node>
+<node CREATED="1360255179495" ID="ID_548612491" MODIFIED="1360334567427" TEXT="rcv Tid, limits">
+<node CREATED="1360255428431" ID="ID_1067723780" MODIFIED="1360255499958" TEXT="Reset pool parameters"/>
+<node CREATED="1360255501795" ID="ID_943031629" MODIFIED="1360255516011" TEXT="Add/remove worker threads as needed"/>
+</node>
+<node CREATED="1360334567882" ID="ID_1909911450" MODIFIED="1360334583842" TEXT="rvc Tid, run_ctl">
+<node CREATED="1360334583845" ID="ID_882927298" MODIFIED="1360336402561" TEXT="shutdown"/>
+</node>
+</node>
+</node>
+<node CREATED="1360081583633" ID="ID_1103044446" MODIFIED="1360328522599" POSITION="right" TEXT="task_thread(t)(Tid task_pool_manager,task)">
+<node CREATED="1360281228443" ID="ID_1814378750" MODIFIED="1360281259435" TEXT="Free running thread"/>
+<node CREATED="1360334423885" ID="ID_1136327708" MODIFIED="1360334431123" TEXT="On startup"/>
+<node CREATED="1360334432374" ID="ID_516047719" MODIFIED="1360334444665" TEXT="Service Loop">
+<node CREATED="1360334444667" ID="ID_1239866205" MODIFIED="1360334469683" TEXT="receive tid, t">
+<node CREATED="1360334469685" ID="ID_1854740647" MODIFIED="1360334485839" TEXT="Call task(tid,t)"/>
+</node>
+<node CREATED="1360334493738" ID="ID_1132173280" MODIFIED="1360334530760" TEXT="receive tid, run_ctl">
+<node CREATED="1360334530762" ID="ID_1133543570" MODIFIED="1360334542293" TEXT="shutdown"/>
+</node>
+</node>
+</node>
+</node>
+</map>


Follow ups