<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>projectwhite &#187; Personal</title>
	<atom:link href="http://www.projectwhite.com/category/personal/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.projectwhite.com</link>
	<description>the fiddly bits of the internet</description>
	<lastBuildDate>Fri, 07 May 2010 12:33:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
	<atom:link rel='hub' href='http://www.projectwhite.com/?pushpress=hub'/>
		<item>
		<title>IIS7 and SMTP</title>
		<link>http://www.projectwhite.com/2010/05/07/iis7-and-smtp/</link>
		<comments>http://www.projectwhite.com/2010/05/07/iis7-and-smtp/#comments</comments>
		<pubDate>Fri, 07 May 2010 12:30:49 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=118</guid>
		<description><![CDATA[Recently, a colleague at work was struggling with one of our new Windows 2008 servers, in that it wasn&#8217;t sending emails out to users. It turns out that there&#8217;s a historical reason for this, which I shall outline below: IIS4/IIS5 were aimed at classic ASP, which used CDONTS to send emails. CDONTS wasn’t aware of [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, a colleague at work was struggling with one of our new Windows 2008 servers, in that it wasn&#8217;t sending emails out to users. It turns out that there&#8217;s a historical reason for this, which I shall outline below:</p>
<p><strong>IIS4/IIS5</strong> were aimed at classic ASP, which used CDONTS to send emails. CDONTS wasn’t aware of external mail servers, it assumed you’d run a single-box environment, so is hardcoded to use localhost and the cutdown SMTP service bundled with IIS: <a href="http://classicasp.aspfaq.com/email/can-i-use-a-remote-smtp-server-with-cdonts-newmail.html">http://classicasp.aspfaq.com/email/can-i-use-a-remote-smtp-server-with-cdonts-newmail.html</a></p>
<p><strong>IIS6 </strong>and above use the replacement, CDOSYS, which is aware of remote servers, so you don’t necessarily need your web server to run a local SMTP service:<a href="http://www.asp101.com/articles/john/cdosmtprelay/default.asp"> http://www.asp101.com/articles/john/cdosmtprelay/default.asp</a></p>
<p>IIS can still run a local/cutdown SMTP server, and this can still be managed via IIS.</p>
<p><strong>IIS7</strong> seems to further this concept and do away with local/cutdown SMTP service under IIS altogether. Although SMTP server can be installed on Windows2008, it’s considered a separate product (and not manageable from IIS7, IIS6 is used with it&#8217;s compatibilty mode); Instead, IIS has the option to use an external SMTP server.</p>
<p><a href="http://weblogs.asp.net/steveschofield/archive/2006/12/19/iis7-post-23-vista-and-smtp-server-where-is-it.aspx">http://weblogs.asp.net/steveschofield/archive/2006/12/19/iis7-post-23-vista-and-smtp-server-where-is-it.aspx</a> (Note: Vista runs same ‘core’ as Windows 2008)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2010/05/07/iis7-and-smtp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Has it really been that long? I hadnt noticed</title>
		<link>http://www.projectwhite.com/2009/07/24/has-it-really-been-that-long-i-hadnt-noticed/</link>
		<comments>http://www.projectwhite.com/2009/07/24/has-it-really-been-that-long-i-hadnt-noticed/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 12:07:58 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=111</guid>
		<description><![CDATA[Ok, I am shit. I promised that I&#8217;d update this site on a semi-regular basis, and my last worthwhile contribution to this site was over two months ago. Just to give a recap on what I&#8217;ve been upto: I am now 29. I now know a little bit more about SQL Server and Windows Server, [...]]]></description>
			<content:encoded><![CDATA[<p>Ok, I am shit. I promised that I&#8217;d update this site on a semi-regular basis, and my last worthwhile contribution to this site was over two months ago.</p>
<p>Just to give a recap on what I&#8217;ve been upto:</p>
<ul>
<li>I am now 29.</li>
<li>I now know a little bit more about SQL Server and Windows Server, and a fair bit more about IIS6.</li>
<li>I went to Bovington Tank Museum</li>
<li>I had a drive about in a  Rally Car at Silverstone.</li>
<li>I saw Blur play in Hyde Park</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/07/24/has-it-really-been-that-long-i-hadnt-noticed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geisha Maps</title>
		<link>http://www.projectwhite.com/2009/03/19/geisha-maps/</link>
		<comments>http://www.projectwhite.com/2009/03/19/geisha-maps/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 20:59:11 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[geisha]]></category>
		<category><![CDATA[japan]]></category>
		<category><![CDATA[kyoto]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=104</guid>
		<description><![CDATA[I found out today that Google Maps now has street view for Koyoto (I should have realised this when I posted the map the other day). Anyway, the aforementioned teahouse can be found in this view. You&#8217;ll want to stand at this point, to catch geisha entering/exiting the teahouse, geisha coming from the alleyway, and [...]]]></description>
			<content:encoded><![CDATA[<p>I found out today that Google Maps now has street view for Koyoto (I should have realised this when I posted the map the other day).</p>
<p>Anyway, the aforementioned teahouse can be found <a href="http://maps.google.co.uk/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=kyoto&amp;sll=34.993424,135.764494&amp;sspn=0.006082,0.013819&amp;ie=UTF8&amp;ll=35.003847,135.775048&amp;spn=0.00076,0.002747&amp;z=19&amp;layer=c&amp;cbll=35.003843,135.774943&amp;panoid=pErWKRDuITbQos_INskIcA&amp;cbp=12,136.449755836424,,0,1.1328125000000007">in this view</a>. You&#8217;ll want to <a href="http://maps.google.co.uk/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=kyoto&amp;sll=34.993424,135.764494&amp;sspn=0.006082,0.013819&amp;ie=UTF8&amp;ll=35.003454,135.775011&amp;spn=0.00076,0.002747&amp;z=19&amp;layer=c&amp;cbll=35.003371,135.77501&amp;panoid=e-CkrcCBsrETipl-rRgyKA&amp;cbp=12,38.891162086423975,,0,4.824218749999992">stand at this point</a>, to catch geisha entering/exiting the teahouse, geisha coming from the alleyway, and geisha coming from behind.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/03/19/geisha-maps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Turning Japanese</title>
		<link>http://www.projectwhite.com/2009/03/17/turning-japanese/</link>
		<comments>http://www.projectwhite.com/2009/03/17/turning-japanese/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 21:39:25 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[culture]]></category>
		<category><![CDATA[japan]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=101</guid>
		<description><![CDATA[There&#8217;s a new season on BBC4, regarding Japanese Culture. Check it out.]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a new season on BBC4, regarding Japanese Culture.</p>
<p><a href="http://bbc.co.uk/japan">Check it out.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/03/17/turning-japanese/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>On finding Geisha</title>
		<link>http://www.projectwhite.com/2009/03/15/geiko-geisha/</link>
		<comments>http://www.projectwhite.com/2009/03/15/geiko-geisha/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 19:35:49 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[geisha]]></category>
		<category><![CDATA[japan]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/2009/03/15/geiko-geisha/</guid>
		<description><![CDATA[Geiko (Geisha) Originally uploaded by mindfieldz I was recently looking over my most popular Flickr photographs, and I came accross this one, shown to the right. I visited Japan in May 2008, and one of the biggest highlights was seeing a real geisha in Kyoto (not to be confused with normal Japanese women in nice [...]]]></description>
			<content:encoded><![CDATA[<div style="float: right; margin-left: 10px; margin-bottom: 10px;"><a title="photo sharing" href="http://www.flickr.com/photos/mindfieldz/2553392094/"><img style="border: solid 2px #000000;" src="http://farm4.static.flickr.com/3115/2553392094_9b7ed4d69c_m.jpg" alt="" /></a></p>
<p><span style="font-size: 0.9em; margin-top: 0px;"><br />
<a href="http://www.flickr.com/photos/mindfieldz/2553392094/">Geiko (Geisha)</a></span></p>
<p>Originally uploaded by <a href="http://www.flickr.com/people/mindfieldz/">mindfieldz</a></div>
<p>I was recently looking over my most popular Flickr photographs, and I came accross this one, shown to the right.</p>
<p>I visited Japan in May 2008, and one of the biggest highlights was seeing a real geisha in Kyoto (not to be confused with normal Japanese women in nice kimono&#8217;s). <em>Lonely Planet</em>, and <em>Rough Guide</em> don&#8217;t really give you an indication of <em>where </em>to find geisha, only that they&#8217;re &#8220;in Gion&#8221;.</p>
<p>After some frantic goggling, in a ryokan in Kyoto, I eventually found hints tucked away in a photography blog. Matching against a Japanese google maps, I convinced my wife to follow me to a side street in Gion.</p>
<p>Success! I&#8217;d managed to find the Ichiriki-tei Teahouse, the most prestigious teahouse in Gion.</p>
<p>[flickr style="border: 1px solid #5A5A5A"]set:72157615254849529[/flickr]</p>
<p>So, if you want to get awesome photos of geisha, follow the instructions below.</p>
<ol>
<li>Get yourself to Gion, in Kyoto.</li>
<li>Locate the <a href="http://www.flickr.com/photos/mindfieldz/3353112751/in/set-72157615254849529/">Ichiriki-tei</a> <a href="http://www.flickr.com/photos/mindfieldz/3353115795/in/set-72157615254849529/">Teahouse</a>, this can be found just off the main street in Gion. On google maps, it&#8217;s the <a href="http://maps.google.com/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;sll=34.44829,132.459111&amp;sspn=0.012245,0.027637&amp;ie=UTF8&amp;ll=35.003627,135.775174&amp;spn=0.00076,0.002747&amp;t=h&amp;z=19">C-shaped grey building</a>.</li>
<li>Wait until about 5:30pm-7:30pm local time. Don&#8217;t get too close to the entrance of the teahouse, else someone will come out and ask you to <a href="http://www.flickr.com/photos/mindfieldz/2553388858/in/set-72157615254849529/">move away from the entrance</a>. Taxi&#8217;s and other vehicles pull up to the etrance, so be careful if you are attached to a camera lens.</li>
<li>You will know if you are in the right place at the right time, as a <a href="http://www.flickr.com/photos/mindfieldz/2551705117/in/set-72157615254849529/">fairly large crowd</a> will gather.</li>
<li>Best place to position yourself is at the corner of the teahouse, looking down the alleyway behind the building. Geisha will come from all directions!</li>
</ol>
<p>That&#8217;s it. In about an hour I saw 7 geisha, which is not bad considering it was a random tip-off from another blog (whose address I&#8217;ve long forgotten).</p>
<p>[Edit: Just realised that latest WordPress upgrade managed to remove the <a href="http://www.flickr.com/photos/mindfieldz/sets/72157615254849529/">photos I'd posted</a>.]</p>
<p>In terms of the kit used to get the shots above:</p>
<p>Canon EOS 400D<br />
18-55mm f3.6-5.0 Tamron lens.<br />
55-200mm f3.6-5.0 Tamron lens.<br />
Mostly 1/60 to 1/200 shots, handheld.</p>
<p>Be prepared to do a lot of running with a camera.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/03/15/geiko-geisha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An unexpected update</title>
		<link>http://www.projectwhite.com/2009/03/09/an-unexpected-update/</link>
		<comments>http://www.projectwhite.com/2009/03/09/an-unexpected-update/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 20:14:22 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[html content blog]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=81</guid>
		<description><![CDATA[So yeah. I lied. I&#8217;m not posting as often as I had promised. There&#8217;s a good reason, seriously&#8230; Anyway, I have made some tweaks to the site. The site now defaults to 75% width, up from 70%. I had aimed/hoped for 80-85%, but my header images aren&#8217;t wide enough, expect that to change at some [...]]]></description>
			<content:encoded><![CDATA[<p>So yeah. I lied. I&#8217;m not posting as often as I had promised.</p>
<p>There&#8217;s a good reason, seriously&#8230;</p>
<p>Anyway, I have made some tweaks to the site.</p>
<ul>
<li>The site now defaults to 75% width, up from 70%. I had aimed/hoped for 80-85%, but my header images aren&#8217;t wide enough, expect that to change at some point.</li>
<li>My <a href="http://www.longren.org/2006/09/27/wrapping-text-inside-pre-tags/">code boxes now word wrap</a>, so you&#8217;ll be able to see my code in all it&#8217;s glory.</li>
</ul>
<p>Not much, but a start. And some content.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/03/09/an-unexpected-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Roomba with a view</title>
		<link>http://www.projectwhite.com/2009/02/22/roomba-with-a-view/</link>
		<comments>http://www.projectwhite.com/2009/02/22/roomba-with-a-view/#comments</comments>
		<pubDate>Sun, 22 Feb 2009 20:46:12 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[bluetooth]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[robot]]></category>
		<category><![CDATA[roomba]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=79</guid>
		<description><![CDATA[Although I already have Left 4 Dead, my wife recently purchased a Roomba. Disappointed by the lack of dueling harnesses for sale on the internet, I decided to get one of the Rootooth Bluetooth serial modules, that allows PC control of the newer Roombas. Although SparkFun says that they&#8217;re out of stock, it seems to [...]]]></description>
			<content:encoded><![CDATA[<p>Although I already have Left 4 Dead, my wife recently purchased a Roomba. Disappointed by the lack of <a href="http://xkcd.com/506/">dueling harnesses</a> for sale on the internet, I decided to get one of the <a href="http://www.sparkfun.com/commerce/product_info.php?products_id=684">Rootooth</a> Bluetooth serial modules, that allows PC control of the newer Roombas.</p>
<p>Although <a href="http://www.sparkfun.com/">SparkFun</a> says that they&#8217;re out of stock, it seems to be more of an &#8216;order on demand&#8217; type of thing. I purchased a Rootooth on backorder, and had one posted to me within two weeks. For reference I chose the cheapskate AirMail option with no tracking, and the item turned up within about 3 weeks from my original order date. Although SparkFun had marked the box belot its actual cost, Customs had decided to open and hold it for a few days anyway.</p>
<p>The Rootooth itself. Don&#8217;t be disheartened if it doesn&#8217;t work out of the box. I discovered three things with mine:</p>
<ol>
<li>You need a Bluetooth dongle that works on Widcomm or the Windows Bluetooth Stack (preferred). I initially tried it with a cheap Bluesoleil Bluetooth dongle, and it failed miserably &#8211; Vista refused to connect to the virtual serial port on the Rootooth, and XP would consistently drop the connection every few minutes.<br />
I eventually bought a Belkin Bluetooth dongle for £10, the F8T013UK. Although it has Widcomm drivers, you can get it running under the Windows stack by <a href="http://www.planetamd64.com/lofiversion/index.php?t24349.html">following some simple instructions</a>.</li>
<li>The Rootooth has been upgraded to use a Firefly Bluetooth module. This version is rumoured to set an incorrect baud rate for the 5xx series of Roombas, despite using the SU,115K instruction. To fix, send the following commands to your Rootooth:<br />
$$$<br />
U,115K,N<br />
Your Rootooth should return back to normal mode (not command mode), and you&#8217;re ready to go.</li>
<li>There are few websites/forum posts giving information relating to the Roomba 5xx series, even fewer bits of code/software which work with them, and even fewer that work with both.<br />
I discovered that the 5xx series uses a <a href="http://www.planetamd64.com/lofiversion/index.php?t24349.html">different set of codes</a>, and that one person had <a href="http://members.lycos.co.uk/peyrebelle/">coded for the latest Rootooth/Roomba combination</a>.</li>
</ol>
<p>So, my Roomba now goes backwards and forwards, and I can monitor the sensors. Next stop, Roomba/Twitter and <a href="http://www.youtube.com/watch?v=NqbcfSqPnLA">Roomba</a>/<a href="http://www.wiilovemario.com/Control+Your+Roomba+with+a+Wii+Balance+Board+or+Wiimote">Wiimote</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/02/22/roomba-with-a-view/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mount and Blade</title>
		<link>http://www.projectwhite.com/2009/01/15/mount-and-blade/</link>
		<comments>http://www.projectwhite.com/2009/01/15/mount-and-blade/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 10:25:07 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[games]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=77</guid>
		<description><![CDATA[Just a quick, blatant, plug. Everyone should download and purchase Mount and Blade.]]></description>
			<content:encoded><![CDATA[<p>Just a quick, blatant, plug. Everyone should download and purchase <a href="http://www.taleworlds.com/">Mount and Blade</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/01/15/mount-and-blade/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Freezebubbles</title>
		<link>http://www.projectwhite.com/2009/01/08/freezebubbles/</link>
		<comments>http://www.projectwhite.com/2009/01/08/freezebubbles/#comments</comments>
		<pubDate>Thu, 08 Jan 2009 21:12:36 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[bubble]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=75</guid>
		<description><![CDATA[I believe that it&#8217;s already been posted on a number of other blogs, but these photos of frozen bubbles is awesome.]]></description>
			<content:encoded><![CDATA[<p>I believe that it&#8217;s already been posted on a number of other blogs, but these <a href="http://www.skipweasel.pwp.blueyonder.co.uk/freezebubbles/album/index.html">photos of frozen bubbles</a> is awesome.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/01/08/freezebubbles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>You sunk my battleship &#8211; part 3</title>
		<link>http://www.projectwhite.com/2009/01/06/you-sunk-my-battleship-part-3/</link>
		<comments>http://www.projectwhite.com/2009/01/06/you-sunk-my-battleship-part-3/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 21:23:19 +0000</pubDate>
		<dc:creator>ben</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[eve online]]></category>
		<category><![CDATA[mssql]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.projectwhite.com/?p=64</guid>
		<description><![CDATA[Continuing from part 2 of the ongoing missing data saga, my Eve Online alliance had managed to loose over 3 months of data, following a hard drive failure in our alliance&#8217;s web server. Although the most recent data could be recovered using Eve&#8217;s API, and data feeds from other alliances, much of the data was [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing from <a href="http://www.projectwhite.com/2009/01/06/you-sunk-my-battleship-part-2you-sunk-my-battleship-part-2/">part 2</a> of the ongoing missing data saga, my <a href="http://www.eve-online.com/">Eve Online</a> <a href="http://www.iron-alliance.com/">alliance</a> had managed to loose over 3 months of data, following a hard drive failure in our alliance&#8217;s web server. Although the most recent data could be recovered using Eve&#8217;s API, and data feeds from other alliances, much of the data was unrecoverable. In part 2 we had successfully copied historic killmails from other alliance&#8217;s killboards, and stored them locally in a database.</p>
<p>Although the collection process outlined in part 2 is still running, it is estimated that we&#8217;ll end up with approximately 70,000 raw killmails which mention our alliance (from the predicted total of 6million). Looking at the killmails themselves, many are duplicated. This is because both the victim, and the pilot who landed the final blow, receive a copy of the killmail; and where more than one alliance is attacking, each alliance will copy the killmail to their own killboard. Of the 70,000 killmails, approximately 25,000 are duplicates, and can be ignored.</p>
<p>De-duping SQL tables is a bit of a nightmare prior to MSSQL 2005. You have to produce a subquery in order to find the latest record for each group, and then delete all others. It&#8217;s fairly prone to error if you&#8217;re not sure what you&#8217;re doing. Fortunately, MSSQL 2005 solves this problem with the introduction of the RANK() keyword. RANK() will give an integer column of where a particular record ranks within a group, for example:<br />
<!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">SELECT</span> kID, iID, killmail, posted,uploaded, RANK() <span class="kwrd">OVER</span> (PARTITION <span class="kwrd">BY</span> <span class="kwrd">SUBSTRING</span>(killmail, 0, 50) <span class="kwrd">ORDER</span> <span class="kwrd">BY</span> kID, iID) <span class="kwrd">AS</span> rnk <span class="kwrd">FROM</span> ekKillmail</pre>
<p>A sixth column, rnk, will rank the records in order of kID and iID. We only group on the first 50 characters of the killmail, as this speeds things up slightly. The timestamp, victim, and lost ship are covered in these first 50 characters, and provide a unique enough record identifier.<br />
In order to get the first record for each group, we push the above query into a subselect:<br />
<!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">SELECT</span> kID, iID, killmail, uploaded <span class="kwrd">FROM</span>
 (<span class="kwrd">SELECT</span> kID, iID, killmail, posted,uploaded, RANK() <span class="kwrd">OVER</span> (PARTITION <span class="kwrd">BY</span> <span class="kwrd">SUBSTRING</span>(killmail, 0, 50) <span class="kwrd">ORDER</span> <span class="kwrd">BY</span> kID, iID) <span class="kwrd">AS</span> rnk <span class="kwrd">FROM</span> ekKillmail) <span class="kwrd">AS</span> k
 <span class="kwrd">WHERE</span> k.rnk &gt; 1</pre>
<p>This instantly de-duplicates our killmails, giving us about 50,000 killmails to process. I should mention that there&#8217;s an excellent guide to the RANK() keywork on <a href="http://rafael-salas.blogspot.com/2007/04/remove-duplicates-using-t-sql-rank.html">Rafeal Salas&#8217; blog</a>.</p>
<p>We can reduce this 50,000 figure further still by filtering records on date. As mentioned at the start of this story, only 3 months of records were lost, whereas we&#8217;re requesting killmails from other alliances&#8217; killboards for as long as they&#8217;ve been active. Looking at the data we&#8217;ve gathered, some killmails are as early as 2005. Although each killmail begins with a timestamp of when the kill happened, this is stored as text, and is very difficult to filter on. This is a relatively easy thing to fix, as we can simply cast the first 17 characters (which represent the date/time), into a datetime data type.<br />
<!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">UPDATE</span> ekKillmail <span class="kwrd">SET</span> posted = <span class="kwrd">CAST</span>(<span class="kwrd">SUBSTRING</span>(killmail, 0, 17) <span class="kwrd">AS</span> DATETIME) <span class="kwrd">WHERE</span> posted <span class="kwrd">IS</span> NULL</pre>
<p>Meaning we can expand our killmail query to then filter on the date and time of the kill (posted column):<br />
<!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode"><span class="kwrd">SELECT</span> kID, iID, killmail, uploaded <span class="kwrd">FROM</span>
 (<span class="kwrd">SELECT</span> kID, iID, killmail, posted,uploaded, RANK() <span class="kwrd">OVER</span> (PARTITION <span class="kwrd">BY</span> <span class="kwrd">SUBSTRING</span>(killmail, 0, 50) <span class="kwrd">ORDER</span> <span class="kwrd">BY</span> kID, iID) <span class="kwrd">AS</span> rnk <span class="kwrd">FROM</span> ekKillmail) <span class="kwrd">AS</span> k
 <span class="kwrd">WHERE</span> k.rnk &gt; 1
 <span class="kwrd">AND</span> k.posted &gt; <span class="str">'2008-09-24 00:00'</span>
 <span class="kwrd">AND</span> k.posted &lt; <span class="str">'2009-01-06 00:00'</span></pre>
<p>This reduces the number of killmails we have to upload back to our alliance killboard to a much more manageable 5,000. We now need to tackle the uploading process.</p>
<p>Uploading killmails manually to our <a href="http://www.iron-alliance.com/">alliance&#8217;s killboard</a> is a fairly rare occurrence, the website itself uses <a href="http://www.eve-online.com/">Eve Online&#8217;s</a> <a href="http://wiki.eveonline.com/wiki/API">API</a> to make frequent queries on each pilot&#8217;s kills, as well as pull kills from other alliances&#8217; killboards. However as we learnt in part 2, these data feeds only go back a few days, or shorter. Prior to the Eve Online API, pilots had to copy and paste killmails from their Eve Online client, into a web form on the alliance&#8217;s website. This form is still available, however it is restricted to authenticated users &#8211; preventing random internet users from posting fictitious killmails.</p>
<p>Authentication is based upon VBulletin, which uses cookies and sessions to keep track of the user. Firefox&#8217;s <a href="https://addons.mozilla.org/en-US/firefox/addon/60">Web Developer</a> add-on will allow you to inspect cookies within a given session, so its then just a case of copying them into our C# page request/post.<br />
<!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode">        <span class="kwrd">static</span> <span class="kwrd">void</span> writeKills()
        {
            <span class="rem">//Declarations</span>
            SqlConnection DBConn;
            SqlDataAdapter DBAdapt;
            DataTable DBTable;
            <span class="kwrd">int</span> i;

            <span class="rem">//Connect to DB</span>
            DBConn = <span class="kwrd">new</span> SqlConnection(<span class="str">"Data Source=SERVER\\SQLEXPRESS;Initial Catalog=eveKills;User Id=sa;Password=secret;MultipleActiveResultSets=True;"</span>);
            DBConn.Open();

            <span class="rem">//Get killmails</span>
            DBTable = <span class="kwrd">new</span> DataTable();
            DBAdapt = <span class="kwrd">new</span> SqlDataAdapter(<span class="str">"SELECT kID, iID, killmail, uploaded FROM (SELECT kID, iID, killmail, posted,uploaded, RANK() OVER (PARTITION BY SUBSTRING(killmail, 0, 50) ORDER BY kID, iID) AS rnk FROM ekKillmail) AS k WHERE k.rnk = 1 AND k.posted &gt; '2008-09-24 00:00' AND k.posted &lt; '2009-01-06 00:00' AND uploaded IS NULL"</span>, DBConn);
            DBAdapt.Fill(DBTable);

            <span class="rem">//Loop through killmails</span>
            <span class="kwrd">for</span> (i = 0; i &lt; DBTable.Rows.Count; i++)
            {
                <span class="rem">//Process killmail</span>
                postKill(DBTable.Rows[i]);

            }
            <span class="rem">//Close DB Connection</span>
            DBConn.Close();
        }

        <span class="kwrd">static</span> <span class="kwrd">void</span> postKill(DataRow drKill)
        {
            <span class="rem">//Declarations</span>
            HttpWebRequest HRequest;
            HttpWebResponse HResponse;
            StreamReader RResponse;
            Stream Request;
            SqlConnection DBConn = <span class="kwrd">null</span>;
            SqlCommand DBComm;
            <span class="kwrd">string</span> sResp = <span class="kwrd">null</span>;
            <span class="kwrd">string</span> sRequ = <span class="kwrd">null</span>;

            <span class="rem">//Create HTTP Request</span>
            HRequest = (HttpWebRequest)WebRequest.Create(<span class="str">"http://www.iron-alliance.com/kb/post.php"</span>);
            <span class="rem">//Emulate an authenticated session</span>
            HRequest.CookieContainer = <span class="kwrd">new</span> CookieContainer();
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"bbuserid"</span>, <span class="str">"secret"</span>, <span class="str">"/"</span>, <span class="str">".iron-alliance.com"</span>));
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"bbsessionhash"</span>, <span class="str">"secret"</span>, <span class="str">"/"</span>, <span class="str">".iron-alliance.com"</span>));
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"bbpassword"</span>, <span class="str">"secret"</span>, <span class="str">"/"</span>, <span class="str">".iron-alliance.com"</span>));
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"bblastvisit"</span>, <span class="str">"secret"</span>, <span class="str">"/"</span>, <span class="str">".iron-alliance.com"</span>));
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"bblastactivity"</span>, <span class="str">"0"</span>, <span class="str">"/"</span>, <span class="str">".iron-alliance.com"</span>));
            HRequest.CookieContainer.Add(<span class="kwrd">new</span> Cookie(<span class="str">"vbulletin"</span>, <span class="str">"secret"</span>, <span class="str">"/"</span>, <span class="str">"www.iron-alliance.com"</span>));
            <span class="rem">//This is a POST, so change header accordingly</span>
            HRequest.Method = <span class="str">"POST"</span>;
            HRequest.ContentType = <span class="str">"application/x-www-form-urlencoded"</span>;
            <span class="rem">//POST Request Payload</span>
            sRequ = <span class="str">"killmail="</span> + drKill[2].ToString() + <span class="str">"&amp;Post=Post"</span>;
            HRequest.ContentLength = sRequ.Length;
            <span class="rem">//Make POST            </span>
            Request = HRequest.GetRequestStream();
            Request.Write(Encoding.ASCII.GetBytes(sRequ), 0, sRequ.Length);
            Request.Close();

            <span class="rem">//Read Response</span>
            HResponse = (HttpWebResponse)HRequest.GetResponse();
            RResponse = <span class="kwrd">new</span> StreamReader(HResponse.GetResponseStream());
            sResp = RResponse.ReadToEnd();

            <span class="rem">//Check response for keywords</span>
            <span class="kwrd">if</span> (sResp.IndexOf(<span class="str">"Success!"</span>) &gt; -1)
            {
                <span class="rem">//Kill posted successfully</span>
                sResp = <span class="str">"Success!"</span>;
            }

            <span class="kwrd">else</span> <span class="kwrd">if</span> (sResp.IndexOf(<span class="str">"already posted"</span>) &gt; -1)
            {
                <span class="rem">//Already posted</span>
                sResp = <span class="str">"Duplicate!"</span>;
            }
            <span class="kwrd">else</span> <span class="kwrd">if</span> (sResp.IndexOf(<span class="str">"problem!"</span>) &gt; -1)
            {
                <span class="rem">//Problem</span>
                sResp = <span class="str">"Problem! "</span> + sResp.Substring(19000, 1024);
                <span class="rem">//Write the killmail to a text file, so that we can deal with it later</span>
                File.WriteAllText(drKill[0].ToString() + <span class="str">"_"</span> + drKill[1].ToString() + <span class="str">".txt"</span>, drKill[2].ToString());
            }
            <span class="kwrd">else</span>
            {
                <span class="rem">//Other (not successful)</span>
                <span class="rem">//Write the killmail to a text file, so that we can deal with it later</span>
                File.WriteAllText(drKill[0].ToString() + <span class="str">"_"</span> + drKill[1].ToString() + <span class="str">".txt"</span>, drKill[2].ToString());
            }

            <span class="rem">//Connect to DB</span>
            DBConn = <span class="kwrd">new</span> SqlConnection(<span class="str">"Data Source=SERVER\\SQLEXPRESS;Initial Catalog=eveKills;User Id=sa;Password=secret;MultipleActiveResultSets=True;"</span>);
            DBConn.Open();
            <span class="rem">//Update killmail</span>
            DBComm = <span class="kwrd">new</span> SqlCommand(<span class="str">"UPDATE ekKillmail SET uploaded = GETDATE(), response = @P1 WHERE kID = @P2 AND iID = @P3"</span>, DBConn);
            DBComm.Parameters.AddWithValue(<span class="str">"@P1"</span>, sResp);
            DBComm.Parameters.AddWithValue(<span class="str">"@P2"</span>, drKill[0]);
            DBComm.Parameters.AddWithValue(<span class="str">"@P3"</span>, drKill[1]);
            DBComm.ExecuteNonQuery();
            <span class="rem">//Close DB</span>
            DBConn.Close();
        }</pre>
<p>Finally, we read back the response of the killmail posting. The <a href="http://eve-id.net/forum/viewforum.php?f=1001">Eve Dev killboard</a> gives fairly good feedback on how a killmail posting went, so we can search for the phrase &#8220;Successful&#8221;,  &#8220;already exists&#8221;, or &#8220;problem&#8221; to determine the status of the posting. These messages correspond to a successful posting, a duplicate killmail being found, and a failed posting. In our code, we&#8217;ve caught the failed postings, and written the killmail out to a simple text file, so that a human can determine the cause of the problem. We&#8217;ve also written the status back to the database so that we don&#8217;t attempt to resubmit problematic killmails.</p>
<p>That&#8217;s it! Overall, about 5,000 killmails were recovered, with about 400 failing to submit to the <a href="http://www.iron-alliance.com/">alliance killboard</a>. It took approximately 72 hours to mine all the original killmails, partly due to throttling on the remote web servers (at its peak, I was downloading killmails at a rate of 300kb/s), and approximately 2 hours to filter and submit killmails to our killboard.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.projectwhite.com/2009/01/06/you-sunk-my-battleship-part-3/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
