<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.neilcrosby.com/~d/styles/itemcontent.css"?><rss 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" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
   <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>Sun, 05 Feb 2012 13:51:28 +0000</pubDate>
      <generator>http://pipes.yahoo.com/pipes/</generator>
      <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.neilcrosby.com/NeilCrosbyLifestreamConsidered" /><feedburner:info uri="neilcrosbylifestreamconsidered" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
         <title>team++; making your team work better together</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/FFGjYfbidc0/team-plus-plus</link>
         <description>&lt;div style="width:425px;" id="__ss_10176010"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/team-plus-plus" title="team++; making your team work better together"&gt;team++; making your team work better together&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View more &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/team-plus-plus</guid>
         <pubDate>Tue, 15 Nov 2011 22:02:45 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/teamplusplus-111115160246-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br>As presented at London Web Standards, on Monday 14th November 2011.

This talk isn&rsquo;t brain science.

Some teams are better than others. Some get more done, some have more bugs. What they all can be though, is better. In this session, Neil Crosby witters on about some of the things that he&rsquo;s done to help create a better functioning team.<img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/FFGjYfbidc0" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/team-plus-plus" />
            <media:description type="plain">As presented at London Web Standards, on Monday 14th November 2011.

This talk isn't brain science.

Some teams are better than others. Some get more done, some have more bugs. What they all can be though, is better. In this session, Neil Crosby witters on about some of the things that he's done to help create a better functioning team.</media:description>
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/teamplusplus-111115160246-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;As presented at London Web Standards, on Monday 14th November 2011.

This talk isn&amp;amp;rsquo;t brain science.

Some teams are better than others. Some get more done, some have more bugs. What they all can be though, is better. In this session, Neil Crosby witters on about some of the things that he&amp;amp;rsquo;s done to help create a better functioning team.</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/teamplusplus-111115160246-phpapp02-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/team-plus-plus</feedburner:origLink></item>
      <item>
         <title>team++</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/0awQMIb9dyw/team-8855746</link>
         <description>&lt;div style="width:425px;" id="__ss_8855746"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/team-8855746" title="team++"&gt;team++&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View more &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/team-8855746</guid>
         <pubDate>Mon, 15 Aug 2011 15:27:06 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/makinglifebetterfortheteam-110815102707-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br>How we powered up the BBC Homepage team.<img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/0awQMIb9dyw" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/team-8855746" />
            <media:description type="plain">How we powered up the BBC Homepage team.</media:description>
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/makinglifebetterfortheteam-110815102707-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;How we powered up the BBC Homepage team.</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/makinglifebetterfortheteam-110815102707-phpapp01-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/team-8855746</feedburner:origLink></item>
      <item>
         <title>Making PHP CodeSniffer use JSLint via Rhino</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/bSXmpCRroug/</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="nofollow" target="_blank" href="http://pear.php.net/package/PHP_CodeSniffer/"&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="nofollow" target="_blank" href="http://www.jslint.com/"&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="nofollow" target="_blank" href="http://www.mozilla.org/rhino/"&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="nofollow" target="_blank" href="http://www.mozilla.org/rhino/download.html"&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="nofollow" target="_blank" href="https://github.com/douglascrockford/JSLint/raw/ca120a731db548c0014320fa0c196edc613536ae/rhino.js"&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="nofollow" target="_blank" href="https://github.com/douglascrockford/JSLint/raw/master/fulljslint.js"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/bSXmpCRroug" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/QRvGrDy54iI/</feedburner:origLink></item>
      <item>
         <title>Dev Checks – Improving code quality by getting developers to look at each other’s work</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/pq9IHA-sG4U/</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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/pq9IHA-sG4U" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/9yDROqGdfoo/</feedburner:origLink></item>
      <item>
         <title>Cuba Libre Oscuro</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/GtSI5kiufZo/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/GtSI5kiufZo" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/cuba-libre-oscuro/</feedburner:origLink></item>
      <item>
         <title>Using last.fm tags to make awesome playlists in your local iTunes library</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/rP9teXa4EFw/</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="nofollow" target="_blank" href="http://www.xml.com/pub/a/2007/09/04/parsing-microformats.html?page=2"&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="nofollow" target="_blank" href="http://github.com/NeilCrosby/itunes-helpers/commit/b94cf1f2c28bdc2b83129b458e0e6bc42573afdb"&gt;couple of scripts&lt;/a&gt; (though obviously take &lt;a rel="nofollow" target="_blank" href="http://github.com/NeilCrosby/itunes-helpers/tree/master/playlist/lastfm/"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/rP9teXa4EFw" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/pm-HuIgSqg4/</feedburner:origLink></item>
      <item>
         <title>Review: Cordless Dog’s “Stay”</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/jQvcZyHeIe8/</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="nofollow" target="_blank" href="http://cordlessdog.com/stay/"&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="nofollow" target="_blank" href="http://cordlessdog.com/stay/"&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="nofollow" target="_blank" href="https://twitter.com/fatbusinessman/status/21316857798"&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="nofollow" target="_blank" href="http://cordlessdog.com/stay/faq/"&gt;a future release of Stay&lt;/a&gt;.&lt;/p&gt;
&lt;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/jQvcZyHeIe8" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/TJ_vXUAuMu4/</feedburner:origLink></item>
      <item>
         <title>The Oatmeal and Raisin Cookies</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/YX_15Kcwsks/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/YX_15Kcwsks" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/the-oatmeal-and-raisin-cookies/</feedburner:origLink></item>
      <item>
         <title>True Blood Raspberry Mojito</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/C4r9ghiTwmk/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/C4r9ghiTwmk" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/true-blood-raspberry-mojito/</feedburner:origLink></item>
      <item>
         <title>Butternut Squash and Chorizo Salad</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/drplKlad6Rg/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/drplKlad6Rg" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/butternut-squash-and-chorizo-salad/</feedburner:origLink></item>
      <item>
         <title>Packratius, and the inevitable overwhelming of del.icio.us</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/pszoT0f_SlE/</link>
         <description>&lt;p&gt;I&amp;#8217;ve been using &lt;a rel="nofollow" target="_blank" href="http://delicious.com"&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="nofollow" target="_blank" href="http://packrati.us"&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="nofollow" target="_blank" href="http://www.bbc.co.uk/food/recipes/carrotsglazedwithcum_80467"&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="nofollow" target="_blank" href="http://packrati.us/preferences"&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="nofollow" target="_blank" href="http://simonjobling.com"&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="nofollow" target="_blank" href="http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101"&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="nofollow" target="_blank" href="http://kulor.com/"&gt;James Broad&lt;/a&gt; has been finding Packratius overwhelming &amp;#8211; it was his &lt;a rel="nofollow" target="_blank" href="http://twitter.com/kulor/status/15596311122"&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="http://delicious.com/simey_j/"&amp;gt;
    statingthebleedingobvious
  &amp;lt;/category&amp;gt;
  &amp;lt;category domain="http://delicious.com/simey_j/"&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="nofollow" target="_blank" href="http://pipes.yahoo.com/pipes/pipe.info?_id=537a07fd888c1c38dedcb59f6b5f8101"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/pszoT0f_SlE" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/RT_0H1oZ1j8/</feedburner:origLink></item>
      <item>
         <title>Geolocation &amp; Beer: Part 4 – Finding the Beer</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/iwZUWBUptzw/</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="nofollow" target="_blank" href="http://beernear.me"&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="nofollow" target="_blank" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_fonje_local"&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="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/"&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;{
    "responseData": {
        "results": [
            {
                "GsearchResultClass":"GlocalSearch",
                "lat":"59.334743",
                "lng":"18.063034",
                "accuracy":"8",
                "title":"&amp;#92;u003cb&amp;#92;u003ePub&amp;#92;u003c/b&amp;#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
}
&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="nofollow" target="_blank" href="http://php.net/apc"&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="nofollow" target="_blank" href="http://www.debian-administration.org/articles/574"&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 = "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
    );
}
&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="nofollow" target="_blank" href="http://sciencehackday.com"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/iwZUWBUptzw" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/LZDu1ldw8JY/</feedburner:origLink></item>
      <item>
         <title>Geolocation &amp; Beer: Part 3 – Static Maps</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/nHBu0I7V_tw/</link>
         <description>&lt;p&gt;The final thing to do now that you&amp;#8217;ve &lt;a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/"&gt;found the user&amp;#8217;s latitude and longitude&lt;/a&gt; and &lt;a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/"&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="nofollow" target="_blank" href="http://beernear.me"&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="nofollow" target="_blank" href="http://code.google.com/apis/maps/documentation/staticmaps/"&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="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" alt="A simple static google map" class="sidenote"&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="nofollow" target="_blank" href="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"&gt;this&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Adding some custom markers&lt;/h2&gt;

&lt;p&gt;&lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.022.jpg" alt="Getting a static map"&gt; &lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.024.jpg" alt="Custom markers"&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="nofollow" target="_blank" href="http://beernear.me/coord/51.517819/-0.13150/"&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="nofollow" target="_blank" href="http://www.pubstandards.co.uk/"&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="nofollow" target="_blank" href="http://beernear.me/coord/51.517819/-0.13150/"&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="nofollow" target="_blank" href="http://beernear.me"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/nHBu0I7V_tw" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/iZqu4-YnFuk/</feedburner:origLink></item>
      <item>
         <title>Geolocation &amp; Beer: Part 2 – Telling the User where they are</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/Ivv2TUhpRQ0/</link>
         <description>&lt;p&gt;In the last entry, I wrote about how we can &lt;a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/"&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="nofollow" target="_blank" href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_intro_fonje"&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;{
    "responseData": {
        "results": [{
            …
            "title": "Kelly Langley…",
            "streetAddress": "Cowley Road, Cavendish House…",
            "city": "Cambridge",
            …
        }]
    }
}
&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="nofollow" target="_blank" href="http://beernear.me"&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="nofollow" target="_blank" href="http://beernear.me"&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="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/"&gt;putting the user&amp;#8217;s location onto a static Google Map&lt;/a&gt;.&lt;/p&gt;
&lt;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/Ivv2TUhpRQ0" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/hOwkNYFOEnc/</feedburner:origLink></item>
      <item>
         <title>Geolocation &amp; Beer: Part 1 – Finding the user</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/qPtZ4xHFkUU/</link>
         <description>&lt;p&gt;I recently attended &lt;a rel="nofollow" target="_blank" href="http://barcamb.ltheobald.co.uk/"&gt;BarCamb3&lt;/a&gt;, a BarCamp held at the lovely &lt;a rel="nofollow" target="_blank" href="http://www.red-gate.com/"&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="nofollow" target="_blank" href="http://beernear.me/"&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="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/"&gt;find out where the user actually is&lt;/a&gt;, and to &lt;a rel="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/"&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="nofollow" target="_blank" href="http://dev.w3.org/geo/api/spec-source.html"&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="http://thecodetrain.co.uk/images/geolocation/geolocation.001.png" alt="GeoLocation &amp;#038; Beer"&gt; &lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.009.png" alt="What will I talk about?"&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="nofollow" target="_blank" href="http://www.wait-till-i.com/2010/03/04/google-chrome-getting-navigator-geolocation/"&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="http://thecodetrain.co.uk/images/geolocation/geolocation.011.png" alt="navigator.geolocation support"&gt; &lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.012.jpg" alt="Other APIs are available"&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="nofollow" target="_blank" href="http://en.wikipedia.org/wiki/Mozilla_Geode"&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="nofollow" target="_blank" href="http://www.loki.com"&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="http://thecodetrain.co.uk/images/geolocation/geolocation.013.jpg" alt="GeoLocation check"&gt; &lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.014.jpg" alt="getCurrentPosition"&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="http://thecodetrain.co.uk/images/geolocation/geolocation.015.jpg" alt="Keep finding the user"&gt; &lt;img src="http://thecodetrain.co.uk/images/geolocation/geolocation.016.jpg" alt="You've got a location!"&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="nofollow" target="_blank" href="http://dev.w3.org/geo/api/spec-source.html#position_interface"&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(
            "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();
}
&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="nofollow" target="_blank" href="http://projects.thecodetrain.co.uk/geolocation/"&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="nofollow" target="_blank" href="http://beernear.me/"&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="nofollow" target="_blank" href="http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/"&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;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/qPtZ4xHFkUU" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/ERzzqZ9HSAU/</feedburner:origLink></item>
      <item>
         <title>Geolocation and Beer</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/qfNj4rNI-q4/geolocation-and-beer</link>
         <description>&lt;div style="width:425px;" id="__ss_3845789"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/geolocation-and-beer" title="Geolocation and Beer"&gt;Geolocation and Beer&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View more &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/geolocation-and-beer</guid>
         <pubDate>Sun, 25 Apr 2010 10:00:47 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/geolocationandbeer-100425050058-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/qfNj4rNI-q4" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/geolocation-and-beer" />
            <media:description type="plain" />
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/geolocationandbeer-100425050058-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/geolocationandbeer-100425050058-phpapp01-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/geolocation-and-beer</feedburner:origLink></item>
      <item>
         <title>Review: The Non-Designer’s Design Book</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/DC36iBvbXR0/</link>
         <description>&lt;p&gt;I&amp;#8217;m not a designer.  That much is obvious from looking at the websites I produce that haven&amp;#8217;t been designed by someone else.  That doesn&amp;#8217;t mean I don&amp;#8217;t care though; which is why on Christmas day last year I ordered &lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&amp;amp;location=http%3A%2F%2Fwww.amazon.co.uk%2Fs%3Fie%3DUTF8%26redirect%3Dtrue%26search-type%3Dss%26index%3Dbooks-uk%26field-author%3DRobin%2520Williams&amp;amp;tag=workingwmeuk-21&amp;amp;linkCode=ur2&amp;amp;camp=1634&amp;amp;creative=19450"&gt;Robin Williams&lt;/a&gt;&amp;#8216; &amp;#8220;&lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321534042?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321534042"&gt;The Non-Designer&amp;#8217;s Design Book&lt;/a&gt;&amp;#8221; (as recommended to me by &lt;a rel="nofollow" target="_blank" href="http://timhuegdon.com/"&gt;Tim Huegdon&lt;/a&gt;).&lt;/p&gt;

 

&lt;p&gt;I&amp;#8217;ve only just got round to reading the book, but I&amp;#8217;m glad I did.  As a learning book it&amp;#8217;s deliberately quite lightweight and easy to get through in a short time, in the same way that &lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&amp;amp;location=http%3A%2F%2Fwww.amazon.co.uk%2Fs%3Fie%3DUTF8%26redirect%3Dtrue%26search-type%3Dss%26index%3Dbooks-uk%26field-author%3DSteve%2520Krug&amp;amp;tag=workingwmeuk-21&amp;amp;linkCode=ur2&amp;amp;camp=1634&amp;amp;creative=19450"&gt;Steve Krug&lt;/a&gt;&amp;#8216;s &amp;#8220;&lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321344758?ie=UTF8&amp;amp;tag=workingwmeuk-21&amp;amp;linkCode=as2&amp;amp;camp=1634&amp;amp;creative=19450&amp;amp;creativeASIN=0321344758"&gt;Don&amp;#8217;t Make Me Think&lt;/a&gt;&amp;#8221; is designed to be absorbed in a couple of hours on a flight.  All told, I spent about three hours with this book, on my tube journeys to and from work this week.&lt;/p&gt;

&lt;p&gt;Robin starts her journey by briefly explaining the concepts of Contrast, Repetition, Alignment and Proximity (anyone spot an acronym there?), before moving on to explore each concept in greater detail.  As Robin repeatedly tells us in her book, by being able to name the concepts you&amp;#8217;re able to identify them and use them deliberately rather than accidentally.&lt;/p&gt;

&lt;p&gt;The second half of the book deals with type; the different styles of typefaces, how to combine them and horrible errors of judgement to avoid.&lt;/p&gt;

&lt;p&gt;Spread throughout the book are a bunch of mini quizzes and exercises designed to get you thinking about what you&amp;#8217;ve just read.  The quizzes are a nice touch, and I&amp;#8217;m sure I&amp;#8217;ve retained more knowledge because of them than I would have done if I&amp;#8217;d just read through from cover to cover.&lt;/p&gt;

&lt;p&gt;The book covers design in general, rather than being focussed on the web, print or presentations.  Whilst Williams has written a book called &amp;#8220;&lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321303377?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321303377"&gt;The Non-Designer&amp;#8217;s Web Book&lt;/a&gt;&amp;#8221; I specifically chose to buy this one because both I wanted a general overview book and because the web book is from 2005 (a lifetime ago on the web) and has some mixed reviews.  &amp;#8220;The Non-Designer&amp;#8217;s Design Book&amp;#8221; did not disappoint &amp;#8211; it&amp;#8217;s given me that overview that I was looking for, and I now feel a bit more comfortable that my designs will actually work.&lt;/p&gt;

&lt;p&gt;&amp;#8220;&lt;a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321534042?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321534042"&gt;The Non-Designer&amp;#8217;s Design Book&lt;/a&gt;&amp;#8221; costs £23.99 in all good bookshops, or currently £12.30 on Amazon.&lt;/p&gt;
&lt;div style="display:block;"&gt;&lt;small&gt;&lt;em&gt;&lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com"&gt;Neil Crosby&lt;/a&gt; also blogs at about t-shirts at &lt;a rel="nofollow" target="_blank" href="http://iwearcotton.com"&gt;I Wear Cotton&lt;/a&gt;, writes &lt;a rel="nofollow" target="_blank" href="http://thetenwordreview.com/users/workingwithme"&gt;Ten Word Reviews&lt;/a&gt;, and uploads &lt;a rel="nofollow" target="_blank" href="http://www.flickr.com/photos/thevoicewithin/"&gt;photos&lt;/a&gt; to flickr.  You can follow a combined feed of posts at &lt;a rel="nofollow" target="_blank" href="http://neilcrosby.com/"&gt;NeilCrosby.com&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/div&gt;</description>
         <guid isPermaLink="false">http://thecodetrain.co.uk/?p=357</guid>
         <pubDate>Sun, 21 Feb 2010 15:10:05 +0000</pubDate>
         <content:encoded><![CDATA[<p>I&#8217;m not a designer.  That much is obvious from looking at the websites I produce that haven&#8217;t been designed by someone else.  That doesn&#8217;t mean I don&#8217;t care though; which is why on Christmas day last year I ordered <a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.co.uk%2Fs%3Fie%3DUTF8%26redirect%3Dtrue%26search-type%3Dss%26index%3Dbooks-uk%26field-author%3DRobin%2520Williams&amp;tag=workingwmeuk-21&amp;linkCode=ur2&amp;camp=1634&amp;creative=19450">Robin Williams</a>&#8216; &#8220;<a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321534042?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321534042">The Non-Designer&#8217;s Design Book</a>&#8221; (as recommended to me by <a rel="nofollow" target="_blank" href="http://timhuegdon.com/">Tim Huegdon</a>).</p>

 

<p>I&#8217;ve only just got round to reading the book, but I&#8217;m glad I did.  As a learning book it&#8217;s deliberately quite lightweight and easy to get through in a short time, in the same way that <a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.co.uk%2Fs%3Fie%3DUTF8%26redirect%3Dtrue%26search-type%3Dss%26index%3Dbooks-uk%26field-author%3DSteve%2520Krug&amp;tag=workingwmeuk-21&amp;linkCode=ur2&amp;camp=1634&amp;creative=19450">Steve Krug</a>&#8216;s &#8220;<a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321344758?ie=UTF8&amp;tag=workingwmeuk-21&amp;linkCode=as2&amp;camp=1634&amp;creative=19450&amp;creativeASIN=0321344758">Don&#8217;t Make Me Think</a>&#8221; is designed to be absorbed in a couple of hours on a flight.  All told, I spent about three hours with this book, on my tube journeys to and from work this week.</p>

<p>Robin starts her journey by briefly explaining the concepts of Contrast, Repetition, Alignment and Proximity (anyone spot an acronym there?), before moving on to explore each concept in greater detail.  As Robin repeatedly tells us in her book, by being able to name the concepts you&#8217;re able to identify them and use them deliberately rather than accidentally.</p>

<p>The second half of the book deals with type; the different styles of typefaces, how to combine them and horrible errors of judgement to avoid.</p>

<p>Spread throughout the book are a bunch of mini quizzes and exercises designed to get you thinking about what you&#8217;ve just read.  The quizzes are a nice touch, and I&#8217;m sure I&#8217;ve retained more knowledge because of them than I would have done if I&#8217;d just read through from cover to cover.</p>

<p>The book covers design in general, rather than being focussed on the web, print or presentations.  Whilst Williams has written a book called &#8220;<a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321303377?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321303377">The Non-Designer&#8217;s Web Book</a>&#8221; I specifically chose to buy this one because both I wanted a general overview book and because the web book is from 2005 (a lifetime ago on the web) and has some mixed reviews.  &#8220;The Non-Designer&#8217;s Design Book&#8221; did not disappoint &#8211; it&#8217;s given me that overview that I was looking for, and I now feel a bit more comfortable that my designs will actually work.</p>

<p>&#8220;<a rel="nofollow" target="_blank" href="http://www.amazon.co.uk/gp/product/0321534042?ie=UTF8tag=workingwmeuk-21linkCode=as2camp=1634creative=19450creativeASIN=0321534042">The Non-Designer&#8217;s Design Book</a>&#8221; costs £23.99 in all good bookshops, or currently £12.30 on Amazon.</p>
<img src="http://feeds.feedburner.com/~r/TheCodeTrain/~4/V0AtRIAMgE0" height="1" width="1"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/DC36iBvbXR0" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feeds.thecodetrain.co.uk/~r/TheCodeTrain/~3/V0AtRIAMgE0/</feedburner:origLink></item>
      <item>
         <title>Chocolate Orange Cupcakes</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/zejO8j3PDhE/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/zejO8j3PDhE" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/chocolate-orange-cupcakes/</feedburner:origLink></item>
      <item>
         <title>Ridiculously Rich Chocolate Cake</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/83j2WIpBiJc/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/83j2WIpBiJc" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/ridiculously-rich-chocolate-cake/</feedburner:origLink></item>
      <item>
         <title>Cherry and Sultana Flapjack</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/GuIe7W-HZiY/</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 [...]</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/GuIe7W-HZiY" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/cherry-and-sultana-flapjack/</feedburner:origLink></item>
      <item>
         <title>Robocop: Directive 3 Baby Food</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/zeW_gw7xTeA/</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 [...]&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/zeW_gw7xTeA" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feedproxy.google.com/~r/IWearCotton/~3/Zc48fbwO4Iw/</feedburner:origLink></item>
      <item>
         <title>Bacon and Courgette Tagliatelle</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/8VHBtkYlwI8/</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'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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/8VHBtkYlwI8" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/bacon-and-courgette-tagliatelle/</feedburner:origLink></item>
      <item>
         <title>ED-209</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/P7ZEbadhWLk/</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 [...]&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/P7ZEbadhWLk" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feedproxy.google.com/~r/IWearCotton/~3/Nd4N3PHHj5c/</feedburner:origLink></item>
      <item>
         <title>Strained Mojito</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/ugEfV8XCQbE/</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><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/ugEfV8XCQbE" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/strained-mojito/</feedburner:origLink></item>
      <item>
         <title>Shortbread</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/9tqXW7q7t2M/</link>
         <description>Tasty shortbread - good on its own, even better as part of Millionaire's Shortbread.</description>
         <guid isPermaLink="false">http://neilsnoms.com/?p=23</guid>
         <pubDate>Sun, 13 Dec 2009 10:13:43 +0000</pubDate>
         <content:encoded><![CDATA[<p>There&#8217;s nothing like a nice simple piece of shortbread that you&#8217;ve made yourself. Most of the time I use this as a base to my yummy Millionaire&#8217;s Shortbread, but it&#8217;s just as tasty on its own or with some good vanilla icecream.</p>

<p>Takes 30 minutes &#8211; 10 minutes preparation, 20 minutes cooking.<span id="more-23"></span></p>

<h2>Ingredients</h2>

<ul>
<li>170g unsalted butter</li>
<li>50g granulated sugar</li>
<li>1/2 tsp vanilla extract</li>
<li>210g plain flour</li>
<li>a pinch of salt</li>
</ul>

<h2>Instructions</h2>

<ol>
<li><p>Preheat your oven to 180ºc. </p></li>
<li><p>Cream the butter and sugar, then beat in the vanilla extract. </p></li>
<li><p>Add flour and salt, and mix until everything&#8217;s come together.  </p></li>
<li><p>Press hard into a tin and bake for 20 minutes, or until slightly golden. </p>

<p>If I&#8217;m making this Shortbread to turn into Millionaire&#8217;s Shortbread I like to line the tin with foil to make turning it out later easier.</p></li>
<li><p>Once the Shortbread comes out of the oven, if you&#8217;re just going to keep it as Shortbread then you might like to score it with a knife to make it easier to break into nommy pieces once it&#8217;s cool.</p></li>
</ol><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/9tqXW7q7t2M" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://neilsnoms.com/shortbread/</feedburner:origLink></item>
      <item>
         <title>Lagging Pipes</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/XMKFp33lGIs/lagging-pipes</link>
         <description>&lt;div style="width:425px;" id="__ss_1972382"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/lagging-pipes" title="Lagging Pipes"&gt;Lagging Pipes&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View more &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/lagging-pipes</guid>
         <pubDate>Wed, 09 Sep 2009 12:54:10 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/pipes-lagging-090909075414-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/XMKFp33lGIs" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/lagging-pipes" />
            <media:description type="plain" />
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/pipes-lagging-090909075414-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/pipes-lagging-090909075414-phpapp02-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/lagging-pipes</feedburner:origLink></item>
      <item>
         <title>Yahoo! Pipes: Munging, Mixing and Mashing</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/F8aUSRVif_4/pipes</link>
         <description>&lt;div style="width:425px;" id="__ss_1937195"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/pipes" title="Yahoo! Pipes: Munging, Mixing and Mashing"&gt;Yahoo! Pipes: Munging, Mixing and Mashing&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View another &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;webinar&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/pipes</guid>
         <pubDate>Tue, 01 Sep 2009 14:42:33 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/pipestalk-090901094249-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/F8aUSRVif_4" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/pipes" />
            <media:description type="plain" />
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/pipestalk-090901094249-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/pipestalk-090901094249-phpapp01-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/pipes</feedburner:origLink></item>
      <item>
         <title>Search Monkey - Open Hack London '09</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/CI6fB8M9ABk/search-monkey-open-hack-london-09</link>
         <description>&lt;div style="width:425px;" id="__ss_1411315"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/search-monkey-open-hack-london-09" title="Search Monkey - Open Hack London &amp;#39;09"&gt;Search Monkey - Open Hack London &amp;#39;09&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View more &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/search-monkey-open-hack-london-09</guid>
         <pubDate>Sun, 10 May 2009 01:25:52 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/searchmonkey-openhackday-090509202600-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/CI6fB8M9ABk" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/search-monkey-open-hack-london-09" />
            <media:description type="plain" />
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/searchmonkey-openhackday-090509202600-phpapp02-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/searchmonkey-openhackday-090509202600-phpapp02-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/search-monkey-open-hack-london-09</feedburner:origLink></item>
      <item>
         <title>Automated Frontend Testing</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/iUvPnSK0xPs/automated-frontend-testing</link>
         <description>&lt;div style="width:425px;" id="__ss_1212895"&gt;&lt;strong style="display:block;margin:12px 0 4px;"&gt;&lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby/automated-frontend-testing" title="Automated Frontend Testing"&gt;Automated Frontend Testing&lt;/a&gt;&lt;/strong&gt;  &lt;div style="padding:5px 0 12px;"&gt; View another &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/"&gt;webinar&lt;/a&gt; from &lt;a rel="nofollow" target="_blank" href="http://www.slideshare.net/neilcrosby"&gt;Neil Crosby&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;</description>
         <author>neilcrosby@slideshare.net(neilcrosby)</author>
         <guid isPermaLink="false">http://www.slideshare.net/neilcrosby/automated-frontend-testing</guid>
         <pubDate>Sat, 28 Mar 2009 00:17:56 +0000</pubDate>
         <content:encoded><![CDATA[<img src="http://cdn.slidesharecdn.com/automatedfrontendtesting-090327191801-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/><br>A talk about my frontend testing framework: http://github.com/NeilCrosby/frontend-test-suite/tree/master<img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/iUvPnSK0xPs" height="1" width="1"/>]]></content:encoded>
         <media:content>
            <media:player url="http://www.slideshare.net/neilcrosby/automated-frontend-testing" />
            <media:description type="plain">A talk about my frontend testing framework: http://github.com/NeilCrosby/frontend-test-suite/tree/master</media:description>
            <media:text type="html">&amp;lt;img src="http://cdn.slidesharecdn.com/automatedfrontendtesting-090327191801-phpapp01-thumbnail-2" alt="" style="border:1px solid #C3E6D8;float:right;"/&amp;gt;&amp;lt;br&amp;gt;A talk about my frontend testing framework: http://github.com/NeilCrosby/frontend-test-suite/tree/master</media:text>
            <media:thumbnail height="90" url="http://cdn.slidesharecdn.com/automatedfrontendtesting-090327191801-phpapp01-thumbnail-2" width="120" />
         </media:content>
      <feedburner:origLink>http://www.slideshare.net/neilcrosby/automated-frontend-testing</feedburner:origLink></item>
      <item>
         <title>The Robotanist</title>
         <link>http://feeds.neilcrosby.com/~r/NeilCrosbyLifestreamConsidered/~3/vDPBka_RVO4/</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 [...]&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"/><img src="http://feeds.feedburner.com/~r/NeilCrosbyLifestreamConsidered/~4/vDPBka_RVO4" height="1" width="1"/>]]></content:encoded>
      <feedburner:origLink>http://feedproxy.google.com/~r/IWearCotton/~3/xjUwli3_FG0/</feedburner:origLink></item>
   </channel>
</rss><!-- fe3.yql.bf1.yahoo.com compressed/chunked Sun Feb  5 13:51:26 UTC 2012 -->

