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

<channel>
	<title>The Code Train &#187; Blog Posts</title>
	<atom:link href="http://thecodetrain.co.uk/category/blog-posts/feed/" rel="self" type="application/rss+xml" />
	<link>http://thecodetrain.co.uk</link>
	<description>Where Neil Crosby talks about coding on the train...</description>
	<lastBuildDate>Wed, 18 Aug 2010 18:22:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using last.fm tags to make awesome playlists in your local iTunes library</title>
		<link>http://thecodetrain.co.uk/2010/08/using-last-fm-tags-to-make-awesome-playlists-in-your-local-itunes-library/</link>
		<comments>http://thecodetrain.co.uk/2010/08/using-last-fm-tags-to-make-awesome-playlists-in-your-local-itunes-library/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 18:00:15 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[itunes]]></category>
		<category><![CDATA[last.fm]]></category>
		<category><![CDATA[shell script]]></category>
		<category><![CDATA[tags]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=484</guid>
		<description><![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 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 href="http://github.com/NeilCrosby/itunes-helpers/commit/b94cf1f2c28bdc2b83129b458e0e6bc42573afdb">couple of scripts</a> (though obviously take <a 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<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 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 href="http://github.com/NeilCrosby/itunes-helpers/commit/b94cf1f2c28bdc2b83129b458e0e6bc42573afdb">couple of scripts</a> (though obviously take <a 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/08/using-last-fm-tags-to-make-awesome-playlists-in-your-local-itunes-library/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Review: Cordless Dog&#8217;s &#8220;Stay&#8221;</title>
		<link>http://thecodetrain.co.uk/2010/08/review-cordless-dogs-stay/</link>
		<comments>http://thecodetrain.co.uk/2010/08/review-cordless-dogs-stay/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 08:39:43 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[positive]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=475</guid>
		<description><![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 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 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 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 href="http://cordlessdog.com/stay/faq/">a future release of Stay</a>.</p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<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 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 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 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 href="http://cordlessdog.com/stay/faq/">a future release of Stay</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/08/review-cordless-dogs-stay/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Packratius, and the inevitable overwhelming of del.icio.us</title>
		<link>http://thecodetrain.co.uk/2010/06/packratius-and-the-inevitable-overwhelming-of-del-icio-us/</link>
		<comments>http://thecodetrain.co.uk/2010/06/packratius-and-the-inevitable-overwhelming-of-del-icio-us/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 20:22:32 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[del.icio.us]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[packrati.us]]></category>
		<category><![CDATA[pipes]]></category>
		<category><![CDATA[yahoo pipes]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=455</guid>
		<description><![CDATA[<p>I&#8217;ve been using <a 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 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 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 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 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 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 href="http://kulor.com/">James Broad</a> has been finding Packratius overwhelming &#8211; it was his <a 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 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using <a 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 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 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 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 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 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 href="http://kulor.com/">James Broad</a> has been finding Packratius overwhelming &#8211; it was his <a 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 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/06/packratius-and-the-inevitable-overwhelming-of-del-icio-us/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geolocation &amp; Beer: Part 4 &#8211; Finding the Beer</title>
		<link>http://thecodetrain.co.uk/2010/06/geolocation-and-beer-part-4-finding-the-beer/</link>
		<comments>http://thecodetrain.co.uk/2010/06/geolocation-and-beer-part-4-finding-the-beer/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 20:24:18 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[beer]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[curl]]></category>
		<category><![CDATA[geolocation]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=449</guid>
		<description><![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 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 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 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":"\u003cb\u003ePub\u003c/b\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 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 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 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<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 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 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 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":"\u003cb\u003ePub\u003c/b\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 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 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 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/06/geolocation-and-beer-part-4-finding-the-beer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Geolocation &amp; Beer: Part 3 &#8211; Static Maps</title>
		<link>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/</link>
		<comments>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/#comments</comments>
		<pubDate>Mon, 17 May 2010 20:10:43 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[progressive enhancement]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=391</guid>
		<description><![CDATA[<p>The final thing to do now that you&#8217;ve <a 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 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 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 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 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 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 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 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 href="http://beernear.me">something slightly useful</a>.  Maybe in a year or two I&#8217;ll have even made it pretty.</p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>The final thing to do now that you&#8217;ve <a 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 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 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 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 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 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 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 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 href="http://beernear.me">something slightly useful</a>.  Maybe in a year or two I&#8217;ll have even made it pretty.</p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-3-static-maps/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geolocation &amp; Beer: Part 2 &#8211; Telling the User where they are</title>
		<link>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/</link>
		<comments>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/#comments</comments>
		<pubDate>Thu, 13 May 2010 22:00:23 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[beer]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=387</guid>
		<description><![CDATA[<p>In the last entry, I wrote about how we can <a 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 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 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 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 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>In the last entry, I wrote about how we can <a 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 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 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 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 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-2-telling-the-user-where-they-are/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Geolocation &amp; Beer: Part 1 &#8211; Finding the user</title>
		<link>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/</link>
		<comments>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/#comments</comments>
		<pubDate>Wed, 05 May 2010 22:10:37 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[barcamb]]></category>
		<category><![CDATA[barcamp]]></category>
		<category><![CDATA[beer]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[w3c]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=389</guid>
		<description><![CDATA[<p>I recently attended <a href="http://barcamb.ltheobald.co.uk/">BarCamb3</a>, a BarCamp held at the lovely <a 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 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 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 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 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 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 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 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 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 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 href="http://beernear.me/">Beer Near Me</a> I do two things with the location once it&#8217;s been found &#8211; I <a 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>I recently attended <a href="http://barcamb.ltheobald.co.uk/">BarCamb3</a>, a BarCamp held at the lovely <a 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 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 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 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 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 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 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 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 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 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 href="http://beernear.me/">Beer Near Me</a> I do two things with the location once it&#8217;s been found &#8211; I <a 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/05/geolocation-and-beer-part-1-finding-the-user/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Review: The Non-Designer&#8217;s Design Book</title>
		<link>http://thecodetrain.co.uk/2010/02/review-the-non-designers-design-book/</link>
		<comments>http://thecodetrain.co.uk/2010/02/review-the-non-designers-design-book/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 15:10:05 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=357</guid>
		<description><![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 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 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 href="http://timhuegdon.com/">Tim Huegdon</a>).</p>

<iframe class="sidenote" src="http://rcm-uk.amazon.co.uk/e/cm?lt1=_top&#038;bc1=FFFFFF&#038;IS2=1&#038;bg1=FFFFFF&#038;fc1=000000&#038;lc1=0000FF&#038;t=workingwmeuk-21&#038;o=2&#038;p=8&#038;l=as1&#038;m=amazon&#038;f=ifr&#038;md=0M5A6TN3AXP2JHJBWT02&#038;asins=0321534042" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>

<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 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>&#8217;s &#8220;<a 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 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 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>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<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 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 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 href="http://timhuegdon.com/">Tim Huegdon</a>).</p>

<iframe class="sidenote" src="http://rcm-uk.amazon.co.uk/e/cm?lt1=_top&#038;bc1=FFFFFF&#038;IS2=1&#038;bg1=FFFFFF&#038;fc1=000000&#038;lc1=0000FF&#038;t=workingwmeuk-21&#038;o=2&#038;p=8&#038;l=as1&#038;m=amazon&#038;f=ifr&#038;md=0M5A6TN3AXP2JHJBWT02&#038;asins=0321534042" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>

<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 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>&#8217;s &#8220;<a 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 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 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>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/02/review-the-non-designers-design-book/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Deep Linking into YouTube Videos</title>
		<link>http://thecodetrain.co.uk/2010/01/deep-linking-into-youtube-videos/</link>
		<comments>http://thecodetrain.co.uk/2010/01/deep-linking-into-youtube-videos/#comments</comments>
		<pubDate>Fri, 08 Jan 2010 23:08:48 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[youtube]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=352</guid>
		<description><![CDATA[<p>Just a very quick post today to highlight something I only became aware of a couple of days ago because of <a href="http://jakearchibald.com">Jake Archibald</a>, when he posted a youtube link on an internal mailing list &#8211; it&#8217;s possible to deep link into an arbitrary point within YouTube videos.</p>

<p>I had thought that this was something most other interested people would have known about already, and that I was slow on the uptake as usual, but it turns out that when I mentioned this to <a href="http://adrianocastro.net">Adriano Castro</a> today he wasn&#8217;t aware.  So, I present to you a method for deep linking into YouTube videos.</p>

<ol>
<li><p>Take one YouTube URL.</p>

<pre><code>http://www.youtube.com/watch?v=4Ust9YBlEfY
</code></pre></li>
<li><p>Watch it, and find a place within it that you&#8217;d like to link to.</p>

<p>In this instance, I want to link 28 seconds in.</p></li>
<li><p>Add a fragment to the URL with the format #t=<em>minutes</em>m<em>seconds</em></p>

<p>In this instance, the URL would become:</p>

<pre><code>http://www.youtube.com/watch?v=4Ust9YBlEfY#t=0m28
</code></pre></li>
<li><p>That&#8217;s all there is to it. <a href="http://www.youtube.com/watch?v=4Ust9YBlEfY#t=0m28">Simples</a>.</p></li>
</ol>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>Just a very quick post today to highlight something I only became aware of a couple of days ago because of <a href="http://jakearchibald.com">Jake Archibald</a>, when he posted a youtube link on an internal mailing list &#8211; it&#8217;s possible to deep link into an arbitrary point within YouTube videos.</p>

<p>I had thought that this was something most other interested people would have known about already, and that I was slow on the uptake as usual, but it turns out that when I mentioned this to <a href="http://adrianocastro.net">Adriano Castro</a> today he wasn&#8217;t aware.  So, I present to you a method for deep linking into YouTube videos.</p>

<ol>
<li><p>Take one YouTube URL.</p>

<pre><code>http://www.youtube.com/watch?v=4Ust9YBlEfY
</code></pre></li>
<li><p>Watch it, and find a place within it that you&#8217;d like to link to.</p>

<p>In this instance, I want to link 28 seconds in.</p></li>
<li><p>Add a fragment to the URL with the format #t=<em>minutes</em>m<em>seconds</em></p>

<p>In this instance, the URL would become:</p>

<pre><code>http://www.youtube.com/watch?v=4Ust9YBlEfY#t=0m28
</code></pre></li>
<li><p>That&#8217;s all there is to it. <a href="http://www.youtube.com/watch?v=4Ust9YBlEfY#t=0m28">Simples</a>.</p></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2010/01/deep-linking-into-youtube-videos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using WordPress&#8217;s &#8220;Upgrade Automatically&#8221; Feature</title>
		<link>http://thecodetrain.co.uk/2009/12/using-wordpresss-upgrade-automatically-feature/</link>
		<comments>http://thecodetrain.co.uk/2009/12/using-wordpresss-upgrade-automatically-feature/#comments</comments>
		<pubDate>Sat, 19 Dec 2009 22:41:12 +0000</pubDate>
		<dc:creator>Neil Crosby</dc:creator>
				<category><![CDATA[Blog Posts]]></category>
		<category><![CDATA[Tips & Tricks]]></category>
		<category><![CDATA[commandline]]></category>
		<category><![CDATA[tip]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://thecodetrain.co.uk/?p=339</guid>
		<description><![CDATA[<p>Yup, it&#8217;s time for the WordPress upgrade dance, yet again &#8211; <a href="http://wordpress.org/development/2009/12/wordpress-2-9/">2.9 Carmen</a> has just been released and everyone using WordPress is being &#8220;urged&#8221; to upgrade.</p>

<p>Now, I&#8217;m slightly ashamed to admit it, but up until last week I hadn&#8217;t been upgrading regularly. It had seemed like in order to be able to use WordPress&#8217;s &#8220;Upgrade Automatically&#8221; functionality I had to either enable FTP (ewwww), or FTPS (seemed like a lot of effort, and needed the SSH extension for PHP installing). So, I&#8217;d ended up doing an upgrade every now and then manually. Not the best plan in the world.</p>

<p>So, last week I decided to take another look and see if there wasn&#8217;t a more sensible way to enable WordPress to run its &#8220;Upgrade Automatically&#8221; code.  Turns out there is &#8211; just make sure the directory you&#8217;re running WordPress under is owned by the same user that your web server is running as. Do this, and suddenly &#8220;Upgrade Automatically&#8221; works, and you&#8217;re a happy camper.</p>

<p>And how to do that? Simple.  First, find out which user your web server is running as:</p>

<pre><code>ps aux | grep apache
</code></pre>

<p>Generally, the answer will be <code>www-data</code>. Then, once you&#8217;ve worked out who the server&#8217;s owner is, change the owner of your WordPress directory tree:</p>

<pre><code>chown -R www-data:www-data /path/to/wordpress/
</code></pre>

<p>Then, when you go back into WordPress you&#8217;ll be able to click on the &#8220;Upgrade Automatically&#8221;, and WordPress will actually upgrade itself.  Hooray! (Of course, don&#8217;t forget to back up before you do this. I am not responsible for your data, follow instructions at your own risk, Santa Claus is real, etc.)</p>

<p>Hopefully this is of use to someone out there. It&#8217;s certainly made me happier about the whole upgrade dance.</p>

<h2>Update</h2>

<p>As Chris so rightly points out below, leaving things open to the web server to change willy nilly can be a little silly, so after running the update do another <code>chown</code>, this time changing the ownership back to your username and group.</p>
<div style="display:block"><small><em><a href="http://neilcrosby.com">Neil Crosby</a> also blogs at about t-shirts at <a href="http://iwearcotton.com">I Wear Cotton</a>, writes <a href="http://thetenwordreview.com/users/workingwithme">Ten Word Reviews</a>, and uploads <a href="http://www.flickr.com/photos/thevoicewithin/">photos</a> to flickr.  You can follow a combined feed of posts at <a href="http://neilcrosby.com/">NeilCrosby.com</a>.</em></small></div>]]></description>
			<content:encoded><![CDATA[<p>Yup, it&#8217;s time for the WordPress upgrade dance, yet again &#8211; <a href="http://wordpress.org/development/2009/12/wordpress-2-9/">2.9 Carmen</a> has just been released and everyone using WordPress is being &#8220;urged&#8221; to upgrade.</p>

<p>Now, I&#8217;m slightly ashamed to admit it, but up until last week I hadn&#8217;t been upgrading regularly. It had seemed like in order to be able to use WordPress&#8217;s &#8220;Upgrade Automatically&#8221; functionality I had to either enable FTP (ewwww), or FTPS (seemed like a lot of effort, and needed the SSH extension for PHP installing). So, I&#8217;d ended up doing an upgrade every now and then manually. Not the best plan in the world.</p>

<p>So, last week I decided to take another look and see if there wasn&#8217;t a more sensible way to enable WordPress to run its &#8220;Upgrade Automatically&#8221; code.  Turns out there is &#8211; just make sure the directory you&#8217;re running WordPress under is owned by the same user that your web server is running as. Do this, and suddenly &#8220;Upgrade Automatically&#8221; works, and you&#8217;re a happy camper.</p>

<p>And how to do that? Simple.  First, find out which user your web server is running as:</p>

<pre><code>ps aux | grep apache
</code></pre>

<p>Generally, the answer will be <code>www-data</code>. Then, once you&#8217;ve worked out who the server&#8217;s owner is, change the owner of your WordPress directory tree:</p>

<pre><code>chown -R www-data:www-data /path/to/wordpress/
</code></pre>

<p>Then, when you go back into WordPress you&#8217;ll be able to click on the &#8220;Upgrade Automatically&#8221;, and WordPress will actually upgrade itself.  Hooray! (Of course, don&#8217;t forget to back up before you do this. I am not responsible for your data, follow instructions at your own risk, Santa Claus is real, etc.)</p>

<p>Hopefully this is of use to someone out there. It&#8217;s certainly made me happier about the whole upgrade dance.</p>

<h2>Update</h2>

<p>As Chris so rightly points out below, leaving things open to the web server to change willy nilly can be a little silly, so after running the update do another <code>chown</code>, this time changing the ownership back to your username and group.</p>
]]></content:encoded>
			<wfw:commentRss>http://thecodetrain.co.uk/2009/12/using-wordpresss-upgrade-automatically-feature/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
