<?xml version="1.0"?>
<rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007" xmlns:atom="http://www.w3.org/2005/Atom">
   <channel>
      <title>Lifestream considered</title>
      <description>Pipes Output</description>
      <link>http://pipes.yahoo.com/pipes/pipe.info?_id=ADbNqOil3BGGzfPa6kjTQA</link>
      <atom:link rel="next" href="http://pipes.yahoo.com/pipes/pipe.run?_id=ADbNqOil3BGGzfPa6kjTQA&amp;_render=rss&amp;page=2"/>
      <pubDate>Thu, 01 Oct 2015 23:04:54 +0000</pubDate>
      <generator>http://pipes.yahoo.com/pipes/</generator>
      <item>
         <title>Enabling Google Books, Maps (and other apps) via the Google Apps Admin Panel</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/GnbfSsL9V48/</link>
         <description>&lt;p&gt;Recently, I received an email from a user of one of the Google Apps domains that I administrate. They were having the problem that if they visited &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://books.google.com/&quot;&gt;Google Books&lt;/a&gt; or &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://maps.google.com/&quot;&gt;Maps&lt;/a&gt; and tried to sign in with their account, they would receive an error message stating that they were not allowed to log in, as the service had no been enabled on their domain. Interesting. I didn&amp;#8217;t remember ever turning it on for any of the other domains I administrate either.&lt;/p&gt;

&lt;p&gt;So, I checked whether I could log in with one of my accounts on a different domain. I could. Trying with the administrator account for the problem domain though I had no luck. Searching the internet for this issue, I found nothing. Searching the Google Apps admin help pages, I found nothing. After about an hour of poking at the admin controls, I finally hit upon the answer.&lt;/p&gt;

&lt;p&gt;So, for anyone else out there who&amp;#8217;s having similar problems, here&amp;#8217;s what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://admin.google.com/&quot;&gt;Admin Control Panel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Click the &amp;#8220;More Controls&amp;#8221; link (it&amp;#8217;s at the bottom of the page).&lt;/li&gt;
&lt;li&gt;Choose &amp;#8220;Other Google Services&amp;#8221;.&lt;/li&gt;
&lt;li&gt;Click the &amp;#8220;Filters&amp;#8221; logo at the top right of the page.&lt;/li&gt;
&lt;li&gt;Untick &amp;#8220;Show top featured services&amp;#8221; (this was the magic bit that had me stumped for a long time).&lt;/li&gt;
&lt;li&gt;Choose services you want to turn on. For me, it was &amp;#8220;Google Books&amp;#8221; and &amp;#8220;Google Maps&amp;#8221;. There are a lot of other hidden services in there too.&lt;/li&gt;
&lt;li&gt;After turning on the services, you&amp;#8217;ll receive a message saying that it might take 24 hours for the changes to propagate. They propagated pretty much immediately for me, and I was able to start using the apps straight away.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully this ends up being useful for someone else out there too, and saves them the head scratching that I had to go through.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2014/02/enabling-google-books-maps-and-other-apps-via-the-google-apps-admin-panel/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=507</guid>
         <pubDate>Mon, 03 Feb 2014 23:30:31 +0000</pubDate>
         <content:encoded><![CDATA[<p>Recently, I received an email from a user of one of the Google Apps domains that I administrate. They were having the problem that if they visited <a rel="nofollow" target="_blank" href="http://books.google.com/">Google Books</a> or <a rel="nofollow" target="_blank" href="http://maps.google.com/">Maps</a> and tried to sign in with their account, they would receive an error message stating that they were not allowed to log in, as the service had no been enabled on their domain. Interesting. I didn&#8217;t remember ever turning it on for any of the other domains I administrate either.</p>

<p>So, I checked whether I could log in with one of my accounts on a different domain. I could. Trying with the administrator account for the problem domain though I had no luck. Searching the internet for this issue, I found nothing. Searching the Google Apps admin help pages, I found nothing. After about an hour of poking at the admin controls, I finally hit upon the answer.</p>

<p>So, for anyone else out there who&#8217;s having similar problems, here&#8217;s what I did:</p>

<ul>
<li>Log in to the <a rel="nofollow" target="_blank" href="https://admin.google.com/">Admin Control Panel</a></li>
<li>Click the &#8220;More Controls&#8221; link (it&#8217;s at the bottom of the page).</li>
<li>Choose &#8220;Other Google Services&#8221;.</li>
<li>Click the &#8220;Filters&#8221; logo at the top right of the page.</li>
<li>Untick &#8220;Show top featured services&#8221; (this was the magic bit that had me stumped for a long time).</li>
<li>Choose services you want to turn on. For me, it was &#8220;Google Books&#8221; and &#8220;Google Maps&#8221;. There are a lot of other hidden services in there too.</li>
<li>After turning on the services, you&#8217;ll receive a message saying that it might take 24 hours for the changes to propagate. They propagated pretty much immediately for me, and I was able to start using the apps straight away.</li>
</ul>

<p>Hopefully this ends up being useful for someone else out there too, and saves them the head scratching that I had to go through.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/GnbfSsL9V48" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Pulled Pork on the Gas BBQ</title>
         <link>http://neilsnoms.com/pulled-pork-on-the-gas-bbq/</link>
         <description>So, last week I had some folks round for a BBQ, and as is my want, I made pulled pork. Truth be told, I was a bit nervous about it, as there were various folks there who I respect a good darn bit when it comes to BBQ and meat in general. So, I was [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=129</guid>
         <pubDate>Sat, 20 Jul 2013 20:23:11 +0000</pubDate>
         <content:encoded><![CDATA[<p><img src="http://distilleryimage3.ak.instagram.com/b05ee5240cd211e3bb4e22000aaa0771_7.jpg" alt="Pulled Pork"></p>

<p>So, last week I had some folks round for a BBQ, and as is my want, I made pulled pork. Truth be told, I was a bit nervous about it, as there were various folks there who I respect a good darn bit when it comes to BBQ and meat in general. So, I was very happy when the verdicts came in, and there were minor demands for the recipe.</p>

<p>So, here it is. This is, of course, just how I do it. There&#8217;ll, no doubt, be people who&#8217;ll turn round and say &#8220;no no no!&#8221;. To them I say, &#8220;No pork for you!&#8221;</p>

<p><span id="more-129"></span></p>

<h2>Ingredients</h2>

<h3>The rub</h3>

<ul>
<li>8 tablespoons paprika</li>
<li>8 tablespoons soft brown sugar</li>
<li>4 teaspoons garlic powder</li>
<li>4 teaspoons mustard powder</li>
<li>4 teaspoons onion powder</li>
<li>8 teaspoons sea salt flakes</li>
<li>4 teaspoons cayenne pepper</li>
</ul>

<h3>The meat</h3>

<ul>
<li>3.5kg pork shoulder, bone out. Served 10-15, with other burgers and sausages on the side.</li>
</ul>

<h2>Equipment</h2>

<ul>
<li><a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/BearPaws-Handler-Perfect-Serving-Roasted/dp/B003IWI66W/">Bear Paws</a></li>
<li><a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/eKitch-digital-probe-thermometer-timer/dp/B003SOC7P6/">Digital meat thermometer</a></li>
<li>A thermometer for measuring the temperature of your BBQ</li>
<li>Le Creuset Oval Stoneware dish</li>
<li>Latex gloves</li>
<li>String</li>
<li>3-4 burner gas BBQ</li>
</ul>

<h2>The instructions</h2>

<h3>Preparing the meat</h3>

<p>At least 48 hours before you want to start eating lovely pulled pork, mix all the dry ingredients together well in a bowl. You&#8217;re safe to use the bowl and a spoon at this point &#8211; no latex gloves are necessary yet.</p>

<p><img src="http://distilleryimage7.ak.instagram.com/60e5d044e8d711e28d4922000aa821c8_7.jpg" alt="The dry rub, combined"></p>

<p>Once you&#8217;ve got your rub ready, the fun begins. The reason why I suggest a big pork shoulder joint with the bone out is because I find that it makes it a lot easier to get the rub giving flavour throughout the entire joint. Now, a lot of people say that the bone is where the flavour is, and that&#8217;s where I began when I first started making pulled pork. For me though, it&#8217;s both easier to find bone out, and easier to get great flavour with it.</p>

<p>Put your latest gloves on.</p>

<p>So, get your pork shoulder ready for the rub. Chances are that because you bought a bone out joint, it&#8217;ll be tightly tied with string. Cut that sucker away &#8211; for now you don&#8217;t need it. You&#8217;ll find once the string is gone that the meat will unroll, leaving you with lots of nooks and crannies and flaps of meat. Great!</p>

<p>Make sure your latex gloves are still on, and your pork is in your earthenware dish.</p>

<p>Start rubbing your meat. Start gently, making sure you massage the rub deeply in. As you get going you can afford to be a little rougher on it. Remember, you want your rub to permeate the meat, giving it lots of flavour. Get into every single nook and cranny. I tend to find that I have to go over the shoulder twice with the rub before I use it all up.</p>

<p><img src="http://distilleryimage5.ak.instagram.com/f080db860b6e11e383d022000aaa0956_7.jpg" alt="The meat, rubbed"></p>

<p>Once your meat is covered, use your new string to tie the pork into a nice tight package again. Cover the pork and bowl with clingfilm (I like to use a few layers), and put it securely in the fridge for a day. You could just do this overnight, but I like to give my pork 36 hours to think about what its fate will be.</p>

<h3>Cooking the meat</h3>

<p><img src="http://distilleryimage1.ak.instagram.com/6dcd65620c7f11e389a722000a9e28d6_7.jpg" alt="Rubbed for a day; look at those juices"></p>

<p>On the morning of your BBQ, get your meat out of the fridge and get your BBQ warmed up. You&#8217;ll only want to have one burner turned on. If you&#8217;re going to be smoking your pork (I try, but I&#8217;m still not convinced it&#8217;s having the most effect), then make sure your wood is prepared and ready to go. </p>

<p><img src="http://distilleryimage4.ak.instagram.com/f3d32df40c7f11e3894722000ae90157_7.jpg" alt="Firing up the BBQ"></p>

<p>Stick your meat thermometer into the thickest part of the meat, and make sure you leave the beep half somewhere that you&#8217;ll be able to hear it.</p>

<p>Stick the meat in the BBQ (still in the earthenware dish) and close the lid. You&#8217;ll want to keep your meat of direct heat. I do this by precariously balancing my meat on the cooling rack inside the BBQ on the opposite side to the burner that I&#8217;m using.</p>

<p><img src="http://distilleryimage10.ak.instagram.com/f39371140cc511e3a96022000a1fd150_7.jpg" alt="Ready to be pulled"></p>

<p>Now, temperatures and times. You&#8217;ll be wanting to stick your meat into the BBQ 9-10 hours before you&#8217;re wanting to eat it. A long time, yes, but really worth it. Try and keep the BBQ&#8217;s temperature to around about 150 Celcius. Better to have the temperature a little too low than a little too high in my book. Set the meat thermometer so that it goes off at 92 Celcius.</p>

<p>Low and slow. Here&#8217;s some <a rel="nofollow" target="_blank" href="http://www.amazingribs.com/tips_and_technique/meat_science.html">science</a>.</p>

<h3>Shredding and eating the meat</h3>

<p>9 hours later the alarm will go off, the pork will be ready to sit for half an hour and cool. During this time, people will be baying for your blood because they&#8217;ll have smelt this cooking for hours. Throw them some nibbles and keep them satiated.</p>

<p>Once the meat it cool enough to handle, pour the juices that will have gathered in the earthenware dish to one side, snip off your string from the pork, remove the top layer of fat, and then rip to shreds with the <a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/BearPaws-Handler-Perfect-Serving-Roasted/dp/B003IWI66W/">Bear Paws</a>. I cannot overstate how much I love these things. They make pulling pork so ridiculously easy. Love them.</p>

<p>As you open up the pork, you may find that you see some rub that didn&#8217;t get absorbed by the pork. This is all fine and good. It&#8217;ll all get absorbed now as you pull the pork with the Bear Paws anyway.</p>

<p>If I&#8217;m feeling unhurried by people, I&#8217;ll reduce down the juices in a pan for a couple of minutes, to make a tasty dipping sauce. Otherwise, I just bring the earthenware bowl to the table, provide a ridiculous number of buns and some BBQ sauce, and tell everyone to dig in.</p>

<h2>What have I learned over the last year?</h2>

<p>I&#8217;ve been making this pork for about a year now, and have gone through various iterations. Here&#8217;s what I&#8217;ve learned:</p>

<ul>
<li>I much prefer bone out to bone in. I end up with more flavour in the meat that way. Your mileage my vary.</li>
<li>You can&#8217;t overdo the amount of rub. At least, I&#8217;ve not managed to yet. I&#8217;m currently using about twice as much per Kg of meat than I did that first time.</li>
<li>Originally I set the pork straight on the grill in the BBQ, letting the juices drip away. Since I started cooking the pork in the earthenware bowl the meat has been far juicier in the final serving.</li>
<li>Bear Paws cannot be underestimated.</li>
<li>The pork will cook a good couple of hours faster in the heat of summer than in the depths of winter. Science. Who knew, eh?</li>
</ul>]]></content:encoded>
      </item>
      <item>
         <title>Making PHP CodeSniffer use JSLint via Rhino</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/QRvGrDy54iI/</link>
         <description>&lt;p&gt;Last week at work, we started writing some JavaScript for the project we&amp;#8217;re working on. Up until now we&amp;#8217;ve been very much focusing on core functionality, but we&amp;#8217;re at the stage now where writing some JavaScript makes sense.  One of the things that we&amp;#8217;ve been doing up un til this point, and has been making sense for us, is to use &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://pear.php.net/package/PHP_CodeSniffer/&quot;&gt;PHP Code Sniffer&lt;/a&gt; to help make sure that the PHP and CSS we&amp;#8217;re writing adheres to known standards and has a maintainable shape.&lt;/p&gt;

&lt;p&gt;So, since PHP Code Sniffer can also run &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.jslint.com/&quot;&gt;JSLint&lt;/a&gt;, we thought we&amp;#8217;d turn on JavaScript sniffing as well.  It all sounds so easy, doesn&amp;#8217;t it?&lt;/p&gt;

&lt;p&gt;Ultimately, it is pretty easy to get PHP Code Sniffer running JSLint, but there were a whole bunch of hurdles that ended up taking me a couple of days to get over. So, I thought a blog post was in order. Here&amp;#8217;s what you need to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Have a working installation of Java.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have a working copy of PHP Code Sniffer, installed via PEAR.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have a working installation of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.mozilla.org/rhino/&quot;&gt;Rhino&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Depending on your system you&amp;#8217;ll want to do one of two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The simplest option is to install a Rhino binary, by doing something like the following on your system:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apt-get install rhino
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will put a &lt;code&gt;rhino&lt;/code&gt; script on your executable path, and you&amp;#8217;re good to go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alternatively, you&amp;#8217;ll need to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.mozilla.org/rhino/download.html&quot;&gt;download Rhino&lt;/a&gt; from Mozilla&amp;#8217;s website. Unfortunately, this download doesn&amp;#8217;t contain a &lt;code&gt;rhino&lt;/code&gt; passthrough script (which PHP Code Sniffer will later need), so we&amp;#8217;ll need to create one. Thankfully it&amp;#8217;s pretty simple, and can look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
java -jar `dirname $0`/js.jar $@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we&amp;#8217;ve made the assumption that we&amp;#8217;ve put the &lt;code&gt;rhino&lt;/code&gt; shell script and the &lt;code&gt;js.jar&lt;/code&gt; file (the only file we need from the download) into the same directory.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a JSLint file that Rhino can use.&lt;/p&gt;

&lt;p&gt;For this, you&amp;#8217;ll need to travel back in time to before Crockford stopped supporting Rhino. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/douglascrockford/JSLint/raw/ca120a731db548c0014320fa0c196edc613536ae/rhino.js&quot;&gt;last version of the &lt;code&gt;rhino.js&lt;/code&gt;&lt;/a&gt; file from GitHub.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://github.com/douglascrockford/JSLint/raw/master/fulljslint.js&quot;&gt;latest version of &lt;code&gt;fulljslint.js&lt;/code&gt;&lt;/a&gt; from Github.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concatenate the two files together.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat fulljslint.js rhino.js &amp;gt; ultimatejslint.js
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tell PHP Code Sniffer where your &lt;code&gt;rhino&lt;/code&gt; and &lt;code&gt;ultimatejslint.js&lt;/code&gt; files are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;phpcs --config-set rhino_path /path/to/rhino
phpcs --config-set jslint_path /path/to/jslint.js
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run PHP Code Sniffer with a standard that knows about JSLint.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Either use the Squiz standard: &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;phpcs --Standard=Squiz .
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Or, add the Squiz JSLint Sniff to your own standard. &lt;/p&gt;

&lt;p&gt;In your standard&amp;#8217;s &lt;code&gt;getIncludedSniffs()&lt;/code&gt; function, add the following Sniff to the returned array:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;'Squiz/Sniffs/Debug/JSLint.php'
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that&amp;#8217;s it. There&amp;#8217;s a few steps, but once you&amp;#8217;ve done them once, JSLint issues will show up as warning in your reporting.  If you want to change the flags that JSLint has turned on, you&amp;#8217;ll need to update the array at the start of the &lt;code&gt;rhino.js&lt;/code&gt; file.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2011/04/making-php-codesniffer-use-jslint-via-rhino/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=505</guid>
         <pubDate>Sun, 03 Apr 2011 18:15:12 +0000</pubDate>
         <content:encoded><![CDATA[<p>Last week at work, we started writing some JavaScript for the project we&#8217;re working on. Up until now we&#8217;ve been very much focusing on core functionality, but we&#8217;re at the stage now where writing some JavaScript makes sense.  One of the things that we&#8217;ve been doing up un til this point, and has been making sense for us, is to use <a rel="nofollow" target="_blank" href="http://pear.php.net/package/PHP_CodeSniffer/">PHP Code Sniffer</a> to help make sure that the PHP and CSS we&#8217;re writing adheres to known standards and has a maintainable shape.</p>

<p>So, since PHP Code Sniffer can also run <a rel="nofollow" target="_blank" href="http://www.jslint.com/">JSLint</a>, we thought we&#8217;d turn on JavaScript sniffing as well.  It all sounds so easy, doesn&#8217;t it?</p>

<p>Ultimately, it is pretty easy to get PHP Code Sniffer running JSLint, but there were a whole bunch of hurdles that ended up taking me a couple of days to get over. So, I thought a blog post was in order. Here&#8217;s what you need to do:</p>

<ol>
<li><p>Have a working installation of Java.</p></li>
<li><p>Have a working copy of PHP Code Sniffer, installed via PEAR.</p></li>
<li><p>Have a working installation of <a rel="nofollow" target="_blank" href="http://www.mozilla.org/rhino/">Rhino</a>.</p>

<p>Depending on your system you&#8217;ll want to do one of two things:</p>

<ul>
<li><p>The simplest option is to install a Rhino binary, by doing something like the following on your system:</p>

<pre><code>apt-get install rhino
</code></pre>

<p>This will put a <code>rhino</code> script on your executable path, and you&#8217;re good to go.</p></li>
<li><p>Alternatively, you&#8217;ll need to <a rel="nofollow" target="_blank" href="http://www.mozilla.org/rhino/download.html">download Rhino</a> from Mozilla&#8217;s website. Unfortunately, this download doesn&#8217;t contain a <code>rhino</code> passthrough script (which PHP Code Sniffer will later need), so we&#8217;ll need to create one. Thankfully it&#8217;s pretty simple, and can look like this:</p>

<pre><code>#!/bin/sh
java -jar `dirname $0`/js.jar $@
</code></pre>

<p>Here, we&#8217;ve made the assumption that we&#8217;ve put the <code>rhino</code> shell script and the <code>js.jar</code> file (the only file we need from the download) into the same directory.</p></li>
</ul></li>
<li><p>Create a JSLint file that Rhino can use.</p>

<p>For this, you&#8217;ll need to travel back in time to before Crockford stopped supporting Rhino. </p>

<ol>
<li><p>Download the <a rel="nofollow" target="_blank" href="https://github.com/douglascrockford/JSLint/raw/ca120a731db548c0014320fa0c196edc613536ae/rhino.js">last version of the <code>rhino.js</code></a> file from GitHub.</p></li>
<li><p>Download the <a rel="nofollow" target="_blank" href="https://github.com/douglascrockford/JSLint/raw/master/fulljslint.js">latest version of <code>fulljslint.js</code></a> from Github.</p></li>
<li><p>Concatenate the two files together.</p>

<pre><code>cat fulljslint.js rhino.js &gt; ultimatejslint.js
</code></pre></li>
</ol></li>
<li><p>Tell PHP Code Sniffer where your <code>rhino</code> and <code>ultimatejslint.js</code> files are:</p>

<pre><code>phpcs --config-set rhino_path /path/to/rhino
phpcs --config-set jslint_path /path/to/jslint.js
</code></pre></li>
<li><p>Run PHP Code Sniffer with a standard that knows about JSLint.  </p>

<ul>
<li><p>Either use the Squiz standard: </p>

<pre><code>phpcs --Standard=Squiz .
</code></pre></li>
<li><p>Or, add the Squiz JSLint Sniff to your own standard. </p>

<p>In your standard&#8217;s <code>getIncludedSniffs()</code> function, add the following Sniff to the returned array:</p>

<pre><code>'Squiz/Sniffs/Debug/JSLint.php'
</code></pre></li>
</ul></li>
</ol>

<p>And that&#8217;s it. There&#8217;s a few steps, but once you&#8217;ve done them once, JSLint issues will show up as warning in your reporting.  If you want to change the flags that JSLint has turned on, you&#8217;ll need to update the array at the start of the <code>rhino.js</code> file.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/QRvGrDy54iI" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Dev Checks – Improving code quality by getting developers to look at each other’s work</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/9yDROqGdfoo/</link>
         <description>&lt;p&gt;I&amp;#8217;ve been working on the BBC&amp;#8217;s Homepage for about a year now, leading a team of five front-end developers to create a high quality product.&lt;/p&gt;

&lt;p&gt;One of the processes that I introduced to the team about six months ago was that of a formal &amp;#8220;dev check&amp;#8221; after every task that we completed from our backlog.  Whilst we call this process a dev check within our team, it could just as easily be called a peer review, or mini code review.&lt;/p&gt;

&lt;p&gt;Up until the point that I introduced the dev check it had not been uncommon for a single person to work on a task, and for code to go through the testing environments and onto live without a single other human ever reading their code. Not the best situation to be in, and it meant that we ended up having more annoying bugs showing up on our test environments than we should have.  These bugs were often things that a simple bit of human scrutiny would have caught, and we ended up wasting time going back and fixing them after the fact.  Working this way also meant that we ended up with certain areas of the homepage that could only ever be worked on by certain people, because they were the only ones who had ever seen the code.&lt;/p&gt;

&lt;p&gt;Like I said; not the best situation to be in.&lt;/p&gt;

&lt;p&gt;So, six months ago, we introduced the formal dev check &amp;#8211; a step to be completed for every single code related task in our backlog.  And, I&amp;#8217;m happy to say it&amp;#8217;s been a very successful process for us &amp;#8211; we now have far fewer bugs getting to test, and we have a lot more shared knowledge within the team.&lt;/p&gt;

&lt;h2&gt;What is a Dev Check?&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Before any task is committed to trunk, a developer who didn&amp;#8217;t work on it must say that they are happy with  how it&amp;#8217;s been completed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&amp;#8217;m hoping that if you&amp;#8217;re still reading at this point that you&amp;#8217;re wanting to find out what goes into a successful dev check&amp;#8230;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The task is &amp;#8220;completed&amp;#8221; by Rachel.&lt;/p&gt;

&lt;p&gt;At this point she has not committed anything to the trunk of the project. Depending on the size of the task, she might have created a development branch which she&amp;#8217;ll have been committing to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rachel asks another member of the development team to come and do a dev check. On this occasion she asks Jon.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Jon comes over to Rachel&amp;#8217;s desk where she will talk through all the changes she has made.&lt;/p&gt;

&lt;p&gt;As part of the discussion, Rachel may realise that some of the things she thought made sense in fact didn&amp;#8217;t. This is great, and she&amp;#8217;ll make the changes necessary and continue with the dev check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After Rachel has finished explaining what she&amp;#8217;s done for the task, and Jon&amp;#8217;s asked as many questions as he feels is necessary he&amp;#8217;ll either give the go ahead to commit the code to the trunk, or he&amp;#8217;ll request various changes to be made to the codebase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rachel will then commit to trunk, build in the team&amp;#8217;s test environment and pass off to the testers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And that&amp;#8217;s a dev check.&lt;/p&gt;

&lt;p&gt;Out of this process Jon has learnt about a bit of the codebase that he might not otherwise have seen, Jo realised that she needed to shore up a couple of her tests, and the codebase has come out feeling more healthy.  This is A Good Thing™.&lt;/p&gt;

&lt;h2&gt;What sort of things will the dev checker ask?&lt;/h2&gt;

&lt;p&gt;Up above there in the &amp;#8220;What is a Dev Check&amp;#8221; section you&amp;#8217;ll have read about Jon asking &amp;#8220;as many questions as he feels is necessary&amp;#8221;, and I&amp;#8217;m sure you&amp;#8217;ll have said to yourself &amp;#8220;But Neil, what are those questions? How will I know what&amp;#8217;s sensible to ask?&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Well, you&amp;#8217;re in luck. By a process of trial and error, as a team we&amp;#8217;ve come up with a bunch of questions that, if asked, will help to make sure that you both understand what&amp;#8217;s going on and can confirm that the code written is of a high quality.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Have new tests been written?&lt;/p&gt;

&lt;p&gt;These might be Unit Tests, or Automated Front-End Tests, or Security Tests. What matters is that valid tests have been written to cover the new functionality. You should also make sure that any pre-existing tests make sense.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do all the tests still pass?&lt;/p&gt;

&lt;p&gt;It should be a no-brainer, but of course you should make sure that all the tests still pass. There&amp;#8217;s nothing worse that breaking The Build for the entire team just because you forgot to run a bunch of tests on your development machine first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are standards adhered to?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PHP Code Sniffer&lt;/li&gt;
&lt;li&gt;HTML/CSS Validation&lt;/li&gt;
&lt;li&gt;JSLint&lt;/li&gt;
&lt;li&gt;Whatever else works in your team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are important to us. We fail our builds if our code isn&amp;#8217;t of high enough quality. Just sayin&amp;#8217;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does what you&amp;#8217;ve written work across all the Level One browsers?&lt;/p&gt;

&lt;p&gt;Obviously this one&amp;#8217;s a bit web development specific as it is, but it&amp;#8217;s important in other spheres as well. Every piece of software that&amp;#8217;s written is expected to run in one or more environments, and you should at least smoke test in a known subset of them to make sure there are no nasty surprises for your dedicated testing team.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Can I see your diffs?&lt;/p&gt;

&lt;p&gt;Again, fairly obvious, but you should take a look to see what&amp;#8217;s changed since the last time the code was checked in. Don&amp;#8217;t just rely on the developer to remember what they&amp;#8217;ve changed &amp;#8211; I know I can&amp;#8217;t remember half the time. This is what machines are good at &amp;#8211; make use of them!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did any of the changes that were made affect any other code?&lt;/p&gt;

&lt;p&gt;This one should be obvious as well, but unfortunately it isn&amp;#8217;t. It&amp;#8217;s all too easy to look at the lines of code that have changed without looking at the later lines which make use of them. Don&amp;#8217;t forget to look at the whole system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is there anything that concerns you?&lt;/p&gt;

&lt;p&gt;The final question to ask, and in many cases the most important one. Oftentimes a developer will know that something smells a bit fishy, but keeps quiet about it in the hope that they won&amp;#8217;t get called on it.  By simply asking these questions though, we&amp;#8217;ve found that these things end up getting talked about, and we end up with better code because of it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;How long does a dev check take?&lt;/h2&gt;

&lt;p&gt;After reading all that, I wouldn&amp;#8217;t be surprised if you&amp;#8217;re thinking &amp;#8220;Woah! But how long does that all take? That seems like a long list of questions…&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Well, in my team, we find that a dev check will take a little less than 10% of the time that the code and tests took to write initially. So, if the task took an hour to complete, the dev check would take roughly 5 minutes. A three hour task would take 15 minutes, and so on.  It honestly doesn&amp;#8217;t take much time once you get into the swing of things.&lt;/p&gt;

&lt;h2&gt;The Power of Veto&lt;/h2&gt;

&lt;p&gt;One of the most important things about dev checks is that everyone on the team is equal. Rachel may be the team leader, but Jon can still challenge her code and say that actually she hasn&amp;#8217;t done everything required to &amp;#8220;pass&amp;#8221; the dev check.&lt;/p&gt;

&lt;p&gt;The person performing a dev check &lt;em&gt;always&lt;/em&gt; has power of veto to say that things, however small, need improving before code is allowed to be committed to the trunk.&lt;/p&gt;

&lt;p&gt;Ultimately, the team is responsible for its own output, and everyone should be invested in that.&lt;/p&gt;

&lt;h2&gt;What do dev checks achieve?&lt;/h2&gt;

&lt;p&gt;As I&amp;#8217;ve mentioned above, there are two main benefits to dev checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fewer bugs&lt;/li&gt;
&lt;li&gt;More knowledge of the codebase by more of the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essentially the team will be more effective.&lt;/p&gt;

&lt;h2&gt;How do you get buy in?&lt;/h2&gt;

&lt;p&gt;Whilst there are obvious benefits to dev checks, sometimes you&amp;#8217;ll need to gain buy-in from people before you can get started. Maybe it&amp;#8217;ll be team members who think that this extra process is unnecessary, or maybe it&amp;#8217;ll be The Boss who thinks that it&amp;#8217;ll all just take far too long. What do you say to them?&lt;/p&gt;

&lt;h3&gt;Getting Buy In From Team Members?&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Everyone is equal.&lt;/li&gt;
&lt;li&gt;Anyone is able to say that a dev check cannot yet be completed.&lt;/li&gt;
&lt;li&gt;The team is responsible for the quality of the team&amp;#8217;s output, not just one person.&lt;/li&gt;
&lt;li&gt;You won&amp;#8217;t end up getting stuck on a horrible portion of the codebase any more, just because you were the last person to write code for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Getting Buy In From The Boss?&lt;/h3&gt;

&lt;p&gt;If you&amp;#8217;re lucky, you won&amp;#8217;t need to get buy-in from The Boss, but in case you do, here are a couple of pointers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quality is improved, leading to fewer bugs and happier users.&lt;/li&gt;
&lt;li&gt;The amount of time spent on dev checking is smaller than than that which would be spent fixing the bugs that would otherwise get through. The project will go live sooner, and you&amp;#8217;ll have spent less money.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Improving the Dev Check&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Any bug that is found is an opportunity to learn and improve our process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, sometimes bugs will still get through. When they do, you need to sit down and work out why that happened.&lt;/p&gt;

&lt;p&gt;In the old world, we used to just accept that bugs happened, that they&amp;#8217;d get found, and we would fix them. No more! Now, any bug that is found is an opportunity to learn and improve our process.&lt;/p&gt;

&lt;p&gt;A real example of this happening came a few weeks ago. Tina had been doing her thing, updating a script that we use to help us with our release management. This was dev checked by Bradley, and as far as he was concerned the changes that had been made were good to go. So, he ticked off the dev check, and Tina carried on with her next task.&lt;/p&gt;

&lt;p&gt;Fast forward to a week later, and Paul was getting &lt;del&gt;down on the floor&lt;/del&gt; ready to give a presentation which required a screenshot of the script running. Unfortunately, it no longer worked &amp;#8211; shock horror! &lt;/p&gt;

&lt;p&gt;What had happened was that Bradley hadn&amp;#8217;t realised that the line of code that was changed had impacted on further lines in the script. Moreover, he&amp;#8217;d only seen the script run against the additional new requirements, and hadn&amp;#8217;t confirmed that it still ran against the original requirements. Whoops.&lt;/p&gt;

&lt;p&gt;What came out of this was an improvement to our dev checks &amp;#8211; if code has changed we need to make sure that nothing else in our code has been affected by that change. It sounds simple, but it was a failing that we had, so we improved upon it.&lt;/p&gt;

&lt;h2&gt;Why not just have a big code review?&lt;/h2&gt;

&lt;p&gt;Big code reviews are great, and are something I very much enjoyed participating in when I was at Yahoo!. Unfortunately, whilst they&amp;#8217;re very useful they&amp;#8217;re also pretty time consuming, and require a fair amount of setup and teardown time in order to be useful.&lt;/p&gt;

&lt;p&gt;Dev checks, on the other hand, are simple to get going with, only take a few minutes, and only have to involve a couple of people.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s not to say that you should get rid of larger code reviews. In my opinion they should still happen, but only for larger chunks of code. The formal dev check gives you the opportunity to review code and share knowledge often and with low cost.&lt;/p&gt;

&lt;h2&gt;Go forth and Dev Check!&lt;/h2&gt;

&lt;p&gt;And that&amp;#8217;s it.  If you&amp;#8217;re working in a team that has bugs, or has bottlenecks of a single person being the only person who knows about certain areas of your product, then start dev checking. You won&amp;#8217;t regret it.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2011/01/dev-checks/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=492</guid>
         <pubDate>Mon, 17 Jan 2011 21:44:20 +0000</pubDate>
         <content:encoded><![CDATA[<p>I&#8217;ve been working on the BBC&#8217;s Homepage for about a year now, leading a team of five front-end developers to create a high quality product.</p>

<p>One of the processes that I introduced to the team about six months ago was that of a formal &#8220;dev check&#8221; after every task that we completed from our backlog.  Whilst we call this process a dev check within our team, it could just as easily be called a peer review, or mini code review.</p>

<p>Up until the point that I introduced the dev check it had not been uncommon for a single person to work on a task, and for code to go through the testing environments and onto live without a single other human ever reading their code. Not the best situation to be in, and it meant that we ended up having more annoying bugs showing up on our test environments than we should have.  These bugs were often things that a simple bit of human scrutiny would have caught, and we ended up wasting time going back and fixing them after the fact.  Working this way also meant that we ended up with certain areas of the homepage that could only ever be worked on by certain people, because they were the only ones who had ever seen the code.</p>

<p>Like I said; not the best situation to be in.</p>

<p>So, six months ago, we introduced the formal dev check &#8211; a step to be completed for every single code related task in our backlog.  And, I&#8217;m happy to say it&#8217;s been a very successful process for us &#8211; we now have far fewer bugs getting to test, and we have a lot more shared knowledge within the team.</p>

<h2>What is a Dev Check?</h2>

<blockquote>
  <p>Before any task is committed to trunk, a developer who didn&#8217;t work on it must say that they are happy with  how it&#8217;s been completed.</p>
</blockquote>

<p>I&#8217;m hoping that if you&#8217;re still reading at this point that you&#8217;re wanting to find out what goes into a successful dev check&#8230;</p>

<ol>
<li><p>The task is &#8220;completed&#8221; by Rachel.</p>

<p>At this point she has not committed anything to the trunk of the project. Depending on the size of the task, she might have created a development branch which she&#8217;ll have been committing to.</p></li>
<li><p>Rachel asks another member of the development team to come and do a dev check. On this occasion she asks Jon.</p></li>
<li><p>Jon comes over to Rachel&#8217;s desk where she will talk through all the changes she has made.</p>

<p>As part of the discussion, Rachel may realise that some of the things she thought made sense in fact didn&#8217;t. This is great, and she&#8217;ll make the changes necessary and continue with the dev check.</p></li>
<li><p>After Rachel has finished explaining what she&#8217;s done for the task, and Jon&#8217;s asked as many questions as he feels is necessary he&#8217;ll either give the go ahead to commit the code to the trunk, or he&#8217;ll request various changes to be made to the codebase.</p></li>
<li><p>Rachel will then commit to trunk, build in the team&#8217;s test environment and pass off to the testers.</p></li>
</ol>

<p>And that&#8217;s a dev check.</p>

<p>Out of this process Jon has learnt about a bit of the codebase that he might not otherwise have seen, Jo realised that she needed to shore up a couple of her tests, and the codebase has come out feeling more healthy.  This is A Good Thing™.</p>

<h2>What sort of things will the dev checker ask?</h2>

<p>Up above there in the &#8220;What is a Dev Check&#8221; section you&#8217;ll have read about Jon asking &#8220;as many questions as he feels is necessary&#8221;, and I&#8217;m sure you&#8217;ll have said to yourself &#8220;But Neil, what are those questions? How will I know what&#8217;s sensible to ask?&#8221;.</p>

<p>Well, you&#8217;re in luck. By a process of trial and error, as a team we&#8217;ve come up with a bunch of questions that, if asked, will help to make sure that you both understand what&#8217;s going on and can confirm that the code written is of a high quality.</p>

<ul>
<li><p>Have new tests been written?</p>

<p>These might be Unit Tests, or Automated Front-End Tests, or Security Tests. What matters is that valid tests have been written to cover the new functionality. You should also make sure that any pre-existing tests make sense.</p></li>
<li><p>Do all the tests still pass?</p>

<p>It should be a no-brainer, but of course you should make sure that all the tests still pass. There&#8217;s nothing worse that breaking The Build for the entire team just because you forgot to run a bunch of tests on your development machine first.</p></li>
<li><p>Are standards adhered to?</p>

<ul>
<li>PHP Code Sniffer</li>
<li>HTML/CSS Validation</li>
<li>JSLint</li>
<li>Whatever else works in your team</li>
</ul>

<p>These are important to us. We fail our builds if our code isn&#8217;t of high enough quality. Just sayin&#8217;.</p></li>
<li><p>Does what you&#8217;ve written work across all the Level One browsers?</p>

<p>Obviously this one&#8217;s a bit web development specific as it is, but it&#8217;s important in other spheres as well. Every piece of software that&#8217;s written is expected to run in one or more environments, and you should at least smoke test in a known subset of them to make sure there are no nasty surprises for your dedicated testing team.</p></li>
<li><p>Can I see your diffs?</p>

<p>Again, fairly obvious, but you should take a look to see what&#8217;s changed since the last time the code was checked in. Don&#8217;t just rely on the developer to remember what they&#8217;ve changed &#8211; I know I can&#8217;t remember half the time. This is what machines are good at &#8211; make use of them!</p></li>
<li><p>Did any of the changes that were made affect any other code?</p>

<p>This one should be obvious as well, but unfortunately it isn&#8217;t. It&#8217;s all too easy to look at the lines of code that have changed without looking at the later lines which make use of them. Don&#8217;t forget to look at the whole system.</p></li>
<li><p>Is there anything that concerns you?</p>

<p>The final question to ask, and in many cases the most important one. Oftentimes a developer will know that something smells a bit fishy, but keeps quiet about it in the hope that they won&#8217;t get called on it.  By simply asking these questions though, we&#8217;ve found that these things end up getting talked about, and we end up with better code because of it.</p></li>
</ul>

<h2>How long does a dev check take?</h2>

<p>After reading all that, I wouldn&#8217;t be surprised if you&#8217;re thinking &#8220;Woah! But how long does that all take? That seems like a long list of questions…&#8221;.</p>

<p>Well, in my team, we find that a dev check will take a little less than 10% of the time that the code and tests took to write initially. So, if the task took an hour to complete, the dev check would take roughly 5 minutes. A three hour task would take 15 minutes, and so on.  It honestly doesn&#8217;t take much time once you get into the swing of things.</p>

<h2>The Power of Veto</h2>

<p>One of the most important things about dev checks is that everyone on the team is equal. Rachel may be the team leader, but Jon can still challenge her code and say that actually she hasn&#8217;t done everything required to &#8220;pass&#8221; the dev check.</p>

<p>The person performing a dev check <em>always</em> has power of veto to say that things, however small, need improving before code is allowed to be committed to the trunk.</p>

<p>Ultimately, the team is responsible for its own output, and everyone should be invested in that.</p>

<h2>What do dev checks achieve?</h2>

<p>As I&#8217;ve mentioned above, there are two main benefits to dev checking:</p>

<ul>
<li>Fewer bugs</li>
<li>More knowledge of the codebase by more of the team.</li>
</ul>

<p>Essentially the team will be more effective.</p>

<h2>How do you get buy in?</h2>

<p>Whilst there are obvious benefits to dev checks, sometimes you&#8217;ll need to gain buy-in from people before you can get started. Maybe it&#8217;ll be team members who think that this extra process is unnecessary, or maybe it&#8217;ll be The Boss who thinks that it&#8217;ll all just take far too long. What do you say to them?</p>

<h3>Getting Buy In From Team Members?</h3>

<ul>
<li>Everyone is equal.</li>
<li>Anyone is able to say that a dev check cannot yet be completed.</li>
<li>The team is responsible for the quality of the team&#8217;s output, not just one person.</li>
<li>You won&#8217;t end up getting stuck on a horrible portion of the codebase any more, just because you were the last person to write code for it.</li>
</ul>

<h3>Getting Buy In From The Boss?</h3>

<p>If you&#8217;re lucky, you won&#8217;t need to get buy-in from The Boss, but in case you do, here are a couple of pointers:</p>

<ul>
<li>Quality is improved, leading to fewer bugs and happier users.</li>
<li>The amount of time spent on dev checking is smaller than than that which would be spent fixing the bugs that would otherwise get through. The project will go live sooner, and you&#8217;ll have spent less money.</li>
</ul>

<h2>Improving the Dev Check</h2>

<blockquote>
  <p>Any bug that is found is an opportunity to learn and improve our process.</p>
</blockquote>

<p>Of course, sometimes bugs will still get through. When they do, you need to sit down and work out why that happened.</p>

<p>In the old world, we used to just accept that bugs happened, that they&#8217;d get found, and we would fix them. No more! Now, any bug that is found is an opportunity to learn and improve our process.</p>

<p>A real example of this happening came a few weeks ago. Tina had been doing her thing, updating a script that we use to help us with our release management. This was dev checked by Bradley, and as far as he was concerned the changes that had been made were good to go. So, he ticked off the dev check, and Tina carried on with her next task.</p>

<p>Fast forward to a week later, and Paul was getting <del>down on the floor</del> ready to give a presentation which required a screenshot of the script running. Unfortunately, it no longer worked &#8211; shock horror! </p>

<p>What had happened was that Bradley hadn&#8217;t realised that the line of code that was changed had impacted on further lines in the script. Moreover, he&#8217;d only seen the script run against the additional new requirements, and hadn&#8217;t confirmed that it still ran against the original requirements. Whoops.</p>

<p>What came out of this was an improvement to our dev checks &#8211; if code has changed we need to make sure that nothing else in our code has been affected by that change. It sounds simple, but it was a failing that we had, so we improved upon it.</p>

<h2>Why not just have a big code review?</h2>

<p>Big code reviews are great, and are something I very much enjoyed participating in when I was at Yahoo!. Unfortunately, whilst they&#8217;re very useful they&#8217;re also pretty time consuming, and require a fair amount of setup and teardown time in order to be useful.</p>

<p>Dev checks, on the other hand, are simple to get going with, only take a few minutes, and only have to involve a couple of people.</p>

<p>That&#8217;s not to say that you should get rid of larger code reviews. In my opinion they should still happen, but only for larger chunks of code. The formal dev check gives you the opportunity to review code and share knowledge often and with low cost.</p>

<h2>Go forth and Dev Check!</h2>

<p>And that&#8217;s it.  If you&#8217;re working in a team that has bugs, or has bottlenecks of a single person being the only person who knows about certain areas of your product, then start dev checking. You won&#8217;t regret it.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/9yDROqGdfoo" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Cuba Libre Oscuro</title>
         <link>http://neilsnoms.com/cuba-libre-oscuro/</link>
         <description>Whilst the mojito may be my favourite rum based drink, what I&amp;#8217;ll be found drink most often in the pub is a Dark Rum and Diet Coke. What I&amp;#8217;ll want to be drinking though, is my variation of the Cuba Libre &amp;#8211; the Cuba Libre Oscuro. A standard Cuba Libre blends the flavours of Cuba [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=116</guid>
         <pubDate>Fri, 20 Aug 2010 20:48:15 +0000</pubDate>
         <content:encoded><![CDATA[<p><img src="http://neilsnoms.com/wp-content/uploads/2010/08/IMG_9914.jpg" alt="Cuba Libre Oscura" title="Cuba Libre Oscura" width="500" height="333" class="alignnone size-full wp-image-118"/></p>

<p>Whilst the <a rel="nofollow" target="_blank" href="http://neilsnoms.com/strained-mojito/">mojito</a> may be my favourite rum based drink, what I&#8217;ll be found drink most often in the pub is a Dark Rum and Diet Coke.  What I&#8217;ll want to be drinking though, is my variation of the Cuba Libre &#8211; the Cuba Libre Oscuro.
<span id="more-116"></span></p>

<p>A standard Cuba Libre blends the flavours of Cuba (a white rum) and &#8220;The Free World&#8221; (Coca Cola), with a bunch of lime juice.  In contrast, and as the name would suggest, the Oscuro is a Cuba Libre made with Darker Rum.  </p>

<p>Right now I&#8217;m enjoying a golden 5 year El Dorado (a drink blended from rums with a minimum age of five years aged in oak barrels) , but I also enjoy it made with a nice shot of Captain Morgan&#8217;s.  It&#8217;s a simple flavoursome drink, and very simple to make. Om nom nom.</p>

<h2>Ingredients</h2>

<ul>
<li>Half a lime</li>
<li>Three ice cubes</li>
<li>1 shot of your favourite dark rum</li>
<li>Diet Coke</li>
</ul>

<p><img src="http://neilsnoms.com/wp-content/uploads/2010/08/IMG_9901.jpg" alt="Cuba Libre Oscura ingredients" title="Cuba Libre Oscura ingredients" width="500" height="333" class="alignnone size-full wp-image-119"/></p>

<h2>Instructions</h2>

<ol>
<li><p>Roll your lime under your hand on a board to squish its insides a bit, thus encouraging the juices to flow once you cut into it.</p></li>
<li><p>Cut the lime in half across its body, and then cut one of those halves in half again.  Squeeze the two quarters hard, and drop them into the glass.</p>

<p>If you have no fresh limes (it happens!) I&#8217;ve been pleasantly surprised by Tesco&#8217;s bottled lime juice.  Replace the half a lime with two and a half teaspoons of bottled juice.  I measure two teaspoons, not worrying about any extra that spills over.</p></li>
<li><p>Add the ice to the lime juice.</p></li>
<li><p>Pour the rum over the ice.</p></li>
<li><p>Finally, you guessed it, top up with diet coke.</p>

<p>The pouring action of each stage should mix the drink for you, leaving you with a tasty limey, rummy, cokey drink. Tasty.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Using last.fm tags to make awesome playlists in your local iTunes library</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/pm-HuIgSqg4/</link>
         <description>&lt;p&gt;As I&amp;#8217;ve mentioned previously, I have a large music collection that I manage using iTunes.  One of the problems with any large collection is the curation and management that goes with it.  I carry my iPhone around with me and I listen to music on it, but even the biggest iPhone available would hold only  fifth of my collection.  So, I need techniques for pulling interesting music from my iTunes library into my iPhone.&lt;/p&gt;

&lt;p&gt;Up until now I&amp;#8217;ve used a collection of Smart Playlists which take into account my ratings, when I last listened to songs and a whole bunch of other information.  At the last count, I had over 70 Smart Playlists feeding into each other to generate the playlists which finally get Synced over to my iPhone.&lt;/p&gt;

&lt;p&gt;But there was something missing.  Whilst I could generate playlists based on the mid-90s simplicity of the &amp;#8220;Genre&amp;#8221; tag, that tag is by design only able to identify one piece of information.  So I wouldn&amp;#8217;t be able to find, for example, all tracks in my collection that are &amp;#8220;rock&amp;#8221;, &amp;#8220;funny&amp;#8221; and performed by a &amp;#8220;female&amp;#8221;.  And even if I could, I wouldn&amp;#8217;t want to go and tag 40,000 tracks by hand. That way madness lies.&lt;/p&gt;

&lt;p&gt;It turns out there&amp;#8217;s a fairly simple solution to this &amp;#8211; last.fm allows users to tag any and all tracks it knows about, and it keeps track of how many times each track has been tagged with each tag.  So, it&amp;#8217;s entirely possible to grab the top 15 tags for each track in my collection, add that data to my tracks somehow, and then query that.&lt;/p&gt;

&lt;p&gt;The somehow turns out to be pretty simple too &amp;#8211; the ID3 &amp;#8220;comment&amp;#8221; field is there for the taking, and by design is expected to be larger than any other field.  Excellent.  So that&amp;#8217;s the &amp;#8220;where to store&amp;#8221; sorted, now how about &amp;#8220;how to store so that the data is queryable&amp;#8221;?&lt;/p&gt;

&lt;p&gt;For this I took &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.xml.com/pub/a/2007/09/04/parsing-microformats.html?page=2&quot;&gt;a trick out of Brian Suda&amp;#8217;s book&lt;/a&gt;.  A couple of years back I took a look at how he&amp;#8217;d written his microformats parser using XSLT to be able to check for classes an element may or may not have &amp;#8211; the trick being to wrap strings of classes with a space at the beginning and end so that every class &lt;em&gt;always&lt;/em&gt; had spaces surrounding it.  I used the same trick for storing my tag data, also wrapping it in a &amp;#8216;lfm&amp;#8217; square bracketed enclosure to separate it from any other data in the comment.&lt;/p&gt;

&lt;p&gt;So, the data I saved in the comment looked a little something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[lfm: tag1 tag2 tag23 tag3 ]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You&amp;#8217;re probably starting to see why wrapping in spaces is important now.  Because iTunes&amp;#8217; Smart Playlist system can only perform simple string matching (Apple doesn&amp;#8217;t seem to like regexes &amp;#8211; AppleScript can&amp;#8217;t do them natively either), you need some way of targetting the beginning and end of tags. Without those spaces, a query of &amp;#8220;&lt;code&gt;Comments contains 'tag2'&lt;/code&gt;&amp;#8221; would return you both &lt;code&gt;tag2&lt;/code&gt; and &lt;code&gt;tag23&lt;/code&gt;, which no-one wants.  By requesting &amp;#8220;&lt;code&gt;Comments contains ' tag2 '&lt;/code&gt;&amp;#8221; instead (note the extra spaces) you end up just being given &lt;code&gt;tag2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All this thinking is packaged up into a &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://github.com/NeilCrosby/itunes-helpers/commit/b94cf1f2c28bdc2b83129b458e0e6bc42573afdb&quot;&gt;couple of scripts&lt;/a&gt; (though obviously take &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://github.com/NeilCrosby/itunes-helpers/tree/master/playlist/lastfm/&quot;&gt;the latest code&lt;/a&gt; if you want to actually use it yourself) I wrote a couple of days ago that takes a given playlist from your iTunes library, asks last.fm for tags for each of the songs in that playlist, and then adds that data to the library using AppleScript.&lt;/p&gt;

&lt;h2&gt;Problems?&lt;/h2&gt;

&lt;p&gt;There are, unfortunately, a couple of issues with the script at the moment.  First off, because last.fm allows anything and everything to be given as a tag, they can contain characters that need to be normalised out.  Right now I&amp;#8217;m doing that very simply (spaces to dashes mostly), but I should revisit the code and harden that normalisation &amp;#8211; I&amp;#8217;ve seen tagging bail out a couple of times because of unexpected data.&lt;/p&gt;

&lt;p&gt;Next up, the fact that last.fm allows tags to be incredibly long coupled with the fact that under ID3 v2.x the comments field can only be 256 characters long means that it&amp;#8217;s possible to run into issues with tagsets being too long to fit into the comments field.  Add that to the fact that some songs in my collection legitimately contain comments already and that I want to add tags non-destructively, and we&amp;#8217;re ending up with not much space for tags.  So, an improvement that I&amp;#8217;m planning on making to the script is to make sure that tags try to take up no more than the space that&amp;#8217;s legitimately available to them.&lt;/p&gt;

&lt;p&gt;The final issue that I&amp;#8217;ve been having lives with last.fm&amp;#8217;s track.getTopTags API method.  Unfortunately at present the track.getTopTags API method does not perform any auto-correction of track names, which means that if you try to get the tags for something that does get auto-corrected by the system then you end up with the tags for the uncorrected track name. A subtle distinction, but it probably means that we end up with unmaintained tags that haven&amp;#8217;t been touched for the year or so since auto-correction was turned on. A possible solution here if last.fm choose not to &amp;#8220;fix&amp;#8221; this behaviour (it could be argued that this is correct behaviour) would be to make a request out to Musicbrainz to get an ID for the track and then pass that into track.getTopTags instead.  But that seems like a whole bunch of extra work for a not massive gain.&lt;/p&gt;

&lt;h2&gt;The final Smart Playlist&lt;/h2&gt;

&lt;p&gt;So, what about that Smart Playlist? After all, that&amp;#8217;s the thing that all this work was done for.&lt;/p&gt;

&lt;p&gt;In iTunes, select &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;New Smart Playlist&lt;/code&gt;, and then enter the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Match all of the following rules:
    Comments contains ' female '
    Comments contains ' rock ' ...
    any of the following rules:
        Comments contains ' comedy '
        Comments contains ' funny '
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This cunning playlist uses a Smart Playlist feature I wasn&amp;#8217;t aware of until yesterday &amp;#8211; rule groups.  Up until now, I&amp;#8217;d been pulling in other Smart Playlists as sources to perform the same job.&lt;/p&gt;

&lt;p&gt;To create a new rule group in a Smart Playlist, simply click an ellipsis button in the Smart Playlist interface, rather than clicking on the plus button.&lt;/p&gt;

&lt;p&gt;Essentially what these rule groups give you is the ability to nest rulesets, and generate very complex playlists that don&amp;#8217;t have half their rules hidden in external playlists.  In the playlist above we&amp;#8217;re simply asking for all tracks tagged with &amp;#8220;female&amp;#8221;, &amp;#8220;rock&amp;#8221; and either &amp;#8220;funny&amp;#8221; or &amp;#8220;comedy&amp;#8221;. So essentially &amp;#8220;female comedy rock&amp;#8221;.  At present this playlist returns me no items from my collection, but not everything&amp;#8217;s been tagged yet.  I&amp;#8217;m hopeful.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/08/using-last-fm-tags-to-make-awesome-playlists-in-your-local-itunes-library/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=484</guid>
         <pubDate>Wed, 18 Aug 2010 18:00:15 +0000</pubDate>
         <content:encoded><![CDATA[<p>As I&#8217;ve mentioned previously, I have a large music collection that I manage using iTunes.  One of the problems with any large collection is the curation and management that goes with it.  I carry my iPhone around with me and I listen to music on it, but even the biggest iPhone available would hold only  fifth of my collection.  So, I need techniques for pulling interesting music from my iTunes library into my iPhone.</p>

<p>Up until now I&#8217;ve used a collection of Smart Playlists which take into account my ratings, when I last listened to songs and a whole bunch of other information.  At the last count, I had over 70 Smart Playlists feeding into each other to generate the playlists which finally get Synced over to my iPhone.</p>

<p>But there was something missing.  Whilst I could generate playlists based on the mid-90s simplicity of the &#8220;Genre&#8221; tag, that tag is by design only able to identify one piece of information.  So I wouldn&#8217;t be able to find, for example, all tracks in my collection that are &#8220;rock&#8221;, &#8220;funny&#8221; and performed by a &#8220;female&#8221;.  And even if I could, I wouldn&#8217;t want to go and tag 40,000 tracks by hand. That way madness lies.</p>

<p>It turns out there&#8217;s a fairly simple solution to this &#8211; last.fm allows users to tag any and all tracks it knows about, and it keeps track of how many times each track has been tagged with each tag.  So, it&#8217;s entirely possible to grab the top 15 tags for each track in my collection, add that data to my tracks somehow, and then query that.</p>

<p>The somehow turns out to be pretty simple too &#8211; the ID3 &#8220;comment&#8221; field is there for the taking, and by design is expected to be larger than any other field.  Excellent.  So that&#8217;s the &#8220;where to store&#8221; sorted, now how about &#8220;how to store so that the data is queryable&#8221;?</p>

<p>For this I took <a rel="nofollow" target="_blank" href="http://www.xml.com/pub/a/2007/09/04/parsing-microformats.html?page=2">a trick out of Brian Suda&#8217;s book</a>.  A couple of years back I took a look at how he&#8217;d written his microformats parser using XSLT to be able to check for classes an element may or may not have &#8211; the trick being to wrap strings of classes with a space at the beginning and end so that every class <em>always</em> had spaces surrounding it.  I used the same trick for storing my tag data, also wrapping it in a &#8216;lfm&#8217; square bracketed enclosure to separate it from any other data in the comment.</p>

<p>So, the data I saved in the comment looked a little something like this:</p>

<pre><code>[lfm: tag1 tag2 tag23 tag3 ]
</code></pre>

<p>You&#8217;re probably starting to see why wrapping in spaces is important now.  Because iTunes&#8217; Smart Playlist system can only perform simple string matching (Apple doesn&#8217;t seem to like regexes &#8211; AppleScript can&#8217;t do them natively either), you need some way of targetting the beginning and end of tags. Without those spaces, a query of &#8220;<code>Comments contains 'tag2'</code>&#8221; would return you both <code>tag2</code> and <code>tag23</code>, which no-one wants.  By requesting &#8220;<code>Comments contains ' tag2 '</code>&#8221; instead (note the extra spaces) you end up just being given <code>tag2</code>.</p>

<p>All this thinking is packaged up into a <a rel="nofollow" target="_blank" href="http://github.com/NeilCrosby/itunes-helpers/commit/b94cf1f2c28bdc2b83129b458e0e6bc42573afdb">couple of scripts</a> (though obviously take <a rel="nofollow" target="_blank" href="http://github.com/NeilCrosby/itunes-helpers/tree/master/playlist/lastfm/">the latest code</a> if you want to actually use it yourself) I wrote a couple of days ago that takes a given playlist from your iTunes library, asks last.fm for tags for each of the songs in that playlist, and then adds that data to the library using AppleScript.</p>

<h2>Problems?</h2>

<p>There are, unfortunately, a couple of issues with the script at the moment.  First off, because last.fm allows anything and everything to be given as a tag, they can contain characters that need to be normalised out.  Right now I&#8217;m doing that very simply (spaces to dashes mostly), but I should revisit the code and harden that normalisation &#8211; I&#8217;ve seen tagging bail out a couple of times because of unexpected data.</p>

<p>Next up, the fact that last.fm allows tags to be incredibly long coupled with the fact that under ID3 v2.x the comments field can only be 256 characters long means that it&#8217;s possible to run into issues with tagsets being too long to fit into the comments field.  Add that to the fact that some songs in my collection legitimately contain comments already and that I want to add tags non-destructively, and we&#8217;re ending up with not much space for tags.  So, an improvement that I&#8217;m planning on making to the script is to make sure that tags try to take up no more than the space that&#8217;s legitimately available to them.</p>

<p>The final issue that I&#8217;ve been having lives with last.fm&#8217;s track.getTopTags API method.  Unfortunately at present the track.getTopTags API method does not perform any auto-correction of track names, which means that if you try to get the tags for something that does get auto-corrected by the system then you end up with the tags for the uncorrected track name. A subtle distinction, but it probably means that we end up with unmaintained tags that haven&#8217;t been touched for the year or so since auto-correction was turned on. A possible solution here if last.fm choose not to &#8220;fix&#8221; this behaviour (it could be argued that this is correct behaviour) would be to make a request out to Musicbrainz to get an ID for the track and then pass that into track.getTopTags instead.  But that seems like a whole bunch of extra work for a not massive gain.</p>

<h2>The final Smart Playlist</h2>

<p>So, what about that Smart Playlist? After all, that&#8217;s the thing that all this work was done for.</p>

<p>In iTunes, select <code>File</code>, <code>New Smart Playlist</code>, and then enter the following:</p>

<pre><code>Match all of the following rules:
    Comments contains ' female '
    Comments contains ' rock ' ...
    any of the following rules:
        Comments contains ' comedy '
        Comments contains ' funny '
</code></pre>

<p>This cunning playlist uses a Smart Playlist feature I wasn&#8217;t aware of until yesterday &#8211; rule groups.  Up until now, I&#8217;d been pulling in other Smart Playlists as sources to perform the same job.</p>

<p>To create a new rule group in a Smart Playlist, simply click an ellipsis button in the Smart Playlist interface, rather than clicking on the plus button.</p>

<p>Essentially what these rule groups give you is the ability to nest rulesets, and generate very complex playlists that don&#8217;t have half their rules hidden in external playlists.  In the playlist above we&#8217;re simply asking for all tracks tagged with &#8220;female&#8221;, &#8220;rock&#8221; and either &#8220;funny&#8221; or &#8220;comedy&#8221;. So essentially &#8220;female comedy rock&#8221;.  At present this playlist returns me no items from my collection, but not everything&#8217;s been tagged yet.  I&#8217;m hopeful.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/pm-HuIgSqg4" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Review: Cordless Dog’s “Stay”</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/TJ_vXUAuMu4/</link>
         <description>&lt;p&gt;One of the problems with being an Apple laptop user who sometimes connects to external displays is the lack of any built in management of where different applications should live on those different displays.  &lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re anything like me, as soon as you connect your laptop to an external display you&amp;#8217;ll end up moving your applications around into a better position and size so that you can work happily. Then, when you disconnect your external display to go back onto the road OSX will do its best to put them somewhere sensible on your smaller laptop screen, but fails horribly.&lt;/p&gt;

&lt;p&gt;Enter Cordless Dog&amp;#8217;s &amp;#8220;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cordlessdog.com/stay/&quot;&gt;Stay&lt;/a&gt;&amp;#8221; application.&lt;/p&gt;

&lt;p&gt;Stay is a deceptively simple (at least the way I&amp;#8217;m using it) application that lives in your Mac&amp;#8217;s taskbar.  First, set up your applications so that they&amp;#8217;re positioned as you want them, then choose &amp;#8220;Store Windows for all Applications&amp;#8221; from the app&amp;#8217;s dropdown menu. If you then want to restore applications to their stored position just pull down the menu again and choose &amp;#8220;Restore Windows&amp;#8221;.  Simple.&lt;/p&gt;

&lt;p&gt;To make things even more simple though, pop open the application preferences. There aren&amp;#8217;t many options here (and there don&amp;#8217;t need to be), but for my money it makes sense to turn on &amp;#8220;Start Stay at login&amp;#8221;, &amp;#8220;Restore Windows as displays are connected and disconnected&amp;#8221; and &amp;#8220;Restore Windows as applications are launched&amp;#8221;.  And suddenly, as if by magic, application positioning with multiple displays starts working in the way it always should have done.&lt;/p&gt;

&lt;p&gt;Cordless Dog&amp;#8217;s &amp;#8220;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cordlessdog.com/stay/&quot;&gt;Stay&lt;/a&gt;&amp;#8221; application costs a measly $15, and is worth every cent.  Good job, Cordless Dog chaps!&lt;/p&gt;

&lt;h2&gt;UPDATE&lt;/h2&gt;

&lt;p&gt;As &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;https://twitter.com/fatbusinessman/status/21316857798&quot;&gt;David Thompson pointed out&lt;/a&gt;, I should probably point out that currently Stay and Spaces don&amp;#8217;t currently live marvellously happily together. If you&amp;#8217;re a user of Spaces (I&amp;#8217;m not), you should probably wait for &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://cordlessdog.com/stay/faq/&quot;&gt;a future release of Stay&lt;/a&gt;.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/08/review-cordless-dogs-stay/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=475</guid>
         <pubDate>Mon, 16 Aug 2010 08:39:43 +0000</pubDate>
         <content:encoded><![CDATA[<p>One of the problems with being an Apple laptop user who sometimes connects to external displays is the lack of any built in management of where different applications should live on those different displays.  </p>

<p>If you&#8217;re anything like me, as soon as you connect your laptop to an external display you&#8217;ll end up moving your applications around into a better position and size so that you can work happily. Then, when you disconnect your external display to go back onto the road OSX will do its best to put them somewhere sensible on your smaller laptop screen, but fails horribly.</p>

<p>Enter Cordless Dog&#8217;s &#8220;<a rel="nofollow" target="_blank" href="http://cordlessdog.com/stay/">Stay</a>&#8221; application.</p>

<p>Stay is a deceptively simple (at least the way I&#8217;m using it) application that lives in your Mac&#8217;s taskbar.  First, set up your applications so that they&#8217;re positioned as you want them, then choose &#8220;Store Windows for all Applications&#8221; from the app&#8217;s dropdown menu. If you then want to restore applications to their stored position just pull down the menu again and choose &#8220;Restore Windows&#8221;.  Simple.</p>

<p>To make things even more simple though, pop open the application preferences. There aren&#8217;t many options here (and there don&#8217;t need to be), but for my money it makes sense to turn on &#8220;Start Stay at login&#8221;, &#8220;Restore Windows as displays are connected and disconnected&#8221; and &#8220;Restore Windows as applications are launched&#8221;.  And suddenly, as if by magic, application positioning with multiple displays starts working in the way it always should have done.</p>

<p>Cordless Dog&#8217;s &#8220;<a rel="nofollow" target="_blank" href="http://cordlessdog.com/stay/">Stay</a>&#8221; application costs a measly $15, and is worth every cent.  Good job, Cordless Dog chaps!</p>

<h2>UPDATE</h2>

<p>As <a rel="nofollow" target="_blank" href="https://twitter.com/fatbusinessman/status/21316857798">David Thompson pointed out</a>, I should probably point out that currently Stay and Spaces don&#8217;t currently live marvellously happily together. If you&#8217;re a user of Spaces (I&#8217;m not), you should probably wait for <a rel="nofollow" target="_blank" href="http://cordlessdog.com/stay/faq/">a future release of Stay</a>.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/TJ_vXUAuMu4" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>The Oatmeal and Raisin Cookies</title>
         <link>http://neilsnoms.com/the-oatmeal-and-raisin-cookies/</link>
         <description>Cookies are awesome. They&amp;#8217;re simple to make, tasty, you can freeze the dough and you can eat it raw if you want to. I love them all. If I had to choose to only make one type of cookie for the rest of my life though, I would choose these. But why? Well, I&amp;#8217;ve got [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=9</guid>
         <pubDate>Wed, 21 Jul 2010 20:00:23 +0000</pubDate>
         <content:encoded><![CDATA[<p><img src="http://farm5.static.flickr.com/4075/4796694738_2befe44c52.jpg" width="500" height="333" alt="The Oatmeal and Raisin Cookies"/></p>

<p>Cookies are awesome.  They&#8217;re simple to make, tasty, you can freeze the dough and you can eat it raw if you want to.  I love them all.  If I had to choose to only make one type of cookie for the rest of my life though, I would choose these.</p>

<p>But why?<span id="more-9"></span></p>

<p>Well, I&#8217;ve got to admit that the main reason isn&#8217;t even in their name &#8211; it&#8217;s the cinnamon in them that I would gladly give up the chance to eat any other type of cookie for.  It might not be the first flavour you&#8217;ll taste in them, but it&#8217;s there, and it gives the cookies a wonderful warmth that just wouldn&#8217;t find otherwise.</p>

<p>Don&#8217;t get me wrong, the oatmeal gives the cookies a wonderful chewy texture, and the raisins give a brilliant juiciness, but it&#8217;s the cinnamon that does the job for me every time.</p>

<p>So, chances are, if I say I&#8217;m going to be making you some cookies I&#8217;ll probably be making you The Oatmeal and Raisin cookies.  Om nom nom.</p>

<p><img src="http://farm3.static.flickr.com/2463/3600417842_338c508c04.jpg" width="500" height="333" alt="Guarding the Oatmeal and Raisin Cookies"/></p>

<p>Makes 25 small cookies, and takes about 20 minutes all told.</p>

<h2>Ingredients</h2>

<ul>
<li>150g butter</li>
<li>85g soft brown sugar</li>
<li>50 granulated sugar</li>
<li>1 small egg</li>
<li>1/2 tsp vanilla extract</li>
<li>100g plain flour</li>
<li>1/2 tsp baking powder</li>
<li>1/4 tsp salt</li>
<li>1 tsp cinnamon</li>
<li>125g porridge oats</li>
<li>100g raisins</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Preheat your oven to 180ºc</p></li>
<li><p>Cream the butter and sugars together.</p></li>
<li><p>In a separate bowl, combine the egg and vanilla extract, before adding these to the creamed ingredients and mixing lightly.</p></li>
<li><p>In yet another bowl  combine the flour, baking powder, salt and cinnamon.  Then, you guessed it &#8211; mix this slowly into the creamy eggy mixture.</p>

<p>I tend to do this a third at a time to make sure everything combines together.</p></li>
<li><p>Finally, mix your oatmeal and raisins and add them to the mix.</p></li>
<li><p>Make sure everything comes together, cover and place in the fridge.</p>

<p>Ideally, leave your mixture in the fridge overnight, but if you can&#8217;t wait then make sure you leave it in there for at least half an hour.  The reason we do this is to let everything firm up again, which in turn means that the cookies won&#8217;t spread to cover your entire baking tray when you cook them.</p></li>
<li><p>Once your cookie dough is fully chilled, use a tablespoon to remove small chunks, which you should form into balls.  Place them on a baking tray &#8211; I tend to fit nine cookies on a tray.</p>

<p>Try to handle your balls as little as possible &#8211; you want them chilled, remember?</p></li>
<li><p>Bake for 11 minutes. Allow to cool sightly before removing from baking tray and then leave to cool on a cooling rack.</p>

<p>Alternatively, put a couple of cookies in a shallow bowl with some good quality vanilla ice-cream and nom.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>True Blood Raspberry Mojito</title>
         <link>http://neilsnoms.com/true-blood-raspberry-mojito/</link>
         <description>It&amp;#8217;s been quite warm here recently. Warm enough that I&amp;#8217;ve not been sleeping too well, even with the bedroom windows wide open, and a fan on full blast all through the night. There&amp;#8217;s no air conditioning here. What I&amp;#8217;ve had to keep my going though is the humble mojito. I love my mojitos. I&amp;#8217;d love [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=105</guid>
         <pubDate>Tue, 29 Jun 2010 18:46:17 +0000</pubDate>
         <content:encoded><![CDATA[<p><img src="http://farm5.static.flickr.com/4080/4739063390_7bb7ecc487.jpg" width="500" height="333" alt="True Blood Raspberry Mojito"></p>

<p>It&#8217;s been quite warm here recently.  Warm enough that I&#8217;ve not been sleeping too well, even with the bedroom windows wide open, and a fan on full blast all through the night.  There&#8217;s no air conditioning here.</p>

<p>What I&#8217;ve had to keep my going though is the humble mojito.  I love my mojitos.  I&#8217;d love to blame Bruce Campbell in Burn Notice, but I&#8217;ve been enjoying them long before I started watching that show.  There&#8217;s something about that combination of lime, mint and ice that makes a summer day wonderful.<span id="more-105"></span></p>

<p>But today I&#8217;m not making my normal <a rel="nofollow" target="_blank" href="http://neilsnoms.com/strained-mojito/">strained mojito</a>.  Since True Blood is returning to our screens, I&#8217;ve been thinking about blood related drinks (you know, like you do).  I&#8217;ve been making raspberry based mojitos for a while now, but I&#8217;ve only just realised what a gorgeous deep blood red you can get out of them.  So, I decided to tweak my recipe a little bit and make something that really looked like blood.</p>

<p>The secret to this is in the double straining.  Normally when I strain a mojito I&#8217;m left with bits of mint and lime flowing through the drink, contributing to the lovely green colour that I adore.  For a drink that you&#8217;re wanting to look bloody though, this doesn&#8217;t quite work.</p>

<p>So, I double strain.  As with most things I do, this is really easy.  Instead of simply straining the drink, I hold a tea strainer between the cocktail shaker and the glass as I&#8217;m pouring.  This has a finer mesh than the normal cocktail strainer, and so stops any bits of mint and any raspberry seeds entering the drink.  What you&#8217;re left with is a very smooth, red drink.</p>

<p>Try it; I&#8217;m sure you&#8217;ll love it.</p>

<h2>Ingredients</h2>

<ul>
<li>Juice of half a lime</li>
<li>1 tablespoon of granulated sugar</li>
<li>12 mint leaves</li>
<li>15 raspberries</li>
<li>2 shots of light rum</li>
<li>A load of ice</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>First, squeeze the juice of half a lime into your cocktail shaker.</p>

<p>Before cutting the lime, I will roll it hard against a table, pushing down on it as I go.  This will smush the inside of the lime a bit, allowing the squeezing process to be a bit easier than otherwise.</p></li>
<li><p>Once you&#8217;ve squeezed the lime, cut the peel up and stick that in the shaker as well, along with the sugar, mint leaves and raspberries (in that order).</p></li>
<li><p>Using a muddler (or the end of a rolling pin), squish and rotate to puree the raspberries, rip the mint and combine everything together.</p>

<p>You can use frozen raspberries if you like.  In fact, I keep a stock of frozen blueberries and raspberries in my freezer all the year around for alcohol related emergencies.  You never know when you might want a nice cocktail.</p></li>
<li><p>Add two shots of rum and a couple of icecubes.  Shake vigorously.</p>

<p>I find that singing a song at this point helps the process.</p></li>
<li><p>To a separate glass, add enough crushed ice to fill.</p></li>
<li><p>Now for the straining.  Double strain the contents of your cocktail shaker into your glass of ice.</p>

<p>So, why am I double straining here? Basically, your shaken mixture will contain lots of raspberry seeds and some shredded mint.  Now, whilst the mint would look gorgeous in a normal mojito it doesn&#8217;t work too well for the True Blood variety.  You want to get rid of all those bits and leave a nice smooth colourful drink.</p>

<p>What I mean by double straining is strain normally using your built-in or hawthorn strainer and then immediately through a standard tea strainer.  Your normal strainer will stop the lumps of ice and lime from entering your drink, and the tea strainer will keep hold of your raspberry pips and mint.</p></li>
<li><p>Finally, garnish with a few raspberries and a sprig of mint.  Add a straw, and enjoy.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Butternut Squash and Chorizo Salad</title>
         <link>http://neilsnoms.com/butternut-squash-and-chorizo-salad/</link>
         <description>I love my Mexican food. Recently, I bought Thomasina Miers&amp;#8217; &amp;#8220;Mexican Food Made Simple&amp;#8220;, which turns out to be a fantastic collection of Mexican recipes from the former winner of Masterchef and founder of Wahaca. Over the last few weeks I&amp;#8217;ve been trying out a fair few of the recipes form the book, and making [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=95</guid>
         <pubDate>Sat, 26 Jun 2010 21:14:06 +0000</pubDate>
         <content:encoded><![CDATA[<p><img src="http://farm2.static.flickr.com/1256/4721584439_a8a673c79a.jpg" width="500" height="333" alt="Butternut Squash and Chorizo Salad"/></p>

<p>I love my Mexican food. Recently, I bought Thomasina Miers&#8217; &#8220;<a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0340994975?ie=UTF8&amp;tag=workingwmeuk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=19450&amp;creativeASIN=0340994975">Mexican Food Made Simple</a>&#8220;, which turns out to be a fantastic collection of Mexican recipes from the former winner of Masterchef and founder of Wahaca.</p>

<p>Over the last few weeks I&#8217;ve been trying out a fair few of the recipes form the book, and making my own adjustments for taste and availability of ingredients.  This Butternut Squash and Chorizo Salad has turned out to be a firm favourite, and not something I would have tried had it not been for this book. <span id="more-95"></span></p>

<p>Here&#8217;s my take on Thomasina&#8217;s recipe to serve two. Takes approximately 40 minutes.</p>

<h2>Ingredients</h2>

<ul>
<li>One small butternut squash (or half a medium one &#8211; even the smallest butternut squash can be too much for two).</li>
<li>One finely chopped red chilli.</li>
<li>Half a teaspoon of cumin seed &#8211; crushed.</li>
<li>Half a teaspoon dried oregano.</li>
<li>Olive oil.</li>
<li>Half a red onion, roughly sliced. </li>
<li>A punnet of baby tomatoes. I like a mix of red and yellow pomodorinos.</li>
<li>A handful of fresh coriander leaves, chopped.</li>
<li>Chorizo.</li>
<li>A small bag of baby spinach.</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Preheat your oven to 190ºC.</p></li>
<li><p>Cut your butternut squash into 5cm or so pieces, making sure you remove the skin and seed.</p>

<p>I hate this job.  I&#8217;m not a fan of how butternut squash smells when raw, but I love the taste after it&#8217;s been roasted, so I put up with it. If I&#8217;m feeling incredibly lazy I&#8217;ll buy pre-cut stuff from the supermarket.  This does not make me a bad person.</p></li>
<li><p>Put your butternut squash, chilli, cumin and oregano into a roasting tin, add enough olive oil to coat lightly and mix.</p></li>
<li><p>Cook for 15 minutes.</p></li>
<li><p>Add the onion to the tin, mix, and cook for a further 10 minutes.</p></li>
<li><p>Add the tomatoes, and cook for a final 10 minutes.</p></li>
<li><p>Whilst the tomatoes are roasting, grind the coriander leaves into a paste in a pestle along with the salt and pepper.  Add a tablespoon or so of olive oil, and mix.  This will be your salad dressing.</p></li>
<li><p>Slice your chorizo and sear it on a griddle.  Once seared, place the slices on some kitchen towel to drain.</p></li>
<li><p>Now that your vegetables have cooked, remove them from the oven and place in a large bowl.  Add the coriander oil and gently mix.</p></li>
<li><p>Finally, line a shallow bowl with spinach leaves, pile on your vegetables and top with chorizo.  Tasty, and the chilli gives it a lovely kick.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Packratius, and the inevitable overwhelming of del.icio.us</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/RT_0H1oZ1j8/</link>
         <description>&lt;p&gt;I&amp;#8217;ve been using &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://delicious.com&quot;&gt;del.icio.us&lt;/a&gt; for years. I started using it well before it was bought up by Yahoo!, and for a long time my primary use for it was to store my bookmarks in an always available location &amp;#8211; I used many computers, and not having my bookmarks tied to a single machine always seemed like a good idea.&lt;/p&gt;

&lt;p&gt;As time went on, I started paying attention to the &amp;#8220;Most Popular&amp;#8221; feeds on the homepage, and even managed to get on there myself a few times.  It was a good way to find interesting techy links.  Then, when the friends network facility was introduced I started following the links that my friends were saving as well.  All was well.&lt;/p&gt;

&lt;p&gt;However, I never really saved as many of the links that I found interesting as I could have done.  There were plenty of occasions when I remembered telling people about particular pages because they were useful, but not being able to find them again myself.  Oh, how I wished I&amp;#8217;d added them to del.icio.us.&lt;/p&gt;

&lt;p&gt;The problem is that I&amp;#8217;m lazy.  So, I was really happy when &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://packrati.us&quot;&gt;Packratius&lt;/a&gt; peeked its nose up to the cage bars.  The idea behind Packratius is that it&amp;#8217;ll keep an eye on your twitter activity and automagically add any links you tweet to del.icio.us (by default with a &lt;code&gt;via:packrati.us&lt;/code&gt; tag).  It&amp;#8217;s deceptively simple, and something that deeply interested me &amp;#8211; I immediately signed up.&lt;/p&gt;

&lt;h2&gt;A good idea gone overwhelming&lt;/h2&gt;

&lt;p&gt;As it turns out, so did quite a few of my friends.  Overnight, my del.icio.us network feed went from being a carefully curated list of links to a mishmash of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.bbc.co.uk/food/recipes/carrotsglazedwithcum_80467&quot;&gt;Carrots Glazed with Cum&lt;/a&gt;, gowalla updates and twitpics.&lt;/p&gt;

&lt;p&gt;Now, to its credit, Packratius has &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://packrati.us/preferences&quot;&gt;options&lt;/a&gt; to allow you to not auto-delish links tweeted by any twitter clients that you define.  This allows you to not auto tweet twitpics and the like.  Of course, telling it to stop tweeting those things from your own twitter account is great, but it doesn&amp;#8217;t stop you from seeing those updates from other people (/me looks pointedly at &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://simonjobling.com&quot;&gt;Simon Jobling&lt;/a&gt;).  So, I needed to find a way to split these auto-delished URLs off from the main list.&lt;/p&gt;

&lt;p&gt;As it turns out, whilst del.icio.us&amp;#8217; searching abilities are pretty powerful, you can&amp;#8217;t do a simply negative search.  So whilst you could say &amp;#8220;Show me everything in my network feed tagged with &amp;#8216;kittens&amp;#8217; but not &amp;#8216;via:packrati.us&amp;#8217;&amp;#8221; you can&amp;#8217;t say &amp;#8220;Show me everything in my network feed not tagged with &amp;#8216;via:packrati.us&amp;#8217;&amp;#8221;.  Thankfully I came up with a solution to this &amp;#8211; I created a Yahoo! Pipe called &amp;#8220;&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101&quot;&gt;del.icio.us network feed minus packratius&lt;/a&gt;&amp;#8220;. (Catchy, huh?)&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a fairly simple pipe, with the following aims:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide a feed of your del.icio.us network with items tagged with &lt;code&gt;via:packrati.us&lt;/code&gt; removed.&lt;/li&gt;
&lt;li&gt;Easily customisable to show different peoples&amp;#8217; network feeds.  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you&amp;#8217;ve been having similar problems with Packratius overwhelming your del.icio.us network feed, then give it a go.  I know &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://kulor.com/&quot;&gt;James Broad&lt;/a&gt; has been finding Packratius overwhelming &amp;#8211; it was his &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://twitter.com/kulor/status/15596311122&quot;&gt;tweet&lt;/a&gt; that inspired me to finally write this post up, in the hope of benefitting a few more people.&lt;/p&gt;

&lt;h2&gt;How does the pipe work?&lt;/h2&gt;

&lt;p&gt;Like I said, the pipe&amp;#8217;s fairly simple &amp;#8211; most of the complexity comes from generating the URL to load a given user&amp;#8217;s del.icio.us network feed.&lt;/p&gt;

&lt;p&gt;Once we&amp;#8217;ve obtained the network feed, the only thing we need to do is discard all the feed items that contain &lt;code&gt;via:packrati.us&lt;/code&gt; as a tag.  Handily, del.icio.us provides us this information in its feeds:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;item&amp;gt;
  …
  &amp;lt;link&amp;gt;

http://wwp.greenwichmeantime.com/time-zone/africa/south-africa/

  &amp;lt;/link&amp;gt;
  &amp;lt;description&amp;gt;
    South Africa is in Southern Africa, 
    at the southern tip of the continent of Africa.
    http:// bit.ly/am78yK
    #statingthebleedingobvious
  &amp;lt;/description&amp;gt;
  &amp;lt;category domain=&quot;http://delicious.com/simey_j/&quot;&amp;gt;
    statingthebleedingobvious
  &amp;lt;/category&amp;gt;
  &amp;lt;category domain=&quot;http://delicious.com/simey_j/&quot;&amp;gt;
    via:packrati.us
  &amp;lt;/category&amp;gt;
&amp;lt;/item&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the feed item above (cut down for space), we can see that as well as &lt;code&gt;via:packrati.us&lt;/code&gt;, a &lt;code&gt;statingthebleedingobvious&lt;/code&gt; tag has been automatically generated from the hashtag in the original tweet.  This is a great feature of Packratius, but it did mean that I ended up having to do more than a very simple filter to filter out the &lt;code&gt;via:packrati.us&lt;/code&gt; tagged feed items.&lt;/p&gt;

&lt;p&gt;Instead what I did was create a &lt;code&gt;Filter&lt;/code&gt; block in pipes with rules that looked at the first 6 tags on each feed item (the idea being that there isn&amp;#8217;t enough space in a tweet for more than 6 or so tags). If any of them matched &lt;code&gt;via:packrati.us&lt;/code&gt; then they&amp;#8217;re discarded from the feed.&lt;/p&gt;

&lt;p&gt;The filter I created looked something a little like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Filter&lt;/p&gt;
  
  &lt;p&gt;Block items that match any of the following:&lt;/p&gt;
  
  &lt;ul&gt;
  &lt;li&gt;item.category.0.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.1.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.2.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.3.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.4.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.5.content is via:packrati.us&lt;/li&gt;
  &lt;li&gt;item.category.content is via:packrati.us&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those first six filter rules cover the instance of more than one tag being applied to the item, and the final filter covers the intances where only a single tag exists.  Simple.&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s all there is to it.  Of course, writing this Pipe wouldn&amp;#8217;t be necessary if del.icio.us allowed us to do a simple negative search. Still, it&amp;#8217;s good that it&amp;#8217;s nice and easy to generate &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101&quot;&gt;this new feed&lt;/a&gt; using Pipes.&lt;/p&gt;

&lt;p&gt;Hopefully it&amp;#8217;ll be useful to a couple of you.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/06/packratius-and-the-inevitable-overwhelming-of-del-icio-us/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=455</guid>
         <pubDate>Tue, 08 Jun 2010 20:22:32 +0000</pubDate>
         <content:encoded><![CDATA[<p>I&#8217;ve been using <a rel="nofollow" target="_blank" href="http://delicious.com">del.icio.us</a> for years. I started using it well before it was bought up by Yahoo!, and for a long time my primary use for it was to store my bookmarks in an always available location &#8211; I used many computers, and not having my bookmarks tied to a single machine always seemed like a good idea.</p>

<p>As time went on, I started paying attention to the &#8220;Most Popular&#8221; feeds on the homepage, and even managed to get on there myself a few times.  It was a good way to find interesting techy links.  Then, when the friends network facility was introduced I started following the links that my friends were saving as well.  All was well.</p>

<p>However, I never really saved as many of the links that I found interesting as I could have done.  There were plenty of occasions when I remembered telling people about particular pages because they were useful, but not being able to find them again myself.  Oh, how I wished I&#8217;d added them to del.icio.us.</p>

<p>The problem is that I&#8217;m lazy.  So, I was really happy when <a rel="nofollow" target="_blank" href="http://packrati.us">Packratius</a> peeked its nose up to the cage bars.  The idea behind Packratius is that it&#8217;ll keep an eye on your twitter activity and automagically add any links you tweet to del.icio.us (by default with a <code>via:packrati.us</code> tag).  It&#8217;s deceptively simple, and something that deeply interested me &#8211; I immediately signed up.</p>

<h2>A good idea gone overwhelming</h2>

<p>As it turns out, so did quite a few of my friends.  Overnight, my del.icio.us network feed went from being a carefully curated list of links to a mishmash of <a rel="nofollow" target="_blank" href="http://www.bbc.co.uk/food/recipes/carrotsglazedwithcum_80467">Carrots Glazed with Cum</a>, gowalla updates and twitpics.</p>

<p>Now, to its credit, Packratius has <a rel="nofollow" target="_blank" href="http://packrati.us/preferences">options</a> to allow you to not auto-delish links tweeted by any twitter clients that you define.  This allows you to not auto tweet twitpics and the like.  Of course, telling it to stop tweeting those things from your own twitter account is great, but it doesn&#8217;t stop you from seeing those updates from other people (/me looks pointedly at <a rel="nofollow" target="_blank" href="http://simonjobling.com">Simon Jobling</a>).  So, I needed to find a way to split these auto-delished URLs off from the main list.</p>

<p>As it turns out, whilst del.icio.us&#8217; searching abilities are pretty powerful, you can&#8217;t do a simply negative search.  So whilst you could say &#8220;Show me everything in my network feed tagged with &#8216;kittens&#8217; but not &#8216;via:packrati.us&#8217;&#8221; you can&#8217;t say &#8220;Show me everything in my network feed not tagged with &#8216;via:packrati.us&#8217;&#8221;.  Thankfully I came up with a solution to this &#8211; I created a Yahoo! Pipe called &#8220;<a rel="nofollow" target="_blank" href="http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101">del.icio.us network feed minus packratius</a>&#8220;. (Catchy, huh?)</p>

<p>It&#8217;s a fairly simple pipe, with the following aims:</p>

<ul>
<li>Provide a feed of your del.icio.us network with items tagged with <code>via:packrati.us</code> removed.</li>
<li>Easily customisable to show different peoples&#8217; network feeds.  </li>
</ul>

<p>If you&#8217;ve been having similar problems with Packratius overwhelming your del.icio.us network feed, then give it a go.  I know <a rel="nofollow" target="_blank" href="http://kulor.com/">James Broad</a> has been finding Packratius overwhelming &#8211; it was his <a rel="nofollow" target="_blank" href="http://twitter.com/kulor/status/15596311122">tweet</a> that inspired me to finally write this post up, in the hope of benefitting a few more people.</p>

<h2>How does the pipe work?</h2>

<p>Like I said, the pipe&#8217;s fairly simple &#8211; most of the complexity comes from generating the URL to load a given user&#8217;s del.icio.us network feed.</p>

<p>Once we&#8217;ve obtained the network feed, the only thing we need to do is discard all the feed items that contain <code>via:packrati.us</code> as a tag.  Handily, del.icio.us provides us this information in its feeds:</p>

<pre><code>&lt;item&gt;
  …
  &lt;link&gt;

http://wwp.greenwichmeantime.com/time-zone/africa/south-africa/

  &lt;/link&gt;
  &lt;description&gt;
    South Africa is in Southern Africa, 
    at the southern tip of the continent of Africa.
    http:// bit.ly/am78yK
    #statingthebleedingobvious
  &lt;/description&gt;
  &lt;category domain="http://delicious.com/simey_j/"&gt;
    statingthebleedingobvious
  &lt;/category&gt;
  &lt;category domain="http://delicious.com/simey_j/"&gt;
    via:packrati.us
  &lt;/category&gt;
&lt;/item&gt;
</code></pre>

<p>In the feed item above (cut down for space), we can see that as well as <code>via:packrati.us</code>, a <code>statingthebleedingobvious</code> tag has been automatically generated from the hashtag in the original tweet.  This is a great feature of Packratius, but it did mean that I ended up having to do more than a very simple filter to filter out the <code>via:packrati.us</code> tagged feed items.</p>

<p>Instead what I did was create a <code>Filter</code> block in pipes with rules that looked at the first 6 tags on each feed item (the idea being that there isn&#8217;t enough space in a tweet for more than 6 or so tags). If any of them matched <code>via:packrati.us</code> then they&#8217;re discarded from the feed.</p>

<p>The filter I created looked something a little like this:</p>

<blockquote>
  <p>Filter</p>
  
  <p>Block items that match any of the following:</p>
  
  <ul>
  <li>item.category.0.content is via:packrati.us</li>
  <li>item.category.1.content is via:packrati.us</li>
  <li>item.category.2.content is via:packrati.us</li>
  <li>item.category.3.content is via:packrati.us</li>
  <li>item.category.4.content is via:packrati.us</li>
  <li>item.category.5.content is via:packrati.us</li>
  <li>item.category.content is via:packrati.us</li>
  </ul>
</blockquote>

<p>Those first six filter rules cover the instance of more than one tag being applied to the item, and the final filter covers the intances where only a single tag exists.  Simple.</p>

<p>And that&#8217;s all there is to it.  Of course, writing this Pipe wouldn&#8217;t be necessary if del.icio.us allowed us to do a simple negative search. Still, it&#8217;s good that it&#8217;s nice and easy to generate <a rel="nofollow" target="_blank" href="http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101">this new feed</a> using Pipes.</p>

<p>Hopefully it&#8217;ll be useful to a couple of you.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/RT_0H1oZ1j8" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Geolocation &amp; Beer: Part 4 – Finding the Beer</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/LZDu1ldw8JY/</link>
         <description>&lt;p&gt;Now, I know I said there were only going to be three parts to this series, but I&amp;#8217;ve just realised that I missed out a quite important part of how I built &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me&quot;&gt;Beer Near Me&lt;/a&gt; &amp;#8211; how I found the beer!&lt;/p&gt;

&lt;p&gt;Even though Beer Near Me was only ever really built as a weekend project intended to help me learn about using the &lt;code&gt;navigator.geolocation&lt;/code&gt; API, it was still pretty important to get some data to display on a map showing where the local beer was. After all, without that what would the point be?&lt;/p&gt;

&lt;h2&gt;Gathering the Data&lt;/h2&gt;

&lt;p&gt;To gather the local beer data I make several searches using the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://code.google.com/apis/ajaxsearch/documentation/reference.html#_fonje_local&quot;&gt;Google Local Search API&lt;/a&gt; &amp;#8211; one that covers pubs, one for cocktail bars, one for off-licences, and so on.  The searches I make to Google&amp;#8217;s local search look something a little like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://ajax.googleapis.com/ajax/services/search/local
    ?v=1.0
    sll={$sll}
    radius=1
    q={$thing}%20loc:{$sll}
    key={$apiKey}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lets walk through those query string parameters…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;sll&lt;/code&gt; doesn&amp;#8217;t actually stand for anything according to the docs, but denotes the centre point of of the search you&amp;#8217;d like to perform.  It&amp;#8217;s a comma separated latitude/longitude value, so you&amp;#8217;d use something like &lt;code&gt;52.2282962,0.1537945&lt;/code&gt; for this parameter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;radius&lt;/code&gt; is the radius around the centre point that you&amp;#8217;d like to search within, in miles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;q&lt;/code&gt; is the most important parameter by far though; being the query term for the thing you&amp;#8217;re wanting to search for.  &lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll notice that I&amp;#8217;ve added a &lt;code&gt;loc:&lt;/code&gt; onto the query.  It turns out that without this undocumented extra bit of data, Google really doesn&amp;#8217;t return much from its local searches.  Before &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/&quot;&gt;last week&amp;#8217;s post&lt;/a&gt; I wasn&amp;#8217;t using this extra qualifier, and whilst my searches were being centered around the expected point they weren&amp;#8217;t returning much data. &lt;/p&gt;

&lt;p&gt;A case in point was around The Bricklayers Arms. Without the &lt;code&gt;loc:&lt;/code&gt; qualifier The Bricklayers Arms was nowhere to be found.  With the qualifier it suddenly started being returned by the searches to Google, along with a whole bunch of other local pubs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Interpreting the Data&lt;/h2&gt;

&lt;p&gt;So, if that&amp;#8217;s the search we make, what does the data we get back look like?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    &quot;responseData&quot;: {
        &quot;results&quot;: [
            {
                &quot;GsearchResultClass&quot;:&quot;GlocalSearch&quot;,
                &quot;lat&quot;:&quot;59.334743&quot;,
                &quot;lng&quot;:&quot;18.063034&quot;,
                &quot;accuracy&quot;:&quot;8&quot;,
                &quot;title&quot;:&quot;&amp;#92;u003cb&amp;#92;u003ePub&amp;#92;u003c/b&amp;#92;u003e&quot;,
                &quot;titleNoFormatting&quot;:&quot;Pub&quot;,
                &quot;streetAddress&quot;:&quot;Hötorget 13&quot;,
                &quot;city&quot;:&quot;Stockholm&quot;,
                &quot;country&quot;:&quot;Sweden&quot;,
                …
                &quot;phoneNumbers&quot;:[
                    {&quot;type&quot;:&quot;&quot;,&quot;number&quot;:&quot;08-782 19 30&quot;},
                    {&quot;type&quot;:&quot;&quot;,&quot;number&quot;:&quot;08-789 19 30&quot;}
                ],
                &quot;addressLines&quot;:[
                    &quot;Hötorget 13&quot;,
                    &quot;111 57 Stockholm, Sweden&quot;
                ]
            },
            {
                // another result
            }
        ]
    }, 
    &quot;responseDetails&quot;: null, 
    &quot;responseStatus&quot;: 200
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(The data above is, by necessity, just a snippet of what&amp;#8217;s actually returned.)&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll notice first of all that each result we get has a &lt;code&gt;GsearchResultClass&lt;/code&gt; of &lt;code&gt;GlocalSearch&lt;/code&gt; set.  This allows easy checking of the data type returned.  For our searches, the result class will always be &lt;code&gt;GlocalSearch&lt;/code&gt;, but other searches would return values for web searches, images searches and more.&lt;/p&gt;

&lt;p&gt;Moving on to the data that actually interests us, each item has the expected &lt;code&gt;lat&lt;/code&gt; and &lt;code&gt;lng&lt;/code&gt; attributes, along with other useful smidgens of data such as &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;streetAddress&lt;/code&gt; etc.  &lt;/p&gt;

&lt;p&gt;Of particular note are the &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;titleNoFormatting&lt;/code&gt; attributes.  You&amp;#8217;ll notice that within the &lt;code&gt;title&lt;/code&gt; field the word &amp;#8220;pub&amp;#8221; is encapsulated in encoded bold tags.  Two things to note here;  first, &amp;#8220;pub&amp;#8221; was the thing we searched for, so this gets emboldened in the standard display that Google would like to use for results (but we&amp;#8217;re still provided &lt;code&gt;titleNoFormatting&lt;/code&gt; if we&amp;#8217;d like to have access to an unformatted string). Second, any formatting applied by google in its API results will be encoded in this way.  In Beer Near Me, I take the easy way out for the data I&amp;#8217;m needing, and use &lt;code&gt;titleNoFormatting&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Moving away from the data that comes from a single API request, lets take a quick look at what happens once we move into the world of performing lots of searches at once.  Since with Beer Near Me I&amp;#8217;m making multiple calls to Google to gather beer related locations, there&amp;#8217;s the pretty large possibility that more than one of the searches will return the same place within its results.  The deduping I do on Beer Near Me is very simple in this case &amp;#8211; I simply keep track of the latitudes and longitudes of all the places that have been returned.  That way if any locations turn up in a position that&amp;#8217;s already had data assigned it it I can ignore it.  It&amp;#8217;s not perfect, but it does the job well enough.&lt;/p&gt;

&lt;h2&gt;Caching the Data&lt;/h2&gt;

&lt;p&gt;The last thing I want to briefly mention that I&amp;#8217;m doing with the data is caching it using PHP&amp;#8217;s &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://php.net/apc&quot;&gt;APC&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This was the first time I&amp;#8217;d attempted using APC on one of my own projects, so I had to install it on my Ubuntu based dev box.  I did that following &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.debian-administration.org/articles/574&quot;&gt;these instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reason for using APC to cache the calls to Google&amp;#8217;s Local Search is simple &amp;#8211; network calls are expensive and slow.  With on average five calls to Local Search occurring on each page load on Beer Near Me you&amp;#8217;d hope that they wouldn&amp;#8217;t be having to go across network every single time.   So, I implemented a very simple cache check:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$url = &quot;http://ajax.google…q=somesearch&quot;
$urlHash = md5($url);

// Try and pull the data from cache
$results = apc_fetch($urlHash);

// If we don't find the data in cache we'll have to make
// an expensive call across the network.
if (!$results) {
    // Get the data however you'd normally get it
    …
    $results = curl_exec($ch);

    // now store the data in APC
    apc_store(
        $urlHash, // Key to identify the cache by
        $results, // Data from our curl call to store 
        $ttl      // Seconds - how long we'll cache for
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see above, I&amp;#8217;m only using two APC methods &amp;#8211; &lt;code&gt;apc_fetch&lt;/code&gt; and &lt;code&gt;apc_store&lt;/code&gt;.  Really, this is all you generally need for simple caching; one method for getting the data if it already exists, and one for storing it in the cache if you had to get the data from elsewhere.&lt;/p&gt;

&lt;p&gt;With that in place, any further requests to that same location will be a lot faster, since we&amp;#8217;ll have stored the results locally.  Result.  For Beer Near Me I can afford to be fairly aggressive with our caching, since for the most parts new pubs and cocktail bars won&amp;#8217;t spring up over the course of a few minutes and become immediately available in Google&amp;#8217;s search results.&lt;/p&gt;

&lt;h2&gt;No more locations&lt;/h2&gt;

&lt;p&gt;And that&amp;#8217;s it.  As far as I&amp;#8217;m concerned, that&amp;#8217;s everything I&amp;#8217;ve done so far on Beer Near Me.  It&amp;#8217;s been a fun little weekend project, and whilst there&amp;#8217;s more I&amp;#8217;d like to do with it at some point, I think I&amp;#8217;m going to leave it alone for a few weeks now.  After all, &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://sciencehackday.com&quot;&gt;Science HackDay&lt;/a&gt; is in just over two weeks time, and no doubt I&amp;#8217;ll get wonderfully caught up in something new for that.  Hopefully whatever I hack on will even be useful.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/06/geolocation-and-beer-part-4-finding-the-beer/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=449</guid>
         <pubDate>Wed, 02 Jun 2010 20:24:18 +0000</pubDate>
         <content:encoded><![CDATA[<p>Now, I know I said there were only going to be three parts to this series, but I&#8217;ve just realised that I missed out a quite important part of how I built <a rel="nofollow" target="_blank" href="http://beernear.me">Beer Near Me</a> &#8211; how I found the beer!</p>

<p>Even though Beer Near Me was only ever really built as a weekend project intended to help me learn about using the <code>navigator.geolocation</code> API, it was still pretty important to get some data to display on a map showing where the local beer was. After all, without that what would the point be?</p>

<h2>Gathering the Data</h2>

<p>To gather the local beer data I make several searches using the <a rel="nofollow" target="_blank" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_fonje_local">Google Local Search API</a> &#8211; one that covers pubs, one for cocktail bars, one for off-licences, and so on.  The searches I make to Google&#8217;s local search look something a little like this:</p>

<pre><code>http://ajax.googleapis.com/ajax/services/search/local
    ?v=1.0
    sll={$sll}
    radius=1
    q={$thing}%20loc:{$sll}
    key={$apiKey}
</code></pre>

<p>Lets walk through those query string parameters…</p>

<ul>
<li><p><code>sll</code> doesn&#8217;t actually stand for anything according to the docs, but denotes the centre point of of the search you&#8217;d like to perform.  It&#8217;s a comma separated latitude/longitude value, so you&#8217;d use something like <code>52.2282962,0.1537945</code> for this parameter.</p></li>
<li><p><code>radius</code> is the radius around the centre point that you&#8217;d like to search within, in miles.</p></li>
<li><p><code>q</code> is the most important parameter by far though; being the query term for the thing you&#8217;re wanting to search for.  </p>

<p>You&#8217;ll notice that I&#8217;ve added a <code>loc:</code> onto the query.  It turns out that without this undocumented extra bit of data, Google really doesn&#8217;t return much from its local searches.  Before <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/">last week&#8217;s post</a> I wasn&#8217;t using this extra qualifier, and whilst my searches were being centered around the expected point they weren&#8217;t returning much data. </p>

<p>A case in point was around The Bricklayers Arms. Without the <code>loc:</code> qualifier The Bricklayers Arms was nowhere to be found.  With the qualifier it suddenly started being returned by the searches to Google, along with a whole bunch of other local pubs.</p></li>
</ul>

<h2>Interpreting the Data</h2>

<p>So, if that&#8217;s the search we make, what does the data we get back look like?</p>

<pre><code>{
    "responseData": {
        "results": [
            {
                "GsearchResultClass":"GlocalSearch",
                "lat":"59.334743",
                "lng":"18.063034",
                "accuracy":"8",
                "title":"&#92;u003cb&#92;u003ePub&#92;u003c/b&#92;u003e",
                "titleNoFormatting":"Pub",
                "streetAddress":"Hötorget 13",
                "city":"Stockholm",
                "country":"Sweden",
                …
                "phoneNumbers":[
                    {"type":"","number":"08-782 19 30"},
                    {"type":"","number":"08-789 19 30"}
                ],
                "addressLines":[
                    "Hötorget 13",
                    "111 57 Stockholm, Sweden"
                ]
            },
            {
                // another result
            }
        ]
    }, 
    "responseDetails": null, 
    "responseStatus": 200
}
</code></pre>

<p>(The data above is, by necessity, just a snippet of what&#8217;s actually returned.)</p>

<p>You&#8217;ll notice first of all that each result we get has a <code>GsearchResultClass</code> of <code>GlocalSearch</code> set.  This allows easy checking of the data type returned.  For our searches, the result class will always be <code>GlocalSearch</code>, but other searches would return values for web searches, images searches and more.</p>

<p>Moving on to the data that actually interests us, each item has the expected <code>lat</code> and <code>lng</code> attributes, along with other useful smidgens of data such as <code>title</code>, <code>streetAddress</code> etc.  </p>

<p>Of particular note are the <code>title</code> and <code>titleNoFormatting</code> attributes.  You&#8217;ll notice that within the <code>title</code> field the word &#8220;pub&#8221; is encapsulated in encoded bold tags.  Two things to note here;  first, &#8220;pub&#8221; was the thing we searched for, so this gets emboldened in the standard display that Google would like to use for results (but we&#8217;re still provided <code>titleNoFormatting</code> if we&#8217;d like to have access to an unformatted string). Second, any formatting applied by google in its API results will be encoded in this way.  In Beer Near Me, I take the easy way out for the data I&#8217;m needing, and use <code>titleNoFormatting</code>.</p>

<p>Moving away from the data that comes from a single API request, lets take a quick look at what happens once we move into the world of performing lots of searches at once.  Since with Beer Near Me I&#8217;m making multiple calls to Google to gather beer related locations, there&#8217;s the pretty large possibility that more than one of the searches will return the same place within its results.  The deduping I do on Beer Near Me is very simple in this case &#8211; I simply keep track of the latitudes and longitudes of all the places that have been returned.  That way if any locations turn up in a position that&#8217;s already had data assigned it it I can ignore it.  It&#8217;s not perfect, but it does the job well enough.</p>

<h2>Caching the Data</h2>

<p>The last thing I want to briefly mention that I&#8217;m doing with the data is caching it using PHP&#8217;s <a rel="nofollow" target="_blank" href="http://php.net/apc">APC</a>.</p>

<p>This was the first time I&#8217;d attempted using APC on one of my own projects, so I had to install it on my Ubuntu based dev box.  I did that following <a rel="nofollow" target="_blank" href="http://www.debian-administration.org/articles/574">these instructions</a>.</p>

<p>The reason for using APC to cache the calls to Google&#8217;s Local Search is simple &#8211; network calls are expensive and slow.  With on average five calls to Local Search occurring on each page load on Beer Near Me you&#8217;d hope that they wouldn&#8217;t be having to go across network every single time.   So, I implemented a very simple cache check:</p>

<pre><code>$url = "http://ajax.google…q=somesearch"
$urlHash = md5($url);

// Try and pull the data from cache
$results = apc_fetch($urlHash);

// If we don't find the data in cache we'll have to make
// an expensive call across the network.
if (!$results) {
    // Get the data however you'd normally get it
    …
    $results = curl_exec($ch);

    // now store the data in APC
    apc_store(
        $urlHash, // Key to identify the cache by
        $results, // Data from our curl call to store 
        $ttl      // Seconds - how long we'll cache for
    );
}
</code></pre>

<p>As you can see above, I&#8217;m only using two APC methods &#8211; <code>apc_fetch</code> and <code>apc_store</code>.  Really, this is all you generally need for simple caching; one method for getting the data if it already exists, and one for storing it in the cache if you had to get the data from elsewhere.</p>

<p>With that in place, any further requests to that same location will be a lot faster, since we&#8217;ll have stored the results locally.  Result.  For Beer Near Me I can afford to be fairly aggressive with our caching, since for the most parts new pubs and cocktail bars won&#8217;t spring up over the course of a few minutes and become immediately available in Google&#8217;s search results.</p>

<h2>No more locations</h2>

<p>And that&#8217;s it.  As far as I&#8217;m concerned, that&#8217;s everything I&#8217;ve done so far on Beer Near Me.  It&#8217;s been a fun little weekend project, and whilst there&#8217;s more I&#8217;d like to do with it at some point, I think I&#8217;m going to leave it alone for a few weeks now.  After all, <a rel="nofollow" target="_blank" href="http://sciencehackday.com">Science HackDay</a> is in just over two weeks time, and no doubt I&#8217;ll get wonderfully caught up in something new for that.  Hopefully whatever I hack on will even be useful.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/LZDu1ldw8JY" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Geolocation &amp; Beer: Part 3 – Static Maps</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/iZqu4-YnFuk/</link>
         <description>&lt;p&gt;The final thing to do now that you&amp;#8217;ve &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/&quot;&gt;found the user&amp;#8217;s latitude and longitude&lt;/a&gt; and &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/&quot;&gt;told them where they are in a human readable format&lt;/a&gt; is to put all the data you&amp;#8217;ve gathered onto a map.  &lt;/p&gt;

&lt;p&gt;Now, there are lots of tutorials out there for the JavaScript based Google Maps API.  So, if you want to learn how to use the JavaScript based API, then I urge you to pop off and look at one of those.  For &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me&quot;&gt;Beer Near Me&lt;/a&gt;, I started off using that API.  However, for various reasons (slow to download over the phone network, scrolling issues on the iPhone), I decided to move away from that and towards the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://code.google.com/apis/maps/documentation/staticmaps/&quot;&gt;Google Static Map API&lt;/a&gt;. The big win for me in using the Static Map API is that it means the user only has to download a single image into their browser, and all the hard work of putting the map together is done on the server-side.  The negatives are that you don&amp;#8217;t get nice clickable areas on the map for free, and you don&amp;#8217;t get to scroll around easily.&lt;/p&gt;

&lt;p&gt;For me, the positives outweighed the negatives, so I went with the static map.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://maps.google.com/maps/api/staticmap
    ?sensor=true
    &amp;amp;size=320x300
    &amp;amp;zoom=15
    &amp;amp;maptype=roadmap
    &amp;amp;mobile=true
    &amp;amp;center=lat,lon
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, although there are a whole bunch of parameters needed to put a map together, they are all fairly simply.  Lets walk through them one at a time:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://maps.google.com/maps/api/staticmap?sensor=true&amp;#038;size=320x300&amp;#038;zoom=15&amp;#038;maptype=roadmap&amp;#038;mobile=true&amp;#038;center=52.2282962,0.1537945&quot; alt=&quot;A simple static google map&quot; class=&quot;sidenote&quot;&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sensor&lt;/code&gt;: Required; either true or false. This simply tells google whether or not we used a sensor to generate this maps&amp;#8217;s position. For us, this will always be true.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt;: Very simple, just width, an &amp;#8216;x&amp;#8217;, and then height in pixels.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;zoom&lt;/code&gt;: How zoomed in you are. 15 gives you a pretty zoomed in map.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maptype&lt;/code&gt;: For us, a roadmap is what we want.  You can also choose satellite or terrain, the same as if you were using the Google Maps site.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mobile&lt;/code&gt;: Setting this to true allegedly gives you slightly simplified maps that have a lower weight.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;center&lt;/code&gt;: Finally, where the centre of our maps should be.  Simple.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put it all together and you get something a little like &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://maps.google.com/maps/api/staticmap?sensor=true&amp;amp;size=320x300&amp;amp;zoom=15&amp;amp;maptype=roadmap&amp;amp;mobile=true&amp;amp;center=52.2282962,0.1537945&quot;&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Adding some custom markers&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.022.jpg&quot; alt=&quot;Getting a static map&quot;&gt; &lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.024.jpg&quot; alt=&quot;Custom markers&quot;&gt;&lt;/p&gt;

&lt;p&gt;But, that&amp;#8217;s a bit boring.  Normal Google Maps let you add all sorts of custom icons.  Well, we can do that too, by adding one or more &lt;code&gt;markers&lt;/code&gt; parameters to the image URL.  So, to add three icons to a map, two of them the same and the third different, you&amp;#8217;d add something like the following to the above URL.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;markers=
    icon:http:%3A%2F%2Furl.encoded%2Fimage.png
    |shadow:false
    |52.2282962,0.1537945
    |52.134152,-0.486364
&amp;amp;markers=
    icon:http:%3A%2F%2Furl.encoded%2Fotherimage.gif
    |shadow:false
    |52.135472,-0.491835
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;#8217;s all there is to it.  After you whack a load of markers onto the URL you&amp;#8217;ll end up with something like the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me/coord/51.517819/-0.13150/&quot;&gt;Tottenham Court Road on Beer Near Me&lt;/a&gt;, where you can see, amongst all the other drinking establishments, The Bricklayers Arms &amp;#8211; the home of &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.pubstandards.co.uk/&quot;&gt;Pub Standards&lt;/a&gt; (the middle thursday of every month &amp;#8211; tell your friends).&lt;/p&gt;

&lt;h2&gt;Making the map clickable&lt;/h2&gt;

&lt;p&gt;You might also notice on that page that if you click or tap on any of the icons on the map that you end with a popup telling you about the place. But how is this possible? Aren&amp;#8217;t we using Google&amp;#8217;s Static map API?&lt;/p&gt;

&lt;p&gt;The answer is &amp;#8220;yes, we&amp;#8217;re still using Google&amp;#8217;s Static map API&amp;#8221;, but we&amp;#8217;re using a little sliver of progressive enhancement to layer data on top of it.  If you turn JavaScript and CSS off for a moment, you&amp;#8217;ll notice a couple of lists underneath the map image.  The first contains links which have targets pointing to the relevant items in the second list.  So, with no CSS or JavaScript clicking the links will move you through the page to the data.  Useful, but not yet useful enough.&lt;/p&gt;

&lt;p&gt;So, what if the user has CSS enabled? What can we do then?  Well, what I chose to do on Beer Near me was to position each of those links over the icon they were assigned to.  First off, all the icons were the same size, so I created some base CSS that I could hang the final positions off:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#map_canvas {
    position: relative;
}

#map_canvas .marker,
#map_canvas .marker a {
    display: block;
    width: 30px;
    height: 30px;
    overflow: hidden;
    text-indent: -9000em;
    list-style: none;
}

#map_canvas .marker {
    position: absolute;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course, if we just did that then all the clickable areas on the map would be dumped up in the top right of the map, and no-one would be happy.  So, we need to work out where to put those &lt;code&gt;top&lt;/code&gt; and &lt;code&gt;left&lt;/code&gt; directives.&lt;/p&gt;

&lt;h3&gt;Warning. Hard-coded Assumptions Incoming&lt;/h3&gt;

&lt;p&gt;Now, it turns out that if you&amp;#8217;re zoomed in to a Google zoom of 15 then each pixel equates to roughly 0.0000266667 units of latitude and 0.0000421875 units of longitude.  So, we can use this to work out where we&amp;#8217;d like to position our clickable elements.&lt;/p&gt;

&lt;p&gt;Lets take an example:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You have created a map that is 320 pixels wide and 300 pixels high, and zoomed to a level of 15.  The centre of this map is at &lt;code&gt;51.510953,-0.133012&lt;/code&gt;.&lt;/p&gt;
  
  &lt;p&gt;A public drinking establishment (De Hems) exists at &lt;code&gt;51.512081,-0.131288&lt;/code&gt;.  Assuming a 30&amp;#215;30 clickable area with its centre at De Hem&amp;#8217;s location, what should the top and left co-ordinates of the clickable area be?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On Beer Near Me, I work out the numbers using some code that looks something like the following.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$mapHeightPix = 300;
$latPerPixel  = 0.0000266667;

$centreLat    = 51.510953;
$locationLat  = 51.512081;
$latDiff      = $locationLat - $centreLat;

$topPix = ($mapHeightPix / 2) - (int)($latDiff / $latPerPixel) - 15;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unsurprisingly, there&amp;#8217;s something remarkably similar for longitudes.  (If you&amp;#8217;re wondering, the answer was &lt;code&gt;top: 93px; left: 185px;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, with that code in place to position the clickable areas on the map users can click and be taken to the relevant item further down the page.  On Beer Near Me I then layered on top some JavaScript to do a simple popup (again, look at the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me/coord/51.517819/-0.13150/&quot;&gt;Tottenham Court Road&lt;/a&gt; page), but I&amp;#8217;ll leave that as an exercise for the reader.&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s essentially that.  What started as a simple weekend project to learn how to use the &lt;code&gt;navigator.geolocation&lt;/code&gt; API ballooned slightly to encompass Google&amp;#8217;s local search API and static maps APIs, and I ended up with &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me&quot;&gt;something slightly useful&lt;/a&gt;.  Maybe in a year or two I&amp;#8217;ll have even made it pretty.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=391</guid>
         <pubDate>Mon, 17 May 2010 20:10:43 +0000</pubDate>
         <content:encoded><![CDATA[<p>The final thing to do now that you&#8217;ve <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/">found the user&#8217;s latitude and longitude</a> and <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">told them where they are in a human readable format</a> is to put all the data you&#8217;ve gathered onto a map.  </p>

<p>Now, there are lots of tutorials out there for the JavaScript based Google Maps API.  So, if you want to learn how to use the JavaScript based API, then I urge you to pop off and look at one of those.  For <a rel="nofollow" target="_blank" href="http://beernear.me">Beer Near Me</a>, I started off using that API.  However, for various reasons (slow to download over the phone network, scrolling issues on the iPhone), I decided to move away from that and towards the <a rel="nofollow" target="_blank" href="http://code.google.com/apis/maps/documentation/staticmaps/">Google Static Map API</a>. The big win for me in using the Static Map API is that it means the user only has to download a single image into their browser, and all the hard work of putting the map together is done on the server-side.  The negatives are that you don&#8217;t get nice clickable areas on the map for free, and you don&#8217;t get to scroll around easily.</p>

<p>For me, the positives outweighed the negatives, so I went with the static map.</p>

<pre><code>http://maps.google.com/maps/api/staticmap
    ?sensor=true
    &amp;size=320x300
    &amp;zoom=15
    &amp;maptype=roadmap
    &amp;mobile=true
    &amp;center=lat,lon
</code></pre>

<p>As you can see, although there are a whole bunch of parameters needed to put a map together, they are all fairly simply.  Lets walk through them one at a time:</p>

<p><img src="http://maps.google.com/maps/api/staticmap?sensor=true&#038;size=320x300&#038;zoom=15&#038;maptype=roadmap&#038;mobile=true&#038;center=52.2282962,0.1537945" alt="A simple static google map" class="sidenote"></p>

<ul>
<li><code>sensor</code>: Required; either true or false. This simply tells google whether or not we used a sensor to generate this maps&#8217;s position. For us, this will always be true.</li>
<li><code>size</code>: Very simple, just width, an &#8216;x&#8217;, and then height in pixels.</li>
<li><code>zoom</code>: How zoomed in you are. 15 gives you a pretty zoomed in map.</li>
<li><code>maptype</code>: For us, a roadmap is what we want.  You can also choose satellite or terrain, the same as if you were using the Google Maps site.</li>
<li><code>mobile</code>: Setting this to true allegedly gives you slightly simplified maps that have a lower weight.</li>
<li><code>center</code>: Finally, where the centre of our maps should be.  Simple.</li>
</ul>

<p>Put it all together and you get something a little like <a rel="nofollow" target="_blank" href="http://maps.google.com/maps/api/staticmap?sensor=true&amp;size=320x300&amp;zoom=15&amp;maptype=roadmap&amp;mobile=true&amp;center=52.2282962,0.1537945">this</a>.</p>

<h2>Adding some custom markers</h2>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.022.jpg" alt="Getting a static map"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.024.jpg" alt="Custom markers"></p>

<p>But, that&#8217;s a bit boring.  Normal Google Maps let you add all sorts of custom icons.  Well, we can do that too, by adding one or more <code>markers</code> parameters to the image URL.  So, to add three icons to a map, two of them the same and the third different, you&#8217;d add something like the following to the above URL.</p>

<pre><code>markers=
    icon:http:%3A%2F%2Furl.encoded%2Fimage.png
    |shadow:false
    |52.2282962,0.1537945
    |52.134152,-0.486364
&amp;markers=
    icon:http:%3A%2F%2Furl.encoded%2Fotherimage.gif
    |shadow:false
    |52.135472,-0.491835
</code></pre>

<p>And that&#8217;s all there is to it.  After you whack a load of markers onto the URL you&#8217;ll end up with something like the <a rel="nofollow" target="_blank" href="http://beernear.me/coord/51.517819/-0.13150/">Tottenham Court Road on Beer Near Me</a>, where you can see, amongst all the other drinking establishments, The Bricklayers Arms &#8211; the home of <a rel="nofollow" target="_blank" href="http://www.pubstandards.co.uk/">Pub Standards</a> (the middle thursday of every month &#8211; tell your friends).</p>

<h2>Making the map clickable</h2>

<p>You might also notice on that page that if you click or tap on any of the icons on the map that you end with a popup telling you about the place. But how is this possible? Aren&#8217;t we using Google&#8217;s Static map API?</p>

<p>The answer is &#8220;yes, we&#8217;re still using Google&#8217;s Static map API&#8221;, but we&#8217;re using a little sliver of progressive enhancement to layer data on top of it.  If you turn JavaScript and CSS off for a moment, you&#8217;ll notice a couple of lists underneath the map image.  The first contains links which have targets pointing to the relevant items in the second list.  So, with no CSS or JavaScript clicking the links will move you through the page to the data.  Useful, but not yet useful enough.</p>

<p>So, what if the user has CSS enabled? What can we do then?  Well, what I chose to do on Beer Near me was to position each of those links over the icon they were assigned to.  First off, all the icons were the same size, so I created some base CSS that I could hang the final positions off:</p>

<pre><code>#map_canvas {
    position: relative;
}

#map_canvas .marker,
#map_canvas .marker a {
    display: block;
    width: 30px;
    height: 30px;
    overflow: hidden;
    text-indent: -9000em;
    list-style: none;
}

#map_canvas .marker {
    position: absolute;
}
</code></pre>

<p>Of course, if we just did that then all the clickable areas on the map would be dumped up in the top right of the map, and no-one would be happy.  So, we need to work out where to put those <code>top</code> and <code>left</code> directives.</p>

<h3>Warning. Hard-coded Assumptions Incoming</h3>

<p>Now, it turns out that if you&#8217;re zoomed in to a Google zoom of 15 then each pixel equates to roughly 0.0000266667 units of latitude and 0.0000421875 units of longitude.  So, we can use this to work out where we&#8217;d like to position our clickable elements.</p>

<p>Lets take an example:</p>

<blockquote>
  <p>You have created a map that is 320 pixels wide and 300 pixels high, and zoomed to a level of 15.  The centre of this map is at <code>51.510953,-0.133012</code>.</p>
  
  <p>A public drinking establishment (De Hems) exists at <code>51.512081,-0.131288</code>.  Assuming a 30&#215;30 clickable area with its centre at De Hem&#8217;s location, what should the top and left co-ordinates of the clickable area be?</p>
</blockquote>

<p>On Beer Near Me, I work out the numbers using some code that looks something like the following.</p>

<pre><code>$mapHeightPix = 300;
$latPerPixel  = 0.0000266667;

$centreLat    = 51.510953;
$locationLat  = 51.512081;
$latDiff      = $locationLat - $centreLat;

$topPix = ($mapHeightPix / 2) - (int)($latDiff / $latPerPixel) - 15;
</code></pre>

<p>Unsurprisingly, there&#8217;s something remarkably similar for longitudes.  (If you&#8217;re wondering, the answer was <code>top: 93px; left: 185px;</code>).</p>

<p>Now, with that code in place to position the clickable areas on the map users can click and be taken to the relevant item further down the page.  On Beer Near Me I then layered on top some JavaScript to do a simple popup (again, look at the <a rel="nofollow" target="_blank" href="http://beernear.me/coord/51.517819/-0.13150/">Tottenham Court Road</a> page), but I&#8217;ll leave that as an exercise for the reader.</p>

<p>And that&#8217;s essentially that.  What started as a simple weekend project to learn how to use the <code>navigator.geolocation</code> API ballooned slightly to encompass Google&#8217;s local search API and static maps APIs, and I ended up with <a rel="nofollow" target="_blank" href="http://beernear.me">something slightly useful</a>.  Maybe in a year or two I&#8217;ll have even made it pretty.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/iZqu4-YnFuk" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Geolocation &amp; Beer: Part 2 – Telling the User where they are</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/hOwkNYFOEnc/</link>
         <description>&lt;p&gt;In the last entry, I wrote about how we can &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/&quot;&gt;use the &lt;code&gt;navigator.geolocation&lt;/code&gt; API to find a user&amp;#8217;s current location&lt;/a&gt;.  In today&amp;#8217;s post I&amp;#8217;m going to continue on to talk about taking that location and turning it into a piece of human readable text that tells the user where they are.&lt;/p&gt;

&lt;p&gt;After all, having a latitude and longitude is all well and good, but as humans we tend not to think that way.  So, it would be quite nice to give the user a street address identifying their location.  As it turns out, this is pretty easy &amp;#8211; the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://code.google.com/apis/ajaxsearch/documentation/reference.html#_intro_fonje&quot;&gt;Google Local Search API&lt;/a&gt; has this functionality baked in.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://ajax.googleapis.com/ajax/services/search/local
    ?v=1.0
    q=lat,lon
    key=yourgoogleapikey
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you add your comma separated latitude and longitude to the structure above, Google will very helpfully return you back a load of data that tells you where it thinks you are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;{
    &quot;responseData&quot;: {
        &quot;results&quot;: [{
            …
            &quot;title&quot;: &quot;Kelly Langley…&quot;,
            &quot;streetAddress&quot;: &quot;Cowley Road, Cavendish House…&quot;,
            &quot;city&quot;: &quot;Cambridge&quot;,
            …
        }]
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is only a chunk of the data that gets returned by Google, but hopefully it should be enough to give you a taste of what&amp;#8217;s available. The obvious thing to do at this point is grab the street address, and maybe the city, and output them as a string to show the user.  This is what &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me&quot;&gt;Beer Near Me&lt;/a&gt; is currently doing.&lt;/p&gt;

&lt;p&gt;&lt;img src='http://thecodetrain.co.uk/images/geolocation/geolocation.018.jpg' alt='Getting an address'&gt; &lt;img src='http://thecodetrain.co.uk/images/geolocation/geolocation.019.jpg' alt='Bob of location data'&gt;&lt;/p&gt;

&lt;p&gt;One piece of data we haven&amp;#8217;t used yet though is the &lt;code&gt;accuracy&lt;/code&gt; data that is returned by &lt;code&gt;navigator.geolocation.getCurrentPosition&lt;/code&gt;.  You&amp;#8217;ll remember from the last post that &lt;code&gt;accuracy&lt;/code&gt; is measured in metres and shows the confidence that the browser has of the location it&amp;#8217;s returned.  So, if &lt;code&gt;accuracy&lt;/code&gt; is given as 500, then the user might be anywhere within a half kilometre radius of the given location &amp;#8211; not particularly accurate, and saying that they were on a specific street would be misleading.  If, on the other hand, the &lt;code&gt;accuracy&lt;/code&gt; given was 25 then the user would be expected to be within a 25 metre radius of the given location &amp;#8211; pretty damn accurate.&lt;/p&gt;

&lt;p&gt;So, what can we do with this? Well, if we&amp;#8217;re not happy that the &lt;code&gt;accuracy&lt;/code&gt; is good enough then we could tell the user they were &amp;#8220;Somewhere in &lt;code&gt;city&lt;/code&gt;&amp;#8221; instead of simply showing them the street name of their location.  On Beer Near Me, I could also stop the &amp;#8220;Find me some beer&amp;#8221; button from working until the &lt;code&gt;accuracy&lt;/code&gt; was good enough.&lt;/p&gt;

&lt;p&gt;So, that&amp;#8217;s how I&amp;#8217;m dealing with showing the user where they are in a nice human readable way on &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me&quot;&gt;Beer Near Me&lt;/a&gt; &amp;#8211; it&amp;#8217;s pretty easy, right?  In the next entry I&amp;#8217;ll finish off talking about the &lt;code&gt;navigator.geolocation&lt;/code&gt; API by &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/&quot;&gt;putting the user&amp;#8217;s location onto a static Google Map&lt;/a&gt;.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=387</guid>
         <pubDate>Thu, 13 May 2010 22:00:23 +0000</pubDate>
         <content:encoded><![CDATA[<p>In the last entry, I wrote about how we can <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/">use the <code>navigator.geolocation</code> API to find a user&#8217;s current location</a>.  In today&#8217;s post I&#8217;m going to continue on to talk about taking that location and turning it into a piece of human readable text that tells the user where they are.</p>

<p>After all, having a latitude and longitude is all well and good, but as humans we tend not to think that way.  So, it would be quite nice to give the user a street address identifying their location.  As it turns out, this is pretty easy &#8211; the <a rel="nofollow" target="_blank" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_intro_fonje">Google Local Search API</a> has this functionality baked in.</p>

<pre><code>http://ajax.googleapis.com/ajax/services/search/local
    ?v=1.0
    q=lat,lon
    key=yourgoogleapikey
</code></pre>

<p>If you add your comma separated latitude and longitude to the structure above, Google will very helpfully return you back a load of data that tells you where it thinks you are:</p>

<pre><code>{
    "responseData": {
        "results": [{
            …
            "title": "Kelly Langley…",
            "streetAddress": "Cowley Road, Cavendish House…",
            "city": "Cambridge",
            …
        }]
    }
}
</code></pre>

<p>This is only a chunk of the data that gets returned by Google, but hopefully it should be enough to give you a taste of what&#8217;s available. The obvious thing to do at this point is grab the street address, and maybe the city, and output them as a string to show the user.  This is what <a rel="nofollow" target="_blank" href="http://beernear.me">Beer Near Me</a> is currently doing.</p>

<p><img src='http://thecodetrain.co.uk/images/geolocation/geolocation.018.jpg' alt='Getting an address'> <img src='http://thecodetrain.co.uk/images/geolocation/geolocation.019.jpg' alt='Bob of location data'></p>

<p>One piece of data we haven&#8217;t used yet though is the <code>accuracy</code> data that is returned by <code>navigator.geolocation.getCurrentPosition</code>.  You&#8217;ll remember from the last post that <code>accuracy</code> is measured in metres and shows the confidence that the browser has of the location it&#8217;s returned.  So, if <code>accuracy</code> is given as 500, then the user might be anywhere within a half kilometre radius of the given location &#8211; not particularly accurate, and saying that they were on a specific street would be misleading.  If, on the other hand, the <code>accuracy</code> given was 25 then the user would be expected to be within a 25 metre radius of the given location &#8211; pretty damn accurate.</p>

<p>So, what can we do with this? Well, if we&#8217;re not happy that the <code>accuracy</code> is good enough then we could tell the user they were &#8220;Somewhere in <code>city</code>&#8221; instead of simply showing them the street name of their location.  On Beer Near Me, I could also stop the &#8220;Find me some beer&#8221; button from working until the <code>accuracy</code> was good enough.</p>

<p>So, that&#8217;s how I&#8217;m dealing with showing the user where they are in a nice human readable way on <a rel="nofollow" target="_blank" href="http://beernear.me">Beer Near Me</a> &#8211; it&#8217;s pretty easy, right?  In the next entry I&#8217;ll finish off talking about the <code>navigator.geolocation</code> API by <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/">putting the user&#8217;s location onto a static Google Map</a>.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/hOwkNYFOEnc" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Geolocation &amp; Beer: Part 1 – Finding the user</title>
         <link>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/ERzzqZ9HSAU/</link>
         <description>&lt;p&gt;I recently attended &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://barcamb.ltheobald.co.uk/&quot;&gt;BarCamb3&lt;/a&gt;, a BarCamp held at the lovely &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.red-gate.com/&quot;&gt;Red Gate Software&lt;/a&gt; offices in Cambridge.  My main contribution to the event was talking about a silly little weekend learning project I&amp;#8217;ve been working on &amp;#8211; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me/&quot;&gt;Beer Near Me&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve split the presentation I gave up into three separate blog posts, which I&amp;#8217;ll be putting up over the next few days.  This one will cover basic use of the &lt;code&gt;navigator.geolocation&lt;/code&gt; API, with the next two showing you how to use the data that gives you to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/&quot;&gt;find out where the user actually is&lt;/a&gt;, and to &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/&quot;&gt;plot that data using Google&amp;#8217;s static maps API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To start, I should explain that Beer Near Me was only ever intended to be used as a platform to be used to help me learn about the &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://dev.w3.org/geo/api/spec-source.html&quot;&gt;&lt;code&gt;navigator.geolocation&lt;/code&gt; API&lt;/a&gt; and how it works.  All the data that gets shown by the site was initially kind of secondary to me, as was the map that I use to show it off.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.001.png&quot; alt=&quot;GeoLocation &amp;#038; Beer&quot;&gt; &lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.009.png&quot; alt=&quot;What will I talk about?&quot;&gt;&lt;/p&gt;

&lt;p&gt;Of course, &lt;code&gt;navigator.geolocation&lt;/code&gt; turned out to be far easier to work with than I expected.&lt;/p&gt;

&lt;h2&gt;Support for navigator.geolocation&lt;/h2&gt;

&lt;p&gt;The first thing to be aware of is that right now, support for &lt;code&gt;navigator.geolocation&lt;/code&gt; is pretty poor.  If you&amp;#8217;re using Firefox 3.5+ or Mobile Safari you can use it out of the box, and you can &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.wait-till-i.com/2010/03/04/google-chrome-getting-navigator-geolocation/&quot;&gt;turn on geolocation support in Chrome&lt;/a&gt;, but apart from that you&amp;#8217;re plain out of luck.  Since the idea behind Beer Near Me was to learn about &lt;code&gt;navigator.geolocation&lt;/code&gt; that means that right now I&amp;#8217;m not supporting any other APIs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.011.png&quot; alt=&quot;navigator.geolocation support&quot;&gt; &lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.012.jpg&quot; alt=&quot;Other APIs are available&quot;&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s not all doom and gloom though.  There are implementations of the API available for use in other browsers as plugins &amp;#8211; for example &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://en.wikipedia.org/wiki/Mozilla_Geode&quot;&gt;Geode&lt;/a&gt; will get you support in earlier versions of Firefox 3, and Google Gears opens up the ability to play with geolocation in some other browsers.  There&amp;#8217;s also &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://www.loki.com&quot;&gt;Loki&lt;/a&gt; (a Skyhook based plugin) that will get you support over a whole bunch of browsers but uses a differently specified API. Of course, I&amp;#8217;ve not actually used any of these, so your guess is as good as mine as to whether they are any good or not.  I seem to remember Loki looking interesting a couple of years ago.&lt;/p&gt;

&lt;h2&gt;Finding a location&lt;/h2&gt;

&lt;p&gt;So, how to actually use &lt;code&gt;navigator.geolocation&lt;/code&gt;?  Well, a good place to start would be checking whether the browser supports it.  We&amp;#8217;ll do this in JavaScript, since that&amp;#8217;s the only place we can reliably perform the check.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if (navigator.geolocation) {
    // do geolocation
} else {
    // say sorry to the user
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Pretty simple.  It&amp;#8217;s your standard JavaScript functionality check.  If we have the functionality available then we can actually do something with it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;navigator.geolocation.getCurrentPosition(
    foundLocation, // a user generated function
    noLocation,    // yup, user generated too
    {
        enableHighAccuracy: true,
        maximumAge: 1800,
        timeout: 30
    }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, we&amp;#8217;re calling &lt;code&gt;getCurrentLocation()&lt;/code&gt; with two callback functions and some options.  Once the browser (and the user) has decided whether or not to return a location, either the &lt;code&gt;foundLocation&lt;/code&gt; or &lt;code&gt;noLocation&lt;/code&gt; functions that you get to write are called, and the user&amp;#8217;s location is passed into them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.013.jpg&quot; alt=&quot;GeoLocation check&quot;&gt; &lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.014.jpg&quot; alt=&quot;getCurrentPosition&quot;&gt;&lt;/p&gt;

&lt;p&gt;Before we get to those callback functions though, lets talk for a minute about the options we&amp;#8217;re passing into &lt;code&gt;getCurrentPosition()&lt;/code&gt;.  Essentially, what we&amp;#8217;re saying in the code above is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Try to give me highly accurate positioning if possible. I&amp;#8217;d like to actually know where I am.&lt;/p&gt;
  
  &lt;p&gt;Oh, and if you have a position cached that&amp;#8217;s no older than 30 minutes, could you give me that immediately please?  I know that kind of contradicts what I said a moment ago, but I know better than you.&lt;/p&gt;
  
  &lt;p&gt;And one more thing &amp;#8211; if it takes you longer than 30 seconds to work out where you are, just give up.  There&amp;#8217;s a good fellow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that&amp;#8217;s it really, with that little bit of code we&amp;#8217;ve set up the browser to do some magic and try and work out where it is.&lt;/p&gt;

&lt;h2&gt;Watching for changes to the user&amp;#8217;s location&lt;/h2&gt;

&lt;p&gt;The only problem with this is that the iPhone in particular seems a bit rubbish at following these instructions.  The first result it sends back seems to be uniformly Not Good, and generally quite old.  So what can we do about that?  Thankfully, there&amp;#8217;s an easy answer provided to us in the API &amp;#8211; the &lt;code&gt;watchPosition()&lt;/code&gt; function.  This uses exactly the same parameters as &lt;code&gt;getCurrentLocation()&lt;/code&gt; and can simply be dropped in as a replacement for it.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.015.jpg&quot; alt=&quot;Keep finding the user&quot;&gt; &lt;img src=&quot;http://thecodetrain.co.uk/images/geolocation/geolocation.016.jpg&quot; alt=&quot;You've got a location!&quot;&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;watchPosition&lt;/code&gt; does what you&amp;#8217;d expect it to do.  Instead of finding a location once, it will keep watching the user&amp;#8217;s location and call the success function whenever the location changes.  The thing that &lt;code&gt;watchPosition()&lt;/code&gt; is most useful for though, is getting more accurate locations as the user&amp;#8217;s device tries different location finding techniques.&lt;/p&gt;

&lt;p&gt;You see, different devices will try and locate themselves in different ways.  Some of the techniques they&amp;#8217;ll use will be be quick, some slow, and some very expensive when it comes to battery life.  For example, here&amp;#8217;s what the iPhone does, as I understand it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, the iPhone will look to see if there&amp;#8217;s a location cached in its memory and give you that if available.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you&amp;#8217;re still watching for new locations, it will then try and grab a general location from the cell towers it knows about.&lt;/p&gt;

&lt;p&gt;Depending on the number of towers available, this might give you really good, or really bad accuracy.  For example, in Bedford (where I live), using cell tower triangulation I get an accuracy which basically covers the entire town.  Not particularly useful.  It is quick though, and doesn&amp;#8217;t really cost much in terms of power.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the cell tower triangulation wasn&amp;#8217;t awesome then the iPhone will gather information about all the WIFI hotspots it can see.  &lt;/p&gt;

&lt;p&gt;This data gets sent to Skyhook, which does a whole bunch of triangulation and sends back a result.  This is obviously slower than just hitting the cell towers, but it can give you a really accurate result depending on where you are (better than GPS in some built up areas).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, if you&amp;#8217;re still looking for a location, the iPhone will fire up the GPS.  &lt;/p&gt;

&lt;p&gt;This is expensive, slow, and drains the battery, so is left as a last resort.  It generally gives the best quality results though.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, you see, things aren&amp;#8217;t necessarily as simple as asking for a position.  A whole bunch of stuff can be going on in the background, and grabbing the best location the user&amp;#8217;s device knows about as time goes on can be very useful.&lt;/p&gt;

&lt;h2&gt;Using the location we&amp;#8217;ve found&lt;/h2&gt;

&lt;p&gt;So, now that we&amp;#8217;re requesting a location, what do we do once we actually get one?  Lets have a look.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;foundLocation = function(position) {
    // position.coords.latitude
    // position.coords.longitude
    // position.coords.accuracy
    // and more…
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you can see, the function we call on location finding success gets passed a single parameter &amp;#8211; &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://dev.w3.org/geo/api/spec-source.html#position_interface&quot;&gt;&lt;code&gt;position&lt;/code&gt;&lt;/a&gt;.  This object contains a &lt;code&gt;coords&lt;/code&gt; object, and a &lt;code&gt;timestamp&lt;/code&gt; representing the time the location was determined.  It&amp;#8217;s the &lt;code&gt;coords&lt;/code&gt; object we&amp;#8217;re interested in right now, since that contains the latitude, longitude and accuracy (measured in metres) of the user&amp;#8217;s current location &amp;#8211; all the information a grown chap could need for finding some beer.  Other applications might make use of the altitude, heading and speed information, but that&amp;#8217;s not vital when looking for beer, so I&amp;#8217;m ignoring it for now.&lt;/p&gt;

&lt;h2&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;Quickly putting all this together, here&amp;#8217;s some JavaScript you can copy and paste into a page to see this all in action.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/*global document, navigator */
var beerLocation = {
    foundLocation: function (position) {
        beerLocation.setPara(
            &quot;Lat = &quot; + position.coords.latitude + 
            &quot;, lon = &quot; + position.coords.longitude + 
            &quot;, accuracy = &quot; + position.coords.accuracy + &quot;m&quot;);
    },

    noLocation: function () {
        beerLocation.setPara(&quot;Boo! You didn't share your location!&quot;);
    },

    noGeoLocation: function () {
        beerLocation.setPara(
            &quot;Sorry, but your browser doesn't support geolocation.&quot;);
    },

    setPara: function (text) {
        var p = document.getElementById('location-info');
        if (!p) {
            p = document.createElement('p');
            p.id = 'location-info';
            document.body.appendChild(p);
        }

        p.innerHTML = text;
    }
};

if (navigator.geolocation) {
    navigator.geolocation.watchPosition(
        beerLocation.foundLocation, 
        beerLocation.noLocation,
        {
            enableHighAccuracy: true,
            maximumAge: 120000
        }
    );
} else {
    beerLocation.noGeoLocation();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Alternatively, take a look at it in situ and in action on my &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://projects.thecodetrain.co.uk/geolocation/&quot;&gt;geolocation test page&lt;/a&gt;.  The location shown by this page will keep updating as you move around or your device&amp;#8217;s accuracy improves.  For best results, try it out on an iPhone.&lt;/p&gt;

&lt;h2&gt;And finally&lt;/h2&gt;

&lt;p&gt;And that&amp;#8217;s how easy it is to find a user&amp;#8217;s location and keep updating it.  You just need to do something with the latitude and longitude once you&amp;#8217;ve found it.&lt;/p&gt;

&lt;p&gt;In &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://beernear.me/&quot;&gt;Beer Near Me&lt;/a&gt; I do two things with the location once it&amp;#8217;s been found &amp;#8211; I &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/&quot;&gt;tell the user the street address of the location&lt;/a&gt;, and I display it on a map.  And, of course, I&amp;#8217;ll be writing about how I&amp;#8217;m doing that in the next couple of posts.&lt;/p&gt;
&lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/#comments&quot;&gt;Leave A Comment&lt;/a&gt;&lt;br /&gt;posted in &lt;a rel=&quot;nofollow&quot; target=&quot;_blank&quot; href=&quot;http://thecodetrain.co.uk/category/blog-posts/&quot;&gt;Blog Posts&lt;/a&gt; by Neil Crosby &lt;br&gt;&lt;br&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=389</guid>
         <pubDate>Wed, 05 May 2010 22:10:37 +0000</pubDate>
         <content:encoded><![CDATA[<p>I recently attended <a rel="nofollow" target="_blank" href="http://barcamb.ltheobald.co.uk/">BarCamb3</a>, a BarCamp held at the lovely <a rel="nofollow" target="_blank" href="http://www.red-gate.com/">Red Gate Software</a> offices in Cambridge.  My main contribution to the event was talking about a silly little weekend learning project I&#8217;ve been working on &#8211; <a rel="nofollow" target="_blank" href="http://beernear.me/">Beer Near Me</a>.  </p>

<p>I&#8217;ve split the presentation I gave up into three separate blog posts, which I&#8217;ll be putting up over the next few days.  This one will cover basic use of the <code>navigator.geolocation</code> API, with the next two showing you how to use the data that gives you to <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">find out where the user actually is</a>, and to <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/">plot that data using Google&#8217;s static maps API</a>.</p>

<p>To start, I should explain that Beer Near Me was only ever intended to be used as a platform to be used to help me learn about the <a rel="nofollow" target="_blank" href="http://dev.w3.org/geo/api/spec-source.html"><code>navigator.geolocation</code> API</a> and how it works.  All the data that gets shown by the site was initially kind of secondary to me, as was the map that I use to show it off.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.001.png" alt="GeoLocation &#038; Beer"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.009.png" alt="What will I talk about?"></p>

<p>Of course, <code>navigator.geolocation</code> turned out to be far easier to work with than I expected.</p>

<h2>Support for navigator.geolocation</h2>

<p>The first thing to be aware of is that right now, support for <code>navigator.geolocation</code> is pretty poor.  If you&#8217;re using Firefox 3.5+ or Mobile Safari you can use it out of the box, and you can <a rel="nofollow" target="_blank" href="http://www.wait-till-i.com/2010/03/04/google-chrome-getting-navigator-geolocation/">turn on geolocation support in Chrome</a>, but apart from that you&#8217;re plain out of luck.  Since the idea behind Beer Near Me was to learn about <code>navigator.geolocation</code> that means that right now I&#8217;m not supporting any other APIs.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.011.png" alt="navigator.geolocation support"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.012.jpg" alt="Other APIs are available"></p>

<p>It&#8217;s not all doom and gloom though.  There are implementations of the API available for use in other browsers as plugins &#8211; for example <a rel="nofollow" target="_blank" href="http://en.wikipedia.org/wiki/Mozilla_Geode">Geode</a> will get you support in earlier versions of Firefox 3, and Google Gears opens up the ability to play with geolocation in some other browsers.  There&#8217;s also <a rel="nofollow" target="_blank" href="http://www.loki.com">Loki</a> (a Skyhook based plugin) that will get you support over a whole bunch of browsers but uses a differently specified API. Of course, I&#8217;ve not actually used any of these, so your guess is as good as mine as to whether they are any good or not.  I seem to remember Loki looking interesting a couple of years ago.</p>

<h2>Finding a location</h2>

<p>So, how to actually use <code>navigator.geolocation</code>?  Well, a good place to start would be checking whether the browser supports it.  We&#8217;ll do this in JavaScript, since that&#8217;s the only place we can reliably perform the check.</p>

<pre><code>if (navigator.geolocation) {
    // do geolocation
} else {
    // say sorry to the user
}
</code></pre>

<p>Pretty simple.  It&#8217;s your standard JavaScript functionality check.  If we have the functionality available then we can actually do something with it.</p>

<pre><code>navigator.geolocation.getCurrentPosition(
    foundLocation, // a user generated function
    noLocation,    // yup, user generated too
    {
        enableHighAccuracy: true,
        maximumAge: 1800,
        timeout: 30
    }
);
</code></pre>

<p>Here, we&#8217;re calling <code>getCurrentLocation()</code> with two callback functions and some options.  Once the browser (and the user) has decided whether or not to return a location, either the <code>foundLocation</code> or <code>noLocation</code> functions that you get to write are called, and the user&#8217;s location is passed into them.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.013.jpg" alt="GeoLocation check"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.014.jpg" alt="getCurrentPosition"></p>

<p>Before we get to those callback functions though, lets talk for a minute about the options we&#8217;re passing into <code>getCurrentPosition()</code>.  Essentially, what we&#8217;re saying in the code above is:</p>

<blockquote>
  <p>Try to give me highly accurate positioning if possible. I&#8217;d like to actually know where I am.</p>
  
  <p>Oh, and if you have a position cached that&#8217;s no older than 30 minutes, could you give me that immediately please?  I know that kind of contradicts what I said a moment ago, but I know better than you.</p>
  
  <p>And one more thing &#8211; if it takes you longer than 30 seconds to work out where you are, just give up.  There&#8217;s a good fellow.</p>
</blockquote>

<p>And that&#8217;s it really, with that little bit of code we&#8217;ve set up the browser to do some magic and try and work out where it is.</p>

<h2>Watching for changes to the user&#8217;s location</h2>

<p>The only problem with this is that the iPhone in particular seems a bit rubbish at following these instructions.  The first result it sends back seems to be uniformly Not Good, and generally quite old.  So what can we do about that?  Thankfully, there&#8217;s an easy answer provided to us in the API &#8211; the <code>watchPosition()</code> function.  This uses exactly the same parameters as <code>getCurrentLocation()</code> and can simply be dropped in as a replacement for it.</p>

<p><img src="http://thecodetrain.co.uk/images/geolocation/geolocation.015.jpg" alt="Keep finding the user"> <img src="http://thecodetrain.co.uk/images/geolocation/geolocation.016.jpg" alt="You've got a location!"></p>

<p><code>watchPosition</code> does what you&#8217;d expect it to do.  Instead of finding a location once, it will keep watching the user&#8217;s location and call the success function whenever the location changes.  The thing that <code>watchPosition()</code> is most useful for though, is getting more accurate locations as the user&#8217;s device tries different location finding techniques.</p>

<p>You see, different devices will try and locate themselves in different ways.  Some of the techniques they&#8217;ll use will be be quick, some slow, and some very expensive when it comes to battery life.  For example, here&#8217;s what the iPhone does, as I understand it:</p>

<ol>
<li><p>First, the iPhone will look to see if there&#8217;s a location cached in its memory and give you that if available.</p></li>
<li><p>If you&#8217;re still watching for new locations, it will then try and grab a general location from the cell towers it knows about.</p>

<p>Depending on the number of towers available, this might give you really good, or really bad accuracy.  For example, in Bedford (where I live), using cell tower triangulation I get an accuracy which basically covers the entire town.  Not particularly useful.  It is quick though, and doesn&#8217;t really cost much in terms of power.</p></li>
<li><p>If the cell tower triangulation wasn&#8217;t awesome then the iPhone will gather information about all the WIFI hotspots it can see.  </p>

<p>This data gets sent to Skyhook, which does a whole bunch of triangulation and sends back a result.  This is obviously slower than just hitting the cell towers, but it can give you a really accurate result depending on where you are (better than GPS in some built up areas).</p></li>
<li><p>Finally, if you&#8217;re still looking for a location, the iPhone will fire up the GPS.  </p>

<p>This is expensive, slow, and drains the battery, so is left as a last resort.  It generally gives the best quality results though.</p></li>
</ol>

<p>So, you see, things aren&#8217;t necessarily as simple as asking for a position.  A whole bunch of stuff can be going on in the background, and grabbing the best location the user&#8217;s device knows about as time goes on can be very useful.</p>

<h2>Using the location we&#8217;ve found</h2>

<p>So, now that we&#8217;re requesting a location, what do we do once we actually get one?  Lets have a look.</p>

<pre><code>foundLocation = function(position) {
    // position.coords.latitude
    // position.coords.longitude
    // position.coords.accuracy
    // and more…
}
</code></pre>

<p>As you can see, the function we call on location finding success gets passed a single parameter &#8211; <a rel="nofollow" target="_blank" href="http://dev.w3.org/geo/api/spec-source.html#position_interface"><code>position</code></a>.  This object contains a <code>coords</code> object, and a <code>timestamp</code> representing the time the location was determined.  It&#8217;s the <code>coords</code> object we&#8217;re interested in right now, since that contains the latitude, longitude and accuracy (measured in metres) of the user&#8217;s current location &#8211; all the information a grown chap could need for finding some beer.  Other applications might make use of the altitude, heading and speed information, but that&#8217;s not vital when looking for beer, so I&#8217;m ignoring it for now.</p>

<h2>Putting it all together</h2>

<p>Quickly putting all this together, here&#8217;s some JavaScript you can copy and paste into a page to see this all in action.</p>

<pre><code>/*global document, navigator */
var beerLocation = {
    foundLocation: function (position) {
        beerLocation.setPara(
            "Lat = " + position.coords.latitude + 
            ", lon = " + position.coords.longitude + 
            ", accuracy = " + position.coords.accuracy + "m");
    },

    noLocation: function () {
        beerLocation.setPara("Boo! You didn't share your location!");
    },

    noGeoLocation: function () {
        beerLocation.setPara(
            "Sorry, but your browser doesn't support geolocation.");
    },

    setPara: function (text) {
        var p = document.getElementById('location-info');
        if (!p) {
            p = document.createElement('p');
            p.id = 'location-info';
            document.body.appendChild(p);
        }

        p.innerHTML = text;
    }
};

if (navigator.geolocation) {
    navigator.geolocation.watchPosition(
        beerLocation.foundLocation, 
        beerLocation.noLocation,
        {
            enableHighAccuracy: true,
            maximumAge: 120000
        }
    );
} else {
    beerLocation.noGeoLocation();
}
</code></pre>

<p>Alternatively, take a look at it in situ and in action on my <a rel="nofollow" target="_blank" href="http://projects.thecodetrain.co.uk/geolocation/">geolocation test page</a>.  The location shown by this page will keep updating as you move around or your device&#8217;s accuracy improves.  For best results, try it out on an iPhone.</p>

<h2>And finally</h2>

<p>And that&#8217;s how easy it is to find a user&#8217;s location and keep updating it.  You just need to do something with the latitude and longitude once you&#8217;ve found it.</p>

<p>In <a rel="nofollow" target="_blank" href="http://beernear.me/">Beer Near Me</a> I do two things with the location once it&#8217;s been found &#8211; I <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/">tell the user the street address of the location</a>, and I display it on a map.  And, of course, I&#8217;ll be writing about how I&#8217;m doing that in the next couple of posts.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/ERzzqZ9HSAU" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Chocolate Orange Cupcakes</title>
         <link>http://neilsnoms.com/chocolate-orange-cupcakes/</link>
         <description>Another post, another chance to point to Lay the Table and show off a different recipe than the one Becs used. This time it&amp;#8217;s for big fat nommery Chocolate Orange Cupcakes. The cake mix is a fairly standard mix, with a bit of good quality cocoa powder thrown in. On top of that you have [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=86</guid>
         <pubDate>Mon, 01 Feb 2010 22:34:31 +0000</pubDate>
         <content:encoded><![CDATA[<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4307577646/" title="White vanilla, red vanilla and Chocolate Orange by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2772/4307577646_5c3f0299eb.jpg" width="500" height="333" alt="White vanilla, red vanilla and Chocolate Orange"/></a></p>

<p>Another post, another chance to point to <a rel="nofollow" target="_blank" href="http://laythetable.com/cupcakes/chocolate-orange-cupcakes/">Lay the Table</a> and show off a different recipe than the one Becs used.  This time it&#8217;s for big fat nommery Chocolate Orange Cupcakes.</p>

<p>The cake mix is a fairly standard mix, with a bit of good quality cocoa powder thrown in.  On top of that you have a nice fruity orange sugar syrup, all topped off with some zesty orange frosting.<span id="more-86"></span></p>

<p>Takes a couple of hours all told, ideally with a day in the middle.  20 minutes cooking time for the cakes.</p>

<p>These ingredients make 12 normal sized cupcakes or 24 little ones.</p>

<h2>Ingredients</h2>

<h3>Zesty Orange Frosting</h3>

<ul>
<li>150g icing sugar</li>
<li>100g cream cheese (full fat!)</li>
<li>50g unsalted butter</li>
<li>The grated zest of two oranges.</li>
</ul>

<h3>Orange Sugar Syrup</h3>

<ul>
<li>The juice of one orange (about 5 tbsp)</li>
<li>75g caster sugar</li>
<li>1 tbsp Cointreau</li>
</ul>

<h3>Chocolate Cupcake base</h3>

<ul>
<li>100g unsalted butter</li>
<li>100g caster sugar</li>
<li>2 medium eggs</li>
<li>85g self raising flour</li>
<li>15g cocoa powder</li>
</ul>

<h2>Instructions</h2>

<h3>Zesty Orange Frosting</h3>

<ol>
<li><p>Cream the butter and sugar.</p></li>
<li><p>Add the cream cheese, and mix this in too.</p></li>
<li><p>Grate the zest of two oranges and, you guessed it, add this into the mix as well!</p>

<p>Don&#8217;t chuck the oranges though &#8211; you&#8217;ll need one of them for the syrup.</p></li>
</ol>

<h3>Orange Sugar Syrup</h3>

<ol>
<li><p>Juice one of the oranges you had left over from the frosting.</p></li>
<li><p>Bring the orange juice and sugar to the boil, stirring to dissolve the sugar.</p></li>
<li><p>Let the syrup cool, and then stir in the Cointreau (or other orange liqueur if you prefer).  </p>

<p>Yes, this means there will be a tiny bit of alcohol in your cakes.  If you&#8217;d prefer there not to be, just add another tablespoon of orange juice instead at this point.</p></li>
<li><p>Leave to infuse overnight if at all possible to let all the lovely flavours intermingle.  If you can&#8217;t wait, then start making the cupcakes now instead.</p></li>
</ol>

<h3>Chocolate Cupcake</h3>

<ol>
<li><p>Preheat the oven to 160ºC.</p></li>
<li><p>Cream the butter and sugar.</p></li>
<li><p>Lightly beat the eggs, and slowly add them to the mix &#8211; combine on a medium speed.</p></li>
<li><p>Once the sugar, butter and eggs are combined, mix in the flour and cocoa powder at a low speed.</p>

<p>That&#8217;s your cake mix &#8211; nice and simple.</p></li>
<li><p>Put your mix into your cupcake cases, and from there into the oven for 18-20 minutes.</p>

<p>I use a children&#8217;s plastic icing plunger to place my cake mix into cases.  I find this is much easier than using spoons, and quicker than using a proper icing bag (which is use for the proper icing).</p></li>
<li><p>Once the cakes have cooked, leave them to cool for ten minutes if you&#8217;re making normal cupcakes, or five minutes if you&#8217;re making mini ones.</p></li>
<li><p>Prick the top of the cupcakes a few times with something pointy like a cocktail stick, and using a pastry brush coat the tops with the sugar syrup.</p>

<p>Be careful not to splash syrup everywhere, but also remember that the syrup is fantastic and will keep the cakes lovely and moist and add flavour so don&#8217;t be stingy.  Don&#8217;t be worried if you have a load of syrup left though &#8211; that&#8217;s normal.</p></li>
<li><p>Once completely cooled, you can ice the cakes using your preferred method.</p></li>
<li><p>Finally, eat the damn cakes!</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Ridiculously Rich Chocolate Cake</title>
         <link>http://neilsnoms.com/ridiculously-rich-chocolate-cake/</link>
         <description>Last weekend was Becca&amp;#8217;s birthday, and since I&amp;#8217;d been promising her I&amp;#8217;d make her a birthday cake I ended up scouring the internet for a nommy sounding recipe. Somehow I managed to miss the fabulous sounding recipe that Becs recently posted on Lay the Table, and instead settled on one from the BBC Good Food [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=80</guid>
         <pubDate>Wed, 27 Jan 2010 20:44:47 +0000</pubDate>
         <content:encoded><![CDATA[<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4301361182/" title="More Chocolatey Chocolate Cake by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2789/4301361182_37b6ba2101.jpg" width="500" height="333" alt="More Chocolatey Chocolate Cake"/></a></p>

<p>Last weekend was Becca&#8217;s birthday, and since I&#8217;d been promising her I&#8217;d make her a birthday cake I ended up scouring the internet for a nommy sounding recipe.  Somehow I managed to miss the fabulous sounding recipe that Becs recently posted on <a rel="nofollow" target="_blank" href="http://laythetable.com/full-size-cake/extra-moist-chocolate-fudge-cake/">Lay the Table</a>, and instead settled on one from the <a rel="nofollow" target="_blank" href="http://www.bbcgoodfood.com/recipes/4689/chocolate-cake">BBC Good Food website</a>, even though if I&#8217;m honest it didn&#8217;t visually appeal to me too much.  As Becca said about the Good Food cake: &#8220;It looks like a f*cking breezeblock!&#8221;.</p>

<p>I&#8217;m ridiculously happy that I looked past that initial photo.  What I ended up with after I tweaked things a bit was frankly fantastic.  It&#8217;s ridiculously rich though, and definitely not something I could see myself making every week &#8211; it&#8217;s most certainly a treat cake.</p>

<p>Takes one hour and fifty minutes &#8211; twenty minutes preparation of the cake, one hour cooking, half an hour icing.<span id="more-80"></span></p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4296523098/" title="2.5Kg of Chocolate Birthday Cake Goodness by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4033/4296523098_73591404d6.jpg" width="500" height="333" alt="2.5Kg of Chocolate Birthday Cake Goodness"/></a></p>

<h2>Ingredients</h2>

<p>For the cake:</p>

<ul>
<li>250g self raising flour</li>
<li>250g soft brown sugar</li>
<li>50g cocoa</li>
<li>250g plain chocolate</li>
<li>250g butter</li>
<li>4 eggs</li>
<li>200ml water</li>
</ul>

<p>For the sauce and icing:</p>

<ul>
<li>150g plain chocolate</li>
<li>250g milk chocolate</li>
<li>300ml single cream</li>
<li>25g butter</li>
<li>700g icing sugar</li>
</ul>

<h2>Instructions</h2>

<h3>The Cake</h3>

<ol>
<li><p>Preheat the oven to 160ºC.</p></li>
<li><p>Mix the flour, sugar and cocoa in a bowl.</p></li>
<li><p>Melt the chocolate, butter and water together in a pan.</p></li>
<li><p>Allow to cool slightly, and beat the wet into the dry mixture along with the eggs.</p></li>
<li><p>Dollop your mixture into a cake tin and bake for one hour.</p></li>
</ol>

<h3>The Icing</h3>

<ol>
<li><p>Whilst the cake cools, it&#8217;s time to make the icing.</p>

<p>Melt the chocolate, butter and single cream in a pan, and mix until it becomes smooth and comes together.</p></li>
<li><p>Allow the sauce to cool for about 20 minutes.</p></li>
<li><p>Beat in about 250g of icing sugar.</p>

<p>At this point the sauce should be rich, thick and dark.</p></li>
<li><p>Slice the cake in half, and spread as much of the sauce as you want between the slices.  Put the top of the cake back onto the bottom.</p></li>
<li><p>Beat in the remaining icing sugar.</p>

<p>The sauce will now have become icing, will be a lot lighter in colour and will form peaks in your bowl.</p></li>
<li><p>Apply the icing to the cake.  Make it as messy as you want &#8211; there&#8217;s something magical about a fully iced cake covered in dozens of little peaks and troughs.</p></li>
<li><p>Allow the cake to set.  </p>

<p>Over the next couple of hours the icing will harden, allowing it to crunch when you bite into it.  The inside of the cake and the rest of the icing will remain wonderfully moist and rich.</p></li>
<li><p>Host a party, or take the cake into work.  This is one cake you certainly don&#8217;t want to keep to yourself.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Cherry and Sultana Flapjack</title>
         <link>http://neilsnoms.com/cherry-and-sultana-flapjack/</link>
         <description>I&amp;#8217;m a big fan of flapjacks &amp;#8211; they&amp;#8217;re sweet and oaty and fruity and yummy. Even better, they&amp;#8217;re gluten-free, so my coeliac friends can eat them too. Most of the time I make mine with cherries and sultanas, but it&amp;#8217;s just as easy to substitute in other ingredients. Takes 10 minutes to prepare, 20 minutes [&amp;#8230;]</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=25</guid>
         <pubDate>Sun, 17 Jan 2010 19:23:07 +0000</pubDate>
         <content:encoded><![CDATA[<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4282608802/" title="Cherry and Sultana Flapjack by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2713/4282608802_34bfb3319b.jpg" width="500" height="333" alt="Cherry and Sultana Flapjack"/></a></p>

<p>I&#8217;m a big fan of flapjacks &#8211; they&#8217;re sweet and oaty and fruity and yummy.  Even better, they&#8217;re gluten-free, so my coeliac friends can eat them too.</p>

<p>Most of the time I make mine with cherries and sultanas, but it&#8217;s just as easy to substitute in other ingredients.</p>

<p>Takes 10 minutes to prepare, 20 minutes to cook.<span id="more-25"></span></p>

<h2>Ingredients</h2>

<ul>
<li>150g unsalted butter</li>
<li>200g light brown sugar</li>
<li>4 tbsp golden syrup</li>
<li>350g porridge oats</li>
<li>150g sultanas</li>
<li>100g glacé cherries</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Preheat oven to 180ºc</p></li>
<li><p>Melt butter, sugar and golden syrup in a pan.</p></li>
<li><p>Whilst the meltening is happening, chop up your cherries.  I tend to take them down to quarters.</p></li>
<li><p>Once everything&#8217;s melted remove from the heat, and mix in the oats, cherries and sultanas.</p></li>
<li><p>Press into a tin, and cook for 20 minutes in the oven.</p></li>
<li><p>Once it&#8217;s out of the oven, let the flapjack cool for a few minutes before scoring it deeply into portion sized pieces.</p></li>
<li><p>Once cold, turn out the flapjack and break into pieces.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>Robocop: Directive 3 Baby Food</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/Zc48fbwO4Iw/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/robocop_baby_food_lead.jpg' alt=''&gt;&lt;/p&gt;Yup, it&amp;#8217;s unboxing time! Today I received a t-shirt I&amp;#8217;ve been looking forward to getting for quite some time &amp;#8211; Robocop: Directive 3 Baby Food, from Dark Bunny Tees. I ordered this way back at the end of November last year, as a pre-order, with the expectation that it would be printed some time in [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/robocop_baby_food_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=79</guid>
         <pubDate>Wed, 13 Jan 2010 22:18:38 +0000</pubDate>
         <content:encoded><![CDATA[<p>Yup, it&#8217;s unboxing time!  Today I received a t-shirt I&#8217;ve been looking forward to getting for quite some time &#8211; <a rel="nofollow" target="_blank" href="http://www.darkbunnytees.com/movietshirts/tshirts/robocopmovietshirt.html">Robocop: Directive 3 Baby Food</a>, from <a rel="nofollow" target="_blank" href="http://www.darkbunnytees.com/">Dark Bunny Tees</a>.  I ordered this way back at the end of November last year, as a pre-order, with the expectation that it would be printed some time in January &#8211; February.  Why did I pre-order? Because I have a bit of a thing for ED-209, because I really liked the idea behind the design, and because Alex Chenery seems like a really rather interesting chap.</p>

<p>Anyway, enough of the pre-amble, lets see why I decided to do an unboxing of this t-shirt (all images link to larger versions on flickr)!</p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4272673932/" title="A black package arrived by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4021/4272673932_c79007040b.jpg" width="500" height="333" alt="A black package arrived"/></a></p>

<p>The t-shirt arrived in a nice simple, black posting bag, but it was immediately obvious to me that it didn&#8217;t just contain your average, limply inserted t-shirt.  Oh no, it was obvious there was something more in here.  Some sort of box.</p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4271934731/" title="Inside was a bubble-wrapped box by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2759/4271934731_3a257f62a3.jpg" width="500" height="333" alt="Inside was a bubble-wrapped box"/></a></p>

<p>A box covered by nothing less than the highest grade of bubblewrap known to man. (Okay, I might be overegging the pudding a little here, but it was wrapped in bubblewrap.  You wouldn&#8217;t want the box getting damaged in transit now, would you?)</p>

<p><span class="action_shot"><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4272678610/" title="It's a VHS tape box! by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2787/4272678610_f4a4f2500d_m.jpg" width="160" height="240" alt="It's a VHS tape box!"/></a> <a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4272680758/" title="With custom artwork front and back by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4016/4272680758_184ff6b213_m.jpg" width="160" height="240" alt="With custom artwork front and back"/></a></span></p>

<p>Of course, being an inquisitive chap I ripped the bubblewrap off the box and discovered a wonderful piece of custom artwork on an old-school VHS tape case.  Frankly, this is a level of commitment I have never before seen in any t-shirt that I&#8217;ve bought.  Of course, I&#8217;ve never bought anything that was in a limited edition of 50 worldwide before either, but that&#8217;s beside the point.  Going to the trouble of creating a second piece of artwork to contain the t-shirt that I was actually purchasing is above and beyond the call of duty.</p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4272684134/" title="Suitable only for persons of a really cool nature by Neil Crosby, on Flickr"><img src="http://farm3.static.flickr.com/2683/4272684134_43fb2ea720.jpg" width="500" height="333" alt="Suitable only for persons of a really cool nature"/></a></p>

<p>The box has a whole load of wonderful little touches, such as the rating certificate of &#8220;DB: Suitable only for persons of a really cool nature and an unatural (sic) love of film&#8221;, and the statement on the front that reads &#8220;&#8230;Life is a war, be a hero.  Be a hero in an awesome t-shirt&#8230;&#8221;.  This packaging makes me happy.</p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4271944361/" title="It's got a t-shirt inside it! by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4024/4271944361_b42e4ce1a5.jpg" width="500" height="333" alt="It's got a t-shirt inside it!"/></a></p>

<p>The t-shirt itself is also pretty damn fab.  The weight is great, and the feel of the cloth is smooth to the touch.  It&#8217;s a pity that the tiny text on the design is almost impossible to read, but that&#8217;s a very minor criticism.  Other than that the design has transferred fantastically from Photoshop to t-shirt.</p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4271947161/" title="The t-shirt itself by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4025/4271947161_526fe1fff3.jpg" width="500" height="333" alt="The t-shirt itself"/></a></p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4271950693/" title="Tag - Side 1 by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4015/4271950693_42c9aea454_m.jpg" width="240" height="160" alt="Tag - Side 1"/></a> <a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4271954209/" title="Tag - Side 2 by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4011/4271954209_b8c4e80299_m.jpg" width="240" height="160" alt="Tag - Side 2"/></a></p>

<p>So, congratulations Alex.  You&#8217;ve successfully made me happier opening this t-shirt than anyone has ever done before.  Good job.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.darkbunnytees.com/movietshirts/tshirts/robocopmovietshirt.html">Robocop: Directive 3 Baby Food</a>&#8221; is part of a limited run of 50 t-shirts from <a rel="nofollow" target="_blank" href="http://www.darkbunnytees.com/">Dark Bunny Tees</a>, and is apparently still available for £25 from the website.  You&#8217;d better get your skates on if you&#8217;re a fan though &#8211; I wouldn&#8217;t bet on it being around for long.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/Zc48fbwO4Iw" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Bacon and Courgette Tagliatelle</title>
         <link>http://neilsnoms.com/bacon-and-courgette-tagliatelle/</link>
         <description>Bacon, Courgette, Tagliatelli.  What could go wrong with this fantastically simple dish?</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=64</guid>
         <pubDate>Mon, 11 Jan 2010 21:02:56 +0000</pubDate>
         <content:encoded><![CDATA[<p>This is one of my favourite simple meals that I love to cook for myself and Becca.  </p>

<p>It takes about 15 minutes to cook and tastes fantastic.  Serves 2.<span id="more-64"></span></p>

<p><a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4266432495/" title="Bacon and Courgette Pasta by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4017/4266432495_08964c75da.jpg" width="500" height="375" alt="Bacon and Courgette Pasta"/></a></p>

<h2>Ingredients</h2>

<ul>
<li>4 &#8211; 5 rashers of bacon (we use Sainsbury&#8217;s Be Good to Yourself Bacon Medallions for this)</li>
<li>1 courgette</li>
<li>Garlic puree</li>
<li>150g &#8220;light&#8221; creme fraiche (we used TESCO&#8217;s Healthy Living Creme Fraiche today)</li>
<li>4-5 balls of Tagliatelle</li>
<li>Olive oil</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Slice the courgette in half lengthways, and then slice each half finely.  Add it to a large frying pan with a little bit of olive oil and a good squeeze of garlic puree.  Mix, and fry on a medium heat for a few minutes until soft.</p></li>
<li><p>Whilst the courgette is softening, remove the fat from your bacon and slice&#8217;n&#8217;dice into small pieces.  Once the courgette is soft add the bacon to the pan.  I tend to turn the heat up a bit now to brown the courgette a bit.</p>

<p>If you want, you can add even more garlic puree at this point.  Don&#8217;t forget to give everything a good mix.</p></li>
<li><p>Now that your bacon and courgette is frying, put your tagliatelle into a saucepan and start cooking it.  We tend to put four to five balls in.  This will be cooked in about 7 minutes.</p></li>
<li><p>Once the bacon is cooked, it&#8217;s time to add your creme fraiche.  Just dollop it into the frying pan and mix.  It&#8217;ll start to turn a creamy yellow colour as it pulls in the lovely juices from your bacon and courgette.</p></li>
<li><p>Give it a couple of minutes, then drain your tagliatelle and add it too to the frying pan.  Mix everything together and serve immediately.  Grate some parmesan on top if you&#8217;re feeling that way inclined.</p></li>
</ol>

<p>Nommy.</p>]]></content:encoded>
      </item>
      <item>
         <title>ED-209</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/Nd4N3PHHj5c/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/ed209_lead.jpg' alt=''&gt;&lt;/p&gt;It&amp;#8217;s been a while since I&amp;#8217;ve posted, hasn&amp;#8217;t it? I&amp;#8217;m afraid that most of that time has been spent taking photographs of ED-209 and starting my new job at The Big British Castle. Nonetheless, I&amp;#8217;m still alive. It&amp;#8217;s because of my love of ED-209, that loveable rogue from the Robocop films, that Becca bought me [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/ed209_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=71</guid>
         <pubDate>Mon, 04 Jan 2010 22:38:22 +0000</pubDate>
         <content:encoded><![CDATA[<p>It&#8217;s been a while since I&#8217;ve posted, hasn&#8217;t it?  I&#8217;m afraid that most of that time has been spent taking <a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/sets/72157621804112466/">photographs of ED-209</a> and starting my <a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2009/11/heading-off-to-the-big-british-castle/">new job at The Big British Castle</a>. Nonetheless, I&#8217;m still alive.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/4246141184/" title="ED 209 - Military System Project by Neil Crosby, on Flickr"><img src="http://farm5.static.flickr.com/4065/4246141184_e309a4dfc9_m.jpg" width="240" height="160" alt="ED 209 - Military System Project"/></a></p>

<p>It&#8217;s because of my love of ED-209, that loveable rogue from the Robocop films, that Becca bought me this wonderful <a rel="nofollow" target="_blank" href="http://www.lastexittonowhere.com/shop/product/ed-209/">t-shirt</a> for Christmas.  It&#8217;s one I&#8217;ve had my eye on for some time, since seeing it on <a rel="nofollow" target="_blank" href="http://www.lastexittonowhere.com/">Last Exit to Nowhere</a> last year.  Last Exit are one of those places that I end up going and looking at quite a lot, because they have rather nice movie based imagery that isn&#8217;t just a straight lift and shift from the movies in question.</p>

<p>This, however, is the first t-shirt that I&#8217;ve ended up getting from them. Normally I wouldn&#8217;t go for t-shirts that are printed on a white or creamy fabric, but since Becca bought this for me I didn&#8217;t have much choice. Frankly though, in the flesh I rather like this one.  As a larger chap, I tend to think they help to make me look even bigger than I am, but happily this doesn&#8217;t seem to be the case with this one.  This despite the fact that when I unwrapped it on Christmas morning I was convince that I&#8217;d been sent a t-shirt one size larger than I needed!</p>

<p>As it turns out, although the t-shirt was the same size as everything else I own, the neck was considerably larger and the shoulders a bit wider.  A bit weird, but nothing that was off-putting to me once I put the t-shirt on.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.lastexittonowhere.com/shop/product/ed-209/">ED-209</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.lastexittonowhere.com/">Last Exit to Nowhere</a> for £18 and is printed on an &#8220;ice grey&#8221; shirt of no specified brand.   And yes, I would buy that for a dollar.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/Nd4N3PHHj5c" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Strained Mojito</title>
         <link>http://neilsnoms.com/strained-mojito/</link>
         <description>It might be slightly unconventional, but this is how I like to make my mojitos.</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=7</guid>
         <pubDate>Mon, 21 Dec 2009 21:12:16 +0000</pubDate>
         <content:encoded><![CDATA[<p>Most mojito recipes that I&#8217;ve come across are prepared in the glass, and then have crushed ice and soda water added to them.  This leaves a whole bunch of muddled mint and lime in the bottom of the glass (referred to by a couple of people I&#8217;ve met as &#8220;foliage&#8221;), and it&#8217;s not something I&#8217;m massively enamoured with.  Instead, I like to strain my mojito over a full glass of crushed ice, allowing its wonderful colours and flavours to seep through the entire thing.</p>

<p>Takes five minutes to prepare, then take as long as you want to drink it.<span id="more-7"></span></p>

<h2>Ingredients</h2>

<ul>
<li>2 shots of rum</li>
<li>Half a lime</li>
<li>2 teaspoons of granulated sugar</li>
<li>10 mint leaves</li>
<li>A whole bunch of crushed ice</li>
<li>Soda water if you really want it</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Spoon two tablespoons of granulated sugar into your cocktail shaker.  Squeeze half a lime onto this, making sure to get as much juice out as you can.  Drop the leftover husk of the lime in too.  Now throw 10 or so mint leaves in as well (take them off the stalks).</p></li>
<li><p>Here&#8217;s where the magic happens &#8211; muddling the sugar, lime and mint together.  If you&#8217;ve already got a muddler then great, use that.  Otherwise, do as I do and use a simple wooden rolling pin.</p>

<p>Push down into your mixture with your muddler, rotating as you do.  This crushes the mint into your sugary limey mixture, releasing its essential oils and wonderful flavours as you do so.  Remember how mint leaves don&#8217;t really smell of anything until you rub them together in your fingers? That&#8217;s what is happening here.</p>

<p>Give it a good bit of pressure, and you&#8217;ll only need to muddle for a few seconds.   We&#8217;ll now leave this to sit for a minute or two whilst we prepare the ice.</p></li>
<li><p>Fill the glass you&#8217;ll be making the mojito in twice with ice (I use a chunky half-pint glass), and empty this out into a tea towel.  Gather the tea towel up to make sure none of the ice can escape, and then give it a few thwacks with a mallet.  We use a cheap wooden one &#8211; it works a lot better than using the rolling pin again.  </p>

<p>Once the ice is sufficiently pulverised, add it to your glass.  You&#8217;ll find that what once filled the glass twice should now pretty happily fit in just the once.</p>

<p>The reason we crush the ice like this is to increase the available surface area to cool the liquid in the drink.  If we do a good job of crushing it, we&#8217;ll end up with things getting so cold that the outside of the glass frosts over.  Lovely.</p>

<p>As you can see, these mojitos use a lot of ice.  For this reason we tend to keep bags of the stuff in the freezer, just for cocktails.</p></li>
<li><p>We&#8217;re back to the cocktail shaker now, and we&#8217;re finally getting to the alcohol.</p>

<p>Add a couple of ice cubes to the shaker, pour in two shots of your favourite white rum, put the top back on and shake roughly.  Once you&#8217;ve finished shaking and everything&#8217;s mixed together nicely, strain into your ice-filled glass.</p>

<p>Your ice will turn green as you pour over it, and you&#8217;ll get some tiny pieces of mint seeping through your drink.</p></li>
<li><p>At this point, I&#8217;d be done.  I don&#8217;t think that these mojitos need anything adding to them to water them down, but depending on how you like yours you might want to.  So, if you want to, add some soda water now.</p></li>
<li><p>Finally, add a straw and some mint to garnish, and sip happily.</p></li>
</ol>]]></content:encoded>
      </item>
      <item>
         <title>The Robotanist</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/xjUwli3_FG0/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/robotanist_lead.jpg' alt=''&gt;&lt;/p&gt;It&amp;#8217;s been a while since I bought this t-shirt, but I think it still bears talking about as it features two of my favourite things — robots and sentient plants. It&amp;#8217;s unclear who has the upper hand in this shirt. Maybe the robot is just a gardener trying to trim back his garden. Maybe he [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/robotanist_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=15</guid>
         <pubDate>Mon, 02 Feb 2009 15:15:00 +0000</pubDate>
         <content:encoded><![CDATA[<p>It&#8217;s been a while since I bought this t-shirt, but I think it still bears talking about as it features two of my favourite things — robots and sentient plants.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2528336052/" title="The plants attack by thevoicewithin, on Flickr"><img src="http://farm4.static.flickr.com/3050/2528336052_b6ee5d877c_m.jpg" width="240" height="180" alt="The plants attack"></a></p>

<p>It&#8217;s unclear who has the upper hand in this shirt.  Maybe the robot is just a gardener trying to trim back his garden.  Maybe he was just taking a stroll when the plants attacked him.  Maybe he&#8217;s some juvenile delinquent robot who just likes setting fire to things.  Whatever the case, it makes for a nice t-shirt.</p>

<p>The thing I love most about this t-shirt though is the incredibly fine printing.  It&#8217;s not something that came across in the photos on Uneetee&#8217;s site, but the printing really is fantastic.  The design is made up of hundreds of individual strokes, resulting in an image that feels both old and new at the same time.  The fact that the design isn&#8217;t made up of large blocks of colour also means that it breathes nicely during the summer.  Not much of a problem this week, with all the snow that&#8217;s falling, but it&#8217;s good to know nonetheless.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?u=263161&amp;b=107913&amp;m=12558&amp;afftrack=&amp;urllink=www%2Euneetee%2Ecom%2Fcategory%2FproductInfo%2Easp%3Fidx%3D156">The Robotanist</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?u=263161&amp;b=107913&amp;m=12558&amp;afftrack=&amp;urllink=www%2Euneetee%2Ecom%2F">Uneetee</a> for $18.99 and is printed on a dark green American Apparel shirt.  It&#8217;s sold out if you&#8217;re an extra large man like me, but there are still a few available for everyone else.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/xjUwli3_FG0" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>I’m Magic!</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/u3bnK6e8N8k/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/im_magic_lead.jpg' alt=''&gt;&lt;/p&gt;Who doesn&amp;#8217;t like Unicorns? I know Obama does, but that&amp;#8217;s another t-shirt. I got &amp;#8220;I&amp;#8217;m Magic!&amp;#8221; from my fiancée Becca this christmas, after Brad told me about it on twitter. The t-shirt comes from Tee and Toast, a wee little company from Northern Ireland. They concentrate on cute, childlike imagery, and there are quite a [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/im_magic_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=44</guid>
         <pubDate>Wed, 21 Jan 2009 21:15:32 +0000</pubDate>
         <content:encoded><![CDATA[<p>Who doesn&#8217;t like Unicorns?  I know Obama does, but that&#8217;s <a rel="nofollow" target="_blank" href="http://chrisbishop.com/obama/">another t-shirt</a>.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/3198595009/" title="I'm Magic! by thevoicewithin, on Flickr"><img src="http://farm4.static.flickr.com/3359/3198595009_59dd3b2153_m.jpg" width="240" height="180" alt="I'm Magic!"/></a></p>

<p>I got &#8220;I&#8217;m Magic!&#8221; from my fiancée <a rel="nofollow" target="_blank" href="http://doesbeccalove.com">Becca</a> this christmas, after <a rel="nofollow" target="_blank" href="http://intranation.com">Brad</a> told me about it on twitter.</p>

<p>The t-shirt comes from <a rel="nofollow" target="_blank" href="http://www.teeandtoast.com/">Tee and Toast</a>, a wee little company from Northern Ireland.  They concentrate on cute, childlike imagery, and there are quite a few things on their site that I&#8217;d very happily pick up for myself.  They&#8217;re a really friendly company as well, as Becca and I found out when she had to request a replacement for the t-shirt I&#8217;d opened on Christmas morning.</p>

<p>I wear an extra-large t-shirt, you see, but what I opened at Christmas was a large.  I was quite disappointed, as I knew I&#8217;d never fit into a mere large t-shirt.  So, thinking Becca had ordered a large in error, I asked her to email Tee and Toast and see if they&#8217;d be happy to replace it with an extra-large for us.  </p>

<p>They emailed back pretty quickly and told us that Becca had ordered an extra-large, but that they must have got confused making up the shirts in the Christmas rush.  No worries though, if we sent back the t-shirt they&#8217;d send us out another in the correct size post-haste.  So we did, and they did (and they even sent us a pound coin back with the new t-shirt to cover our return postage).</p>

<p>Throughout the whole process I loved the customer service from Tee and Toast.  They were lovely and friendly, and did everything they could to make sure I got the t-shirt back for last week&#8217;s <a rel="nofollow" target="_blank" href="http://upcoming.yahoo.com/event/1457262/">Pub Standards</a> (it came the day before, and I was very happy).  I&#8217;d have no hesitation buying from them again, and in fact I have — I bought a Mr T &#8220;I pity the fool who don&#8217;t drink tea&#8221; hoodie for Becca for her birthday today.</p>

<p>The t-shirt itself is a simple two colour heat transfer print of a lovely unicorn that knows it&#8217;s magic, and isn&#8217;t afraid to tell you.  The only thing I wish is that it was available on a bright pink t-shirt for guys as well as girls.  Oh well, you can&#8217;t have everything, can you?</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://shop.teeandtoast.com/index.php?_a=viewProd&amp;productId=205">I&#8217;m Magic!</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.teeandtoast.com/">Tee and Toast</a> for £20, but shipping is free within the UK.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/u3bnK6e8N8k" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>We Built This City…</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/q8aBY4W9WK8/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/we_built_this_city_lead.jpg' alt=''&gt;&lt;/p&gt;When we built this city, we didn&amp;#8217;t go down the traditional route of bricks and mortar. We didn&amp;#8217;t go for the currently in vogue technique of Rock and Roll. We didn&amp;#8217;t even use jam and scones. Instead, we got out our old Lego bricks and started building that way. Sure, it took a long time [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/we_built_this_city_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=31</guid>
         <pubDate>Fri, 03 Oct 2008 07:00:11 +0000</pubDate>
         <content:encoded><![CDATA[<p>When we built this city, we didn&#8217;t go down the traditional route of bricks and mortar.  We didn&#8217;t go for the currently in vogue technique of Rock and Roll.  We didn&#8217;t even use jam and scones.  Instead, we got out our old Lego bricks and started building that way.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2516477901/" title="We built this city by thevoicewithin, on Flickr"><img src="http://farm3.static.flickr.com/2110/2516477901_6641346c4b_m.jpg" width="240" height="180" alt="We built this city"/></a></p>

<p>Sure, it took a long time to build the city, but since it was funded by the government they didn&#8217;t seem to mind that we we over budget and over schedule &#8211; what we came up with in the end was pretty, if a little bit uncomfortable to walk around on in bare feet.</p>

<p>I&#8217;m a big fan of Lego, so any shirt showing a minifig is immediately going to score extra points in my book.  Add to that the use of Starship&#8217;s &#8220;We Built This City&#8221; and we have a winner.  </p>

<p>The shirt isn&#8217;t over the top, using a simple single colour print.  The print colour is Lego minifig yellow, and the typeface is the classic Lego font.  Add to that the fact that the minifigs are the modern era &#8220;simple&#8221; minifgs that I grew up with and this shirt quickly became a must have for me.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.tkqlhce.com/click-5376206-10406616?url=http%3A%2F%2Fwww.bustedtees.com%2Fwebuiltthiscity">We Built This City</a>&#8221; is printed on a red American Apparel t-shirt and is sold by <a rel="nofollow" target="_blank" href="http://www.tkqlhce.com/click-5376206-10406623?url=http%3A%2F%2Fwww.bustedtees.com%2F">Busted Tees</a> for $18.99.  It comes in both male and female sizes.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/q8aBY4W9WK8" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Brains!</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/-QUrbsi5DDk/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/brains_lead.jpg' alt=''&gt;&lt;/p&gt;Frankly, I&amp;#8217;m an idiot. When I bought this t-shirt, I bought it because I got a feeling of &amp;#8220;gee whiz, it&amp;#8217;s the scarecrow from The Wizard of Oz but he&amp;#8217;s a zombie now!&amp;#8221;. It wasn&amp;#8217;t until a couple of weeks later that I realised &amp;#8220;oh&amp;#8230; in the books he wanted brains, didn&amp;#8217;t he? Oh, that&amp;#8217;s [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/brains_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=16</guid>
         <pubDate>Sun, 21 Sep 2008 18:28:43 +0000</pubDate>
         <content:encoded><![CDATA[<p>Frankly, I&#8217;m an idiot.  When I bought this t-shirt, I bought it because I got a feeling of &#8220;gee whiz, it&#8217;s the scarecrow from The Wizard of Oz but he&#8217;s a zombie now!&#8221;.  It wasn&#8217;t until a couple of weeks later that I realised &#8220;oh&#8230; in the books he wanted brains, didn&#8217;t he?  Oh, that&#8217;s kind of funny&#8221;.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2516378571/" title="Braaaaaaains by thevoicewithin, on Flickr"><img src="http://farm3.static.flickr.com/2194/2516378571_373cb53f7c_m.jpg" width="240" height="180" alt="Braaaaaaains"/></a></p>

<p>So yeah, like I said &#8211; idiot.</p>

<p>The thing I like most about this shirt, and which isn&#8217;t obvious from the photos on Busted Tee&#8217;s site, is the fine detail of the scarecrow.  If you look closely at the image above you&#8217;ll see very thin lines of dark brown around the bright red of zombie-scarecrow&#8217;s eyes, and light green detailing around the tufts of corn protruding from his clothes.  It&#8217;s scratchy, but it&#8217;s there and I kind of like it.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.kqzyfj.com/click-5376206-10499752?url=http%3A%2F%2Fwww.bustedtees.com%2Fbrains%2Ffemale&amp;cjsku=396f">Brains!</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.tkqlhce.com/click-5376206-10406623?url=http%3A%2F%2Fwww.bustedtees.com%2F">Busted Tees</a> for $13.99 in both men&#8217;s and women&#8217;s sizes.  It&#8217;s printed on a bright green American Apparel t-shirt and it wants to eat your brains.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/-QUrbsi5DDk" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Beware of Beard</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/7Gmk45Rn2D0/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/beware_of_beard_lead.jpg' alt=''&gt;&lt;/p&gt;I bought this shirt a few months ago now, when I was in the full flow of not shaving for Bearduary. The world was good, my life was happy, but my beard was starting to take on a life of its own &amp;#8211; it had to be stopped! &amp;#8220;Beware of Beard&amp;#8221; is a full frontal [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/beware_of_beard_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=23</guid>
         <pubDate>Sun, 15 Jun 2008 08:59:56 +0000</pubDate>
         <content:encoded><![CDATA[<p>I bought this shirt a few months ago now, when I was in the full flow of not shaving for <a rel="nofollow" target="_blank" href="http://www.bearduary.com/">Bearduary</a>.  The world was good, my life was happy, but my beard was starting to take on <a rel="nofollow" target="_blank" href="http://buttersafe.com/2008/03/06/the-massive-beard/">a life of its own</a> &#8211; it had to be stopped!</p>

<p><a rel="nofollow" class='action_shot' target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2580152510/" title="Beware of Beard Triptych by thevoicewithin, on Flickr"><img src="http://farm4.static.flickr.com/3095/2580152510_8df8d09bdd.jpg" width="222" height="500" alt="Beware of Beard Triptych"/></a>&#8220;<a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/product/beware-of-beard">Beware of Beard</a>&#8221; is a full frontal print.  It&#8217;s <em>big</em>, and takes up the entire front of the t-shirt.  But it&#8217;s cool.  Raise it up over the lower half of your head and you can pull faces, and people will never know whether you&#8217;re sporting hair or not.  This t-shirt tells the world that beards aren&#8217;t to be trusted, and if you see one you should run away, fast.  Either that or stroke it.  I&#8217;m not sure which.</p>

<p>This is the first shirt that I&#8217;ve bought from <a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/">turn nocturnal</a>, and it&#8217;s a good&#8217;un.  The print has a high quality rubbery feel to it, and is printed on a Gildan Heavy Cotton t-shirt.  My only (very minor) gripe is the postcard-sized Turn Nocturnal logo on the back of the shirt, but even that&#8217;s not that obtrusive.</p>

<p>Given the fact that I love this shirt, it&#8217;s a pity that Turn Nocturnal don&#8217;t have anything else in their selection that really inspires me.  I&#8217;m sure a lot of people would love <a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/product/punctuation-foil">Puctuation</a> and <a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/product/sans-serif-black">sans-serif</a>, but they just don&#8217;t do it for me.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/product/beware-of-beard">Beware of Beard</a>&#8221; is currently available from <a rel="nofollow" target="_blank" href="http://www.turnnocturnal.com/">Turn Nocturnal</a> for $10 and it&#8217;s printed on a dark red Gildan Heavy Cotton shirt.  Unfortunately only small sizes are still available, but you could always ask them to reprint &#8211; it couldn&#8217;t hurt.  Yarr.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/7Gmk45Rn2D0" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Noodle Surprise</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/oiQNMAH8YAQ/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/noodle_surprise_lead.jpg' alt=''&gt;&lt;/p&gt;This shirt is perfect for me. For those of you who don&amp;#8217;t know, I&amp;#8217;m missing the top third of the ring finger on my left hand. Of course, no-one ever notices, so I end up showing them and telling the the story about how I lost it. In the real world it happened in a [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/noodle_surprise_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=22</guid>
         <pubDate>Tue, 20 May 2008 20:46:04 +0000</pubDate>
         <content:encoded><![CDATA[<p>This shirt is perfect for me. For those of you who don&#8217;t know, I&#8217;m missing the top third of the ring finger on my left hand. Of course, no-one ever notices, so I end up showing them and telling the the story about how I lost it. In the real world it happened in a pork pie factory rather than a noodle sweatshop, but it&#8217;s the missing finger that&#8217;s important, not how it was lost.</p>

<p><a rel="nofollow" class="action_shot" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2509681316/" title="Noodle Surprise by thevoicewithin, on Flickr"><img src="http://farm3.static.flickr.com/2097/2509681316_dfabf0fa97_m.jpg" width="240" height="180" alt="Noodle Surprise"/></a>Of course, this shirt isn&#8217;t just good if you&#8217;ve lost a finger yourself.  Maybe you know someone who has, or maybe you just like eating human fingers.  Whatever your reason, this cheeky little print is sure to brighten your day.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.splittheatom.com/product/item15/index.asp">Noodle Surprise</a>&#8221; is the first shirt I&#8217;ve bought from <a rel="nofollow" target="_blank" href="http://www.splittheatom.com/">Split the Atom</a> and I&#8217;ve got to say I&#8217;m impressed.  I ordered it in the wee small hours of Sunday morning and by the time I got home from work on Tuesday it was there, sitting on my front mat waiting for me.  They also made me smile by including a <a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2509701798/">sticker</a> in the package to go onto <a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2508870897/">my laptop</a>.  Sure, it&#8217;s a little big to be able to go on in one go, but I can cut it up a bit and fit it in somewhere.  It makes me happy when something a little extra arrives in the package with my shirt.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.splittheatom.com/product/item15/index.asp">Noodle Surprise</a>&#8221; is printed on an orange American Apparel shirt, and is available from <a rel="nofollow" target="_blank" href="http://www.splittheatom.com/">Split the Atom</a> for £15.99.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/oiQNMAH8YAQ" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Control?  Escape!</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/lyaQDI0MmD4/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/ctrl_escape_lead.jpg' alt=''&gt;&lt;/p&gt;Since it&amp;#8217;s GTA IV week, what could be better than a good old geek inspired cops &amp;#8216;n&amp;#8217; robbers based t-shirt? Not many things, that&amp;#8217;s what. The t-shirt itself is pretty simple. A CTRL key dressed like a policeman is chasing after an ESC key. Obviously, the ESC key tried to fight the law, but it [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/ctrl_escape_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=12</guid>
         <pubDate>Mon, 28 Apr 2008 13:40:45 +0000</pubDate>
         <content:encoded><![CDATA[<p>Since it&#8217;s GTA IV week, what could be better than a good old geek inspired cops &#8216;n&#8217; robbers based t-shirt?  Not many things, that&#8217;s what.</p>

<p><a rel="nofollow" class='action_shot' target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2449193794/" title="Control?  Escape! by thevoicewithin, on Flickr"><img src="http://farm4.static.flickr.com/3218/2449193794_d5bfd5888f_m.jpg" width="240" height="180" alt="Control?  Escape!"/></a>The t-shirt itself is pretty simple.  A CTRL key dressed like a policeman is chasing after an ESC key.  Obviously, the ESC key tried to fight the law, but it looks as though the law is going to win.  C&#8217;est la vie.</p>

<p>Maybe things aren&#8217;t as simple as that though.  Whilst the CTRL is definitely a cop, the ESC could just be a normal person &#8211; he isn&#8217;t wearing the stereotypical striped convict&#8217;s outfit so beloved of the 1920s.  So, maybe the t-shirt is actually an allegory of the control the state has over our lives and that the common man must always run to stay alive.</p>

<p>Or, maybe it&#8217;s just a cute t-shirt.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?u=263161&amp;b=80042&amp;m=12558&amp;afftrack=&amp;urllink=www%2Euneetee%2Ecom%2Fcategory%2FproductInfo%2Easp%3Fidx%3D137">Fugitive</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?u=263161&amp;b=80042&amp;m=12558&amp;afftrack=&amp;urllink=www%2Euneetee%2Ecom">uneetee</a> for $17.99 and is printed on a asphalt American Apparel shirt.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/lyaQDI0MmD4" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
      <item>
         <title>Mr File Attachment Got Dumped</title>
         <link>http://feedproxy.google.com/~r/IWearCotton/~3/91EsNZTDgJY/</link>
         <description>&lt;p&gt;&lt;img width='500' src='http://iwearcotton.com/images/mr_file_attachment_got_dumped_lead.jpg' alt=''&gt;&lt;/p&gt;This file attachment in a OS X style trash bin was just so darned cute, I had to have him. Files have feelings too, you know. Unlike the actual OS X trash can though, this bin is for recyclables. You see? As well as wearing a groovy t-shirt with a very cute piece of paper [&amp;#8230;]&lt;p class='img_sec'&gt;&lt;img width='293' src='http://iwearcotton.com/images/mr_file_attachment_got_dumped_secondary.jpg' alt=''&gt;&lt;/p&gt;</description>
         <guid isPermaLink="false">http://iwearcotton.com/?p=11</guid>
         <pubDate>Mon, 14 Apr 2008 11:45:36 +0000</pubDate>
         <content:encoded><![CDATA[<p>This file attachment in a OS X style trash bin was just so darned cute, I had to have him.  Files have feelings too, you know.</p>

<p><a rel="nofollow" class='action_shot' target="_blank" href="http://www.flickr.com/photos/thevoicewithin/2412614209/" title="Mr File Attachment got Dumped by thevoicewithin, on Flickr"><img src="http://farm3.static.flickr.com/2208/2412614209_0c492a827e_m.jpg" width="240" height="180" alt="Mr File Attachment got Dumped"/></a>Unlike the actual OS X trash can though, this bin is for recyclables.  You see?  As well as wearing a groovy t-shirt with a very cute piece of paper on it, I&#8217;m also making a social statement &#8211; recycling is good.  Of course, the little <a rel="nofollow" target="_blank" href="http://en.wikipedia.org/wiki/TPS_report">TPS report</a> dude isn&#8217;t going to be too happy, being pummelled down into pulp and all, but what can he do about it?  Anyway, he&#8217;ll probably get turned into something far cooler, like a <a rel="nofollow" target="_blank" href="http://en.wikipedia.org/wiki/Wonderbra#Worldwide_reintroduction.2C_1991_to_1994">wonderbra advert from the 90s</a> that causes people to crash their cars.  Or maybe a <a rel="nofollow" target="_blank" href="http://iwearcotton.com/2008/04/11/the-mondays/">post-it note</a>.</p>

<p>Whatever happens to him though, I&#8217;m sure he&#8217;ll be happy that you chose to buy a t-shirt that immortalised him.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?u=263161&amp;b=80042&amp;m=12558&amp;afftrack=&amp;urllink=www%2Euneetee%2Ecom%2Fcategory%2FproductInfo%2Easp%3Fidx%3D118">Mr File Attachment got Dumped</a>&#8221; is available from <a rel="nofollow" target="_blank" href="http://www.shareasale.com/r.cfm?B=107911&amp;U=263161&amp;M=12558">uneetee</a> for $17.99 and is printed on an American Apparel t-shirt.</p>
<img src="http://feeds.feedburner.com/~r/IWearCotton/~4/91EsNZTDgJY" height="1" width="1" alt=""/>]]></content:encoded>
      </item>
   </channel>
</rss>
<!-- fe7.yql.bf1.yahoo.com compressed/chunked Thu Oct  1 23:04:54 UTC 2015 -->
