<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Ben Nolan</title>
 <link href="http://bnolan.github.com/atom.xml" rel="self"/>
 <link href="http://bnolan.github.com/"/>
 <updated>2011-11-06T18:37:40-08:00</updated>
 <id>http://bnolan.github.com/</id>
 <author>
   <name>Ben Nolan</name>
   <email>ben@nolanconsul.com</email>
 </author>

 
 <entry>
   <title>Big MySql Imports</title>
   <link href="http://bnolan.github.com/2011/11/07/big-mysql-imports.html"/>
   <updated>2011-11-07T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/11/07/big-mysql-imports</id>
   <content type="html">&lt;p&gt;Today I&amp;#8217;ve been fighting a 10+ gigabyte mysql import. I&amp;#8217;ve come across and solved a few problems that might be handy to someone in the future.&lt;/p&gt;

&lt;h1 id='max_allowed_packet'&gt;max_allowed_packet&lt;/h1&gt;

&lt;p&gt;In your &lt;code&gt;/etc/my.cnf&lt;/code&gt;, it specifies the maximum packet size. I had the problem where some of the insert statements exceeded 1 megabyte in size, so increasing this limit to 64M solved my first problem.&lt;/p&gt;

&lt;h1 id='resuming_from_midway_through_an_import'&gt;Resuming from mid-way through an import&lt;/h1&gt;

&lt;p&gt;Next up, I wanted to &lt;code&gt;cat&lt;/code&gt; the sql import, but skip all the tables up to table &lt;code&gt;xyz&lt;/code&gt;. This I accomplished with a little bit of sed magic:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cat dump.sql | sed -n -e &amp;#39;/`some_table_name`/,$p&amp;#39; | mysql --init-command=&amp;quot;SET foreign_key_checks = 0;&amp;quot; database_name&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;set foreign_key_checks&lt;/code&gt; parameter to mysql, this is normally set at the top of your dump file, because we&amp;#8217;re truncating the front off the dump file, you need to disable foreign key checks explicitly.&lt;/p&gt;

&lt;h1 id='using_pipe_viewer'&gt;Using pipe viewer&lt;/h1&gt;

&lt;p&gt;&lt;a href='http://www.ivarch.com/programs/pv.shtml'&gt;PV&lt;/a&gt; is a tool to graph your progress. Instead of running &lt;code&gt;cat&lt;/code&gt; and hoping for the best, you get graphical feedback on how long your database restore process will take.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CSV Parser in CoffeeScript</title>
   <link href="http://bnolan.github.com/2011/10/24/csv-parser.html"/>
   <updated>2011-10-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/10/24/csv-parser</id>
   <content type="html">&lt;p&gt;I recently needed to be able to parse CSV export from excel, in Javascript. The only way I could find to parse it was a stream-oriented parser, so I came up with this that seems to cope with the majority of strangeness, including multiline cells, quotation marks, and escape and non-escaped cells.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s implemented in coffeescript:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class CSV
  constructor: (data) -&amp;gt;
    @raw = data

    @_parse(@raw)

  _parse: -&amp;gt;
    @rows = []
    row = []
    cell = &amp;quot;&amp;quot;

    offset = 0

    mode = CSV.RAW

    while offset &amp;lt; @raw.length
      ch = @raw.charAt(offset)
      adjacent = @raw.charAt(offset+1)

      if mode == CSV.RAW
        if ch == &amp;quot;,&amp;quot;
          row.push cell
          cell = &amp;quot;&amp;quot;
        else if ch == &amp;quot;\r&amp;quot;
          @rows.push row
          row = []
          cell = &amp;quot;&amp;quot;
        else if ch == &amp;quot;\&amp;quot;&amp;quot;
          mode = CSV.ESC
        else
          cell += ch

      else if mode == CSV.ESC
        if ch == &amp;quot;\&amp;quot;&amp;quot;
          if adjacent == &amp;quot;\&amp;quot;&amp;quot;
            cell += ch
            offset += 1
          else
            mode = CSV.RAW
        else
          cell += ch
      
      else
        throw &amp;quot;Invalid csv parser mode&amp;quot;
    
      offset += 1

    @rows
  
CSV.RAW = 1
CSV.ESC = 2

@CSV = CSV&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a good example of code which will block the browser in a big-time way. For example, if you tried to parse a one megabyte CSV file, you&amp;#8217;ll probably crash webkit mobile devices, and get script timeout errors in slower javascript implementations. Whoever, because all the looping logic is in a while, it&amp;#8217;d be straightforward to make the parser run inside a setInterval loop, and let the browser remain responsive.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Overscore.js</title>
   <link href="http://bnolan.github.com/2011/10/07/overscore.html"/>
   <updated>2011-10-07T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/10/07/overscore</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve extracted the non-blocking &lt;code&gt;.map&lt;/code&gt; and &lt;code&gt;.select&lt;/code&gt; implementation that I use in my mobile apps to keep them responsive while processing large arrays. I called it &lt;a href='http://github.com/bnolan/Overscore'&gt;overscore.js&lt;/a&gt; and it&amp;#8217;s available on github.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Javascript Mobile Apps - Tooling</title>
   <link href="http://bnolan.github.com/2011/09/25/tooling.html"/>
   <updated>2011-09-25T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/09/25/tooling</id>
   <content type="html">&lt;p&gt;As another part of my series on Javascript mobile apps, I&amp;#8217;m going to discuss tooling.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve listed my toolkit before, but here it is again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jQuery&lt;/li&gt;

&lt;li&gt;CoffeeScript&lt;/li&gt;

&lt;li&gt;Backbone.js&lt;/li&gt;

&lt;li&gt;&lt;a href='/capt/'&gt;Capt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id='jquery'&gt;jQuery&lt;/h1&gt;

&lt;p&gt;I use jQuery for the same reason everyone else does. It&amp;#8217;s well implemented, fast and fun to use. The well implemented part becomes important when you&amp;#8217;re dealing with fiddly implementation details of &lt;code&gt;$.ajax&lt;/code&gt; calls. Being able to set headers, read headers and hook the progress events of the ajax object is important to a good mobile app. I use etags when checking for updates in my apps, specifying headers in a convenient hash shorthand is the kind of small detail that jQuery covers so well.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$.ajax {
  url : &amp;quot;http://example.com/endpoint/&amp;quot;
  dataType : &amp;#39;json&amp;#39;
  timeout : 25000
  headers : { &amp;#39;If-None-Match&amp;#39; : localStorage.getItem(&amp;#39;etag&amp;#39;) }
}&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='coffeescript'&gt;CoffeeScript&lt;/h1&gt;

&lt;p&gt;There are pros and cons of Javascript. The biggest downside I see is that if you&amp;#8217;re working on projects that aren&amp;#8217;t 100% coffeescript, you&amp;#8217;re going to end up with ugliness. You either want to be able to convert all your code over to coffeescript (with the exception of 3rd party libraries), or you want to leave it all as javascript. Doing a combination is going to only cause heartbreak.&lt;/p&gt;

&lt;p&gt;If you are sold on CoffeeScript though, it&amp;#8217;s a fantastic tool. Using the fat arrow &lt;code&gt;=&amp;gt;&lt;/code&gt; to ensure class methods are called with the right &lt;code&gt;this&lt;/code&gt; scope is an awesome timesaver. The biggest problem with CoffeeScript is probably debugging. This was easier in older versions of the coffee compiler, which had a 1:1 line to line conversion ratio, so model.js:23 was the same as model.coffee:23. Now, unhappily, your line numbers won&amp;#8217;t match up, but as long as you can view the javascript output and find the error, you can easily work back and find out which line of coffeescript blew up on you.&lt;/p&gt;

&lt;h1 id='backbonejs'&gt;Backbone.js&lt;/h1&gt;

&lt;p&gt;If you want a reason why to use Backbone, just view the &lt;a href='http://documentcloud.github.com/backbone/#examples'&gt;apps using Backbone&lt;/a&gt; list on the backbone site. It&amp;#8217;s a fantastic small piece of kit. It adds events, collections and models in a sensible way that will be familiar to any rails developer, but it does it without trying to pervert Javascript.&lt;/p&gt;

&lt;p&gt;Basically, if you&amp;#8217;re recieving json data from an endpoint and displaying it using Javascript, you should be using backbone or something similar.&lt;/p&gt;

&lt;p&gt;I personally, used to make the mistake of trying to be ultra-minimal in my Javascript, avoiding doing heavy computation or having a lot of code over in the client. I&amp;#8217;ve changed my way over the past year or two. If you&amp;#8217;re struggling to do something without the correct tools, you&amp;#8217;re wasting time, and you&amp;#8217;ll probably end up with a half-assed solution. Refactor, break your code out into more classes, and increase your lines of code in Javascript.&lt;/p&gt;

&lt;h1 id='capt'&gt;Capt&lt;/h1&gt;

&lt;p&gt;This is my own tool, that I can&amp;#8217;t really recommend to anyone else at the moment, since it&amp;#8217;s a little bit half-assed and half-finished. But the important thing to do is to have a build tool that you can rely on. You want to be able to use .eco, .less, .coffee and .jst files easily, without having to compile them by hand, or having some makefile you run over and over. Find a build tool that watches your files, recompiles on the fly and includes each file seperately, so that when you get error messages, it&amp;#8217;s not just &lt;code&gt;error in bundled.js:31423423&lt;/code&gt;, which is going to be pleasantly impossible to debug.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;d be keen to hear what other developers use for their build tools.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Javascript Mobile Apps</title>
   <link href="http://bnolan.github.com/2011/09/24/javascript-mobile-apps.html"/>
   <updated>2011-09-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/09/24/javascript-mobile-apps</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve worked on three javascript mobile apps now, one used internally by Lonely Planet, one on the &lt;a href='http://itunes.apple.com/nz/app/rankers-app/id454894632?mt=8'&gt;appstore&lt;/a&gt;, and another an unreleased site I built myself. I&amp;#8217;ve been wanting to write up my notes on development for a while, so since it&amp;#8217;s a sunny day and the house is tidy, I&amp;#8217;ll put up some notes. First up&amp;#8230;&lt;/p&gt;

&lt;h1 id='reasoning'&gt;Reasoning&lt;/h1&gt;

&lt;p&gt;First up, why even use Javascript + XHTML to build your mobile apps? The obvious answer is to get cross-platform support out the box, a well written app will deploy on phonegap to android and iOS with no extra work. Another answer, which is easily dismissed, is the benefits of having a single tool that you can use across more than just your mobile app.&lt;/p&gt;

&lt;p&gt;Any business logic you encode in Javascript you can re-use for your desktop client and can be tested on the command line using node.js and &lt;a href='https://github.com/tmpvar/jsdom'&gt;jsdom&lt;/a&gt;. Where possible, one language is better than two in my book.&lt;/p&gt;

&lt;p&gt;Finally, by using javascript, you are free from the tyranny of app-stores. I&amp;#8217;ve had apps initially rejected by the appstore, and although they were easily resubmitted and are now selling well, if you&amp;#8217;re doing anything &amp;#8220;fringe&amp;#8221;, that may run afoul of the appstore, having the option to deploy your app over the web as an html5 app is a nice fallback.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Using the new static streetview api</title>
   <link href="http://bnolan.github.com/2011/09/19/using-postgis-and-static-maps.html"/>
   <updated>2011-09-19T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/09/19/using-postgis-and-static-maps</id>
   <content type="html">&lt;p&gt;So, Google just released a &lt;a href='http://googlegeodevelopers.blogspot.com/2011/09/quick-and-simple-street-view-with.html'&gt;static street view api&lt;/a&gt;, which is awesome, since showing a streetview of a place will usually jog someones memory much quicker than a top down view.&lt;/p&gt;

&lt;p&gt;The only problem with the API (and it may be fixed in a future revision), is that you need to specify the heading that you want the returned image to be facing. This is a problem, since usually you only have the lat long of the place that you are visualizing, and not the bearing from the nearest road that a google streetview car drove along.&lt;/p&gt;

&lt;p&gt;However - in my case, I have a complete set of OpenStreetMap data in my places database, so I could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look for the nearest street&lt;/li&gt;

&lt;li&gt;Calculate the nearest point on the street&lt;/li&gt;

&lt;li&gt;Get the azimuth angle between the nearest point and the destination place&lt;/li&gt;

&lt;li&gt;Convert radians to degrees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And get the correct street view images. See this &lt;a href='http://nz.geonear.com/places/search?q=curry'&gt;search for curry&lt;/a&gt; on Geonear to see what I mean.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the code I used (rails code using postgis):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;%= image_tag &amp;quot;.../streetview
  ?location=#{place.latitude},#{place.longitude}
  &amp;amp;size=280x200
  &amp;amp;pitch=15
  &amp;amp;fov=65
  &amp;amp;heading=#{place.street_view_heading}
  &amp;amp;sensor=false&amp;quot; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And in &lt;code&gt;place.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def street_view_heading
  street = nearest_street
  
  point = Place.find_by_sql([&amp;#39;select st_closestpoint(?, ?) as geometry&amp;#39;, street.geometry, self.geometry])
    .first
    .geometry
  
  (Street.find_by_sql([&amp;#39;select st_azimuth(?, ?) as azimuth&amp;#39;, point, self.geometry])
    .first
    .azimuth
    .to_f * 180 / 3.14159).floor
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And we&amp;#8217;re away. Very nice, thanks Google. :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Lerping LatLngs</title>
   <link href="http://bnolan.github.com/2011/08/24/lerp-latlng.html"/>
   <updated>2011-08-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/24/lerp-latlng</id>
   <content type="html">&lt;p&gt;I needed some code for lerping google maps latlongs (for providing a custom streetview navigator). Here&amp;#8217;s the function in coffeescript:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;google.maps.LatLng.prototype.lerp = (b, i) -&amp;gt;
  lat = (b.lat() - @lat()) * i + @lat()
  lng = (b.lng() - @lng()) * i + @lng()&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Etags, Phonegap and Rails</title>
   <link href="http://bnolan.github.com/2011/08/23/etags-phonegap-and-rails.html"/>
   <updated>2011-08-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/23/etags-phonegap-and-rails</id>
   <content type="html">&lt;p&gt;In the &lt;a href='http://www.rankers.co.nz/'&gt;rankers app&lt;/a&gt; that I&amp;#8217;ve recently finished for a client, I cached the users data offline, but needed a way to quickly and easy to see if the user had the freshed version of the data.&lt;/p&gt;
&lt;img src='/images/rankers-updates.png' /&gt;&lt;cite&gt;Downloading database updates&lt;/cite&gt;
&lt;p&gt;To speed up loading time, and enable offline access, I download the list of places (about 350kb) by an ajax call, and then cache the json and the etag of the latest revision in &lt;code&gt;localStorage&lt;/code&gt;. Then when the app launches next time, I send a request for the newest version of the places list, and attach the etag to the request, so that rails can send a not-modified response, and save the users some data.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the rails pseudocode code I used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@places = Proc.new do 
  Place.find(:all)
end

response.etag = @etag = [
  Place.find(:first, :order =&amp;gt; &amp;#39;updated_at desc&amp;#39;).updated_at.to_i,
  Place.count
]

if request.fresh?(response)
   head :not_modified
else
  render :action =&amp;gt; &amp;#39;index&amp;#39;, :mime_type =&amp;gt; &amp;#39;application/json&amp;#39;
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And in the view:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% cache(@etag) do %&amp;gt;&amp;lt;%= @places.call.to_json %&amp;gt;&amp;lt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This cached the json (since json generation can be pretty slow in ruby), and sends the appropriate header. To handle this on the client side, I used something like this, to cache the places data, and the etag.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$.ajax {
  url : &amp;quot;http://example.com/some/endpoint&amp;quot;
  dataType : &amp;#39;json&amp;#39;
  headers : { &amp;#39;If-None-Match&amp;#39; : localStorage.getItem(&amp;#39;etag&amp;#39;) }
  success : (data, textStatus, xhr) =&amp;gt;
    if textStatus == &amp;quot;success&amp;quot;
      localStorage.setItem(&amp;#39;etag&amp;#39;, xhr.getResponseHeader(&amp;#39;Etag&amp;#39;))
      localStorage.setItem(&amp;#39;placesData&amp;#39;, JSON.stringify(data))
    else if textStatus == &amp;quot;notmodified&amp;quot;
      data = JSON.parse(localStorage.getItem(&amp;#39;placesData&amp;#39;))
    else
      throw &amp;quot;your toys&amp;quot;

    Places.reset(data)
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I was going to implement my own version of etags and &lt;code&gt;if-none-match&lt;/code&gt;, since I thought I might get heisenbugs with different implementations of xmlhttprequest on different mobile webkits, but in the end, I decided not to reinvent the wheel and use what already exists. So far this has worked well.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Detecting phonegap</title>
   <link href="http://bnolan.github.com/2011/08/22/phonegap-detection.html"/>
   <updated>2011-08-22T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/22/phonegap-detection</id>
   <content type="html">&lt;p&gt;With my capt apps, I do most of the development and testing using the desktop safari browser, and then move onto testing on actual devices later on, once I&amp;#8217;ve got the app mostly working. I use this fragment of code to detect if I&amp;#8217;m running inside phonegap, or if it&amp;#8217;s a desktop browser, and then instantiate my app appropriately.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function onDeviceReady(){
  window.app = new Application;
  app.start();
}

if(window.PhoneGap){
    document.addEventListener(&amp;quot;deviceready&amp;quot;,onDeviceReady,false);
}else{
  $(document).ready(function(){
    onDeviceReady();
  });
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The window.app style of encapsulating my apps has worked well for me in apps I&amp;#8217;ve built using &lt;code&gt;capt&lt;/code&gt; and &lt;code&gt;backbone&lt;/code&gt;, I still haven&amp;#8217;t got to the point of encapsulating everything (all classes are copied into the window scope for example).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Duplication detection with postgis</title>
   <link href="http://bnolan.github.com/2011/08/20/duplication-postgis.html"/>
   <updated>2011-08-20T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/20/duplication-postgis</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve written a particularly gnarly query here that I thought I would share. It&amp;#8217;s for iterating over a collection of points that have names, and identifying points that likely candidates for merging.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select
  name, floor(length(ST_ExteriorRing(st_box2d(st_extent(geometry)))) * 1000000) as length, count(id)
from
  places
group by
  name
order by 
  count desc;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basically, it selects places with similair names, and returns the length of the bounding box surrounding those places. You can use this as a basic test to see if those places should be merged. There a tonne of situations in which this won&amp;#8217;t work, but to get you out the gate, it might be helpful.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Google doesn't get the web</title>
   <link href="http://bnolan.github.com/2011/08/19/google-doesnt-get-the-web.html"/>
   <updated>2011-08-19T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/19/google-doesnt-get-the-web</id>
   <content type="html">&lt;p&gt;It must drive the google search team crazy, when they look at the sort of html the rest of the google organisation spits out. Take for example - this &lt;a href='http://maps.google.com/maps/place?cid=3923961084232206133'&gt;google places&lt;/a&gt; page. There is no html, no metadata, no microformats, no schema.org support. It&amp;#8217;s basically impossible to index. How can they run the worlds biggest web crawler, but generate such obtuse and impossible to index code themselves? It&amp;#8217;s astounding I say!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Phonegap</title>
   <link href="http://bnolan.github.com/2011/08/15/phonegap.html"/>
   <updated>2011-08-15T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/08/15/phonegap</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve got two apps on the go using Phonegap, and this is just a quick post to say that I can highly recommend the mobile web as a development platform. My list of tools / libraries that I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Capt for building the project and compiling / watching intermediate languages&lt;/li&gt;

&lt;li&gt;LESS.js for css&lt;/li&gt;

&lt;li&gt;Coffeescript&lt;/li&gt;

&lt;li&gt;Backbone.js&lt;/li&gt;

&lt;li&gt;Underscore.js&lt;/li&gt;

&lt;li&gt;My responsive map/reduce underscore.js helpers (yet to be released)&lt;/li&gt;

&lt;li&gt;Leaflet for touch-based maps that are GPU accelerated&lt;/li&gt;

&lt;li&gt;JSON.js from douglas crockford&lt;/li&gt;

&lt;li&gt;jQuery, although I may move to using zepto later on&lt;/li&gt;

&lt;li&gt;Phonegap for deploying to Android and iPhone&lt;/li&gt;

&lt;li&gt;Makefile for packaging and bundling&lt;/li&gt;

&lt;li&gt;Jasmine for speccing&lt;/li&gt;

&lt;li&gt;Latlon.js for distance and bearing functions&lt;/li&gt;

&lt;li&gt;iScroll.js for fixed position headers and footers&lt;/li&gt;

&lt;li&gt;Cross-origin ajax requests to allow local development while accessing remote servers&lt;/li&gt;

&lt;li&gt;ECO templates by Sam Stephenson for in-app rendering&lt;/li&gt;

&lt;li&gt;JST templates from underscore.js for static html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It&amp;#8217;s a pretty nice toolkit. I need to do some more work on capt and put up a sample app so that other people can use my toolkit, but yeah, coffeescript, backbone and less.js are a great way to build mobile apps.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Payroll</title>
   <link href="http://bnolan.github.com/2011/07/28/payroll.html"/>
   <updated>2011-07-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/07/28/payroll</id>
   <content type="html">&lt;p&gt;When you&amp;#8217;re using &lt;a href='http://xero.com/'&gt;xero&lt;/a&gt; and &lt;a href='http://minutedock.com/'&gt;minutedock&lt;/a&gt;, you get used to having nice quality tools. It&amp;#8217;s like having chisels that were shaped by &lt;a href='http://twitter.com/storminwalker'&gt;master&lt;/a&gt; &lt;a href='http://twitter.com/nikz/'&gt;craftsmen&lt;/a&gt;. And then there&amp;#8217;s your payroll package&amp;#8230;&lt;/p&gt;

&lt;h1 id='payroll'&gt;Payroll?&lt;/h1&gt;

&lt;p&gt;Payroll is the software that takes money from my company account, pays the tax man, deducts my taxes as an employee, then pays me in my personal account.&lt;/p&gt;

&lt;h1 id='ipayroll'&gt;iPayroll&lt;/h1&gt;
&lt;img src='/images/payroll-ipayroll.png' /&gt;
&lt;p&gt;I&amp;#8217;ve always used iPayroll. Giles Crisp is a great contact there (tell him Ben sent you), and provides great service. With iPayroll, you authorize them to move the money around and they get access to your company bank accounts. You will be paid every Tuesday without having to lift a finger. Plus it does all sort of HR stuff as well, so if you have employees, you can know know how many days off they should have.&lt;/p&gt;

&lt;p&gt;Anyway - Ipayroll is great, but it&amp;#8217;s kinda funky looking, and trying to sign up just recently has been a real PITA. Bugs a plenty with the sign-up process.&lt;/p&gt;

&lt;p&gt;So I went to the xero &lt;a href='http://www.xero.com/advisors/solutions/payroll/'&gt;payroll providers page&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='smart_payroll'&gt;&lt;a href='http://www.smartpayroll.co.nz/'&gt;Smart Payroll&lt;/a&gt;&lt;/h2&gt;
&lt;img src='/images/payroll-smart.png' /&gt;
&lt;p&gt;Looks awesome. Until you actually look at the screenshots of the real app, not the pretty marketing page. It looks like it was designed in 1901. It makes iPayroll look a perfectly executed piece of modern art. Pass.&lt;/p&gt;

&lt;h2 id='flexitime'&gt;&lt;a href='http://flexitime.co.nz/'&gt;Flexitime&lt;/a&gt;&lt;/h2&gt;
&lt;img src='/images/payroll-flexitime.png' /&gt;
&lt;p&gt;Looks awesome. The app is very xero / minutedock-ish, so I rang them up on their 0800 number and asked:&lt;/p&gt;

&lt;p&gt;&amp;#8220;Can I pay you money to take money from my account and move the money around?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Err - no sorry&amp;#8221;&lt;/p&gt;

&lt;p&gt;The Flexitime guy told me what I&amp;#8217;d have to do to use flexitime to satisfy my obligations as an employer. Basically, set up an automatic payment, modify the AP as necessary, update flexitime, and remember to log into IRD once a month and upload a report that I download from the flexitime site. That&amp;#8217;s a lot of remembering.&lt;/p&gt;

&lt;p&gt;If Flexitime had put a &amp;#8216;we manage everything&amp;#8217; option on their website with a nice CSS3 button for me to press and a well form that let me set up my organisation, I probably would have chosen them as my payroll provider. Oh well, back to iPayroll.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Map Reduce in Javascript</title>
   <link href="http://bnolan.github.com/2011/07/27/map-reduce.html"/>
   <updated>2011-07-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/07/27/map-reduce</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s the non-blocking map reduce class that I was talking about. It uses at most 75% of the CPU, so that the browser remains responsive while your job is processed. You can destroy the job at any stage.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class MapReduceJob
  constructor: (inputsOriginal, mapFunc, reduceFunc) -&amp;gt;
    utilisation = 75
    inputs = inputsOriginal.slice()

    # todo - replace with a better clone function
    inputs = for input in inputsOriginal
      input

    outputs = []

    @interval = setInterval( =&amp;gt;
      tzero = (new Date).getTime()
  
      # Process at least one
      if inputs.length &amp;gt; 0
        outputs.push mapFunc(inputs.pop())

      # Process more
      while ((new Date).getTime() - tzero &amp;lt; utilisation) and (inputs.length &amp;gt; 0)
        outputs.push mapFunc(inputs.pop())
  
      if inputs.length == 0
        clearInterval(@interval)
        reduceFunc(outputs)
    
    , 100)

  destroy: -&amp;gt;
    clearInterval(@interval)
    delete @interval&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You use it like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;new MapReduceJob(
  [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;, &amp;#39;d&amp;#39;],
  function(input){
    // do something computationally expensive here, like uppercasing the input
    return input.toUpperCase();
  },
  function(outputs){
    console.log(outputs);
  }
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is excellent for things like clustering markers on a map, or doing a backbone filtering on large collections. You need to structure your code to be asyncronous.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve got a few things I might do with this code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Port underscore.js to this continuations style, so that you can use all the existing functions. I&amp;#8217;ve already ported the &lt;code&gt;collect&lt;/code&gt; and &lt;code&gt;inject&lt;/code&gt; functions.&lt;/li&gt;

&lt;li&gt;Add a progress() method to the class.&lt;/li&gt;

&lt;li&gt;Add support for webworkers for desktop browsers.&lt;/li&gt;

&lt;li&gt;Port backbone.js to use these continuations, so that for example, the sort function doesn&amp;#8217;t block when sorting large arrays.&lt;/li&gt;

&lt;li&gt;Assuming the mapFunction is constant time, measure the number of inputs to process per interval, then stop checking the date function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;#8217;s pretty interesting stuff, we&amp;#8217;ll see how we go.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CORS, Rails and Weinre</title>
   <link href="http://bnolan.github.com/2011/07/26/thank-me-later.html"/>
   <updated>2011-07-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/07/26/thank-me-later</id>
   <content type="html">&lt;p&gt;Doing mobile development on your Android but can&amp;#8217;t get any debugging action going? Add this code (from the inimitable &lt;a href='http://www.tsheffler.com/blog/?p=428'&gt;Tom Shelfer&lt;/a&gt;) to the rails controller that provides your json views, so that you can serve your app on a different port than you serve your API:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers

protected

# For all responses in this controller, return the CORS access control headers.
def cors_set_access_control_headers
  headers[&amp;#39;Access-Control-Allow-Origin&amp;#39;] = &amp;#39;*&amp;#39;
  headers[&amp;#39;Access-Control-Allow-Methods&amp;#39;] = &amp;#39;POST, GET, OPTIONS&amp;#39;
  headers[&amp;#39;Access-Control-Max-Age&amp;#39;] = &amp;quot;1728000&amp;quot;
end

# If this is a preflight OPTIONS request, then short-circuit the
# request, return only the necessary headers and return an empty
# text/plain.
def cors_preflight_check
  if request.method == :options
    headers[&amp;#39;Access-Control-Allow-Origin&amp;#39;] = &amp;#39;*&amp;#39;
    headers[&amp;#39;Access-Control-Allow-Methods&amp;#39;] = &amp;#39;POST, GET, OPTIONS&amp;#39;
    headers[&amp;#39;Access-Control-Allow-Headers&amp;#39;] = &amp;#39;X-Requested-With, X-Prototype-Version&amp;#39;
    headers[&amp;#39;Access-Control-Max-Age&amp;#39;] = &amp;#39;1728000&amp;#39;
    render :text =&amp;gt; &amp;#39;&amp;#39;, :content_type =&amp;gt; &amp;#39;text/plain&amp;#39;
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then install the MacOS version of &lt;a href='http://phonegap.github.com/weinre/'&gt;weinre&lt;/a&gt; and edit &lt;code&gt;Content/MacOS/Launcher&lt;/code&gt; like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;java \
    -XstartOnFirstThread \
    -classpath $BASEDIR/weinre-ui.jar:$BASEDIR/weinre.jar:$BASEDIR/swt.jar \
    weinre.application.GUIMain --boundHost -all-&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then launch weinre (webkit inspector for mobile devices), and add weinre to your web app and reload the browser.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;script src=&amp;quot;http://192.168.1.77:8080/target/target-script-min.js#anonymous&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Sorry this post isn&amp;#8217;t very cohesive - but that there is a fantastic stack for debugging standalone apps to access existing rails apps. I&amp;#8217;m using it to debug my phonegap version of the &lt;a href='http://rankers.co.nz/'&gt;rankers app&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Something expensive</title>
   <link href="http://bnolan.github.com/2011/07/26/something-expensive.html"/>
   <updated>2011-07-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/07/26/something-expensive</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m clustering 1200 points on the iphone in javascript in an app I&amp;#8217;m writing at the moment. On my iphone 2g it takes 1500ms in a worst case. There are two fixes I&amp;#8217;m going to do:&lt;/p&gt;

&lt;h1 id='quadtree'&gt;Quadtree&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ll probably end up implementing a quadtree, or a grid-based acceleration structure, since currently the complexity is currently n squared in a worst case. I&amp;#8217;ll let you know how I get on with this.&lt;/p&gt;

&lt;h1 id='break_something_expensive'&gt;Break something expensive&lt;/h1&gt;

&lt;p&gt;This is a generic pattern you can use in javascript (here implemented in coffeescript) to maintain responsiveness in your jobs. You create an interval that runs every 100ms, and it will do at most 50ms of work in each loop, until your data has been processed, then terminates the job.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;inputs = [.., .., .., ..]
outputs = []

interval = null

interval = setInterval( =&amp;gt;
  tzero = (new Date).getTime()

  while ((new Date).getTime() - tzero &amp;lt; 50) and (inputs.length &amp;gt; 0)
    input = inputs.pop()
    
    outputs.push(
      doSomethingExpensiveWith(input)
    )
    
  if inputs.length == 0
    clearInterval(interval)
    
    console.log(outputs)
, 100)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I might pull that code out into a generalised form (since I could use it throughout the app) and also add support for chaining inputs and outputs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;inputs.mapReduce(filterFunction).mapReduce(processFunction).mapReduce(outputFunction);&lt;/code&gt;&lt;/pre&gt;

&lt;dl&gt;
&lt;dt&gt;Something like that would be pretty cool, but the above code is the simplified version that works for me.&lt;/dt&gt;

&lt;dd&gt;
&lt;p&gt;)&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;</content>
 </entry>
 
 <entry>
   <title>Ajax download progress</title>
   <link href="http://bnolan.github.com/2011/07/21/ajax-download-progress.html"/>
   <updated>2011-07-21T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/07/21/ajax-download-progress</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m working on an iphone app that needs 650kb of json data to get started, so I needed a bit of progress display while the data is being fetched. This works on mobile webkit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;interval = null

$.ajax {
  url : &amp;quot;endpoint.json&amp;quot;

  dataType : &amp;#39;json&amp;#39;

  xhr : () =&amp;gt;
    xhr = jQuery.ajaxSettings.xhr()
  
    interval = setInterval( =&amp;gt;
      if xhr.readyState &amp;gt; 2
        total = parseInt(xhr.getResponseHeader(&amp;#39;Content-length&amp;#39;))
        completed = parseInt(xhr.responseText.length)
        percentage = (100.0 / total * completed).toFixed(2)
      
        console.log &amp;quot;Completed #{percentage}%&amp;quot;
    , 50)
  
    xhr

  complete: -&amp;gt;
    clearInterval(interval)
  
  success : (data) =&amp;gt;
    alert(data)
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s a bit painful because of the way you access the raw &lt;code&gt;xhr&lt;/code&gt; object in jQuery 1.5, but works nicely. I then store the data in localStorage (as a bit json blob) and we&amp;#8217;re away.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Wellington.js</title>
   <link href="http://bnolan.github.com/2011/06/27/wellington-js.html"/>
   <updated>2011-06-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/27/wellington-js</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ll be presenting at Wellington.js on the 13th of July about Backbone.js and my experiences with Capt, my javascript build tool.&lt;/p&gt;

&lt;p&gt;That is all.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Webkit Transform</title>
   <link href="http://bnolan.github.com/2011/06/26/webkit-transform.html"/>
   <updated>2011-06-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/26/webkit-transform</id>
   <content type="html">&lt;p&gt;I was quite taken with these &lt;a href='http://www.minecraftforum.net/topic/37409-mcmap-isometric-renders-sspsmp-18-support/'&gt;isometric minecraft renders&lt;/a&gt;, so I decided to dig out some of my old game code and try and build an isometric renderer&amp;#8230;&lt;/p&gt;
&lt;img src='/images/webkit-transform.png' /&gt;&lt;cite&gt;A little 3d world&lt;/cite&gt;
&lt;p&gt;That is created using webkit transforms, the minecraft textures. The heightmap is some perlin noise that I same via getImageData. Now to add some collision detection so you can walk around the world.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Disconnected Sundays</title>
   <link href="http://bnolan.github.com/2011/06/24/disconnected-sundays.html"/>
   <updated>2011-06-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/24/disconnected-sundays</id>
   <content type="html">&lt;p&gt;Four weeks on from my &lt;a href='http://bennolan.com/2011/06/11/disconnected-sundays.html'&gt;original post&lt;/a&gt;, I wanted to do a follow up about the &amp;#8220;Day of Disconnection&amp;#8221;.&lt;/p&gt;

&lt;p&gt;The &amp;#8220;day of disconnect&amp;#8221; is now one of my favourite things. I look forward to it all week. It&amp;#8217;s the day you don&amp;#8217;t get sucked into the computer, and you have no excuses to go outside and do all the wonderful things in the world. And when you don&amp;#8217;t feel like going out, you are &lt;em&gt;forced&lt;/em&gt; to go out and find something fun to do.&lt;/p&gt;

&lt;p&gt;My first Sunday was a day of drinking, but the following Sundays have been a lot more productive. Most recently, my partner and I drove up to the east cape of New Zealand in a little convertible and walked up to the easternmost lighthouse in the world. Another Sunday was spent exercising and collecting driftwood for a big bonfire out the back of the house, and I spent another Sunday doing some vigorous gardening.&lt;/p&gt;

&lt;p&gt;So - I recommend you try disconnected Sunday. It&amp;#8217;s a truly wonderful thing, and makes your Monday coffee + internet fix even better.&lt;/p&gt;

&lt;p&gt;At this rate I&amp;#8217;m going to end up making a nicely designed &lt;code&gt;sundaydisconnect.com&lt;/code&gt; site. Hah. :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Jasmine and Backbone</title>
   <link href="http://bnolan.github.com/2011/06/14/rspec-and-backbone.html"/>
   <updated>2011-06-14T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/14/rspec-and-backbone</id>
   <content type="html">&lt;p&gt;I use Jasmine to spec / test my Backbone apps. It can be a pain setting up a Javascript testing environment (unless you&amp;#8217;re using &lt;a href='/capt/'&gt;capt&lt;/a&gt; in which case you get a testing environment for free - but I digress. I decided to pull out some code from an existing app of mine and document a bit of it.&lt;/p&gt;

&lt;p&gt;This isn&amp;#8217;t best practise stuff, I&amp;#8217;m making this up as I go along, but it is the summary of several years of Javascript development on desktop and mobile.&lt;/p&gt;

&lt;p&gt;Start test suite:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;describe &amp;#39;places controller&amp;#39;, -&amp;gt;
  describe &amp;#39;search view&amp;#39;, -&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I like to nest my suites so that any errors point to the correct controller and view.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;beforeEach -&amp;gt;
  window.app = new Application
  window.app.location = { latitude : -45, longitude : 170}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;My current app has a bit of an awful hack in that it uses a global &amp;#8216;app&amp;#8217; instance that wraps up all the application functionality. It is easy to work with, but I don&amp;#8217;t like it for testing, since your tests inevitably have side effects. But by recreating a new &amp;#8216;app&amp;#8217; instance for each test you help defeat some of those side effects.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;#39;should handle the truth&amp;#39;, -&amp;gt;
  expect(true).toBeTruthy()
it &amp;#39;should exist&amp;#39;, -&amp;gt;
  expect(SearchView).toBeTruthy()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some sanity checks to make sure the view we&amp;#8217;re testing exists, there are no syntax or dependency problems.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;#39;should instantiate&amp;#39;, -&amp;gt;
  x = new SearchView { collection : new PlaceCollection }
  expect(x instanceof SearchView).toBeTruthy()
  expect(x instanceof Backbone.View).toBeTruthy()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we start to do something useful, by instantiating the SearchView. Notice that the view can be instantiated outside of the app, and without a specified element. Backbone will create it&amp;#8217;s own div element for the view.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;#39;should have render method&amp;#39;, -&amp;gt;
  x = new SearchView { collection : new PlaceCollection }
  x.render()
  expect(x.el).toBeTruthy()
  expect(x.el.find(&amp;#39;input&amp;#39;).is(&amp;#39;input&amp;#39;)).toBeTruthy()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can start to do some &amp;#8216;functional&amp;#8217; testing and make sure that the view renders up an input inside my view. This is where you can start to do some poke and prod testing, and make sure the result is as you expect it. Note that I&amp;#8217;m running my test suite inside safari, but which something like jsdom, you could run this test suite entirely inside node.js.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;#39;should render nearby&amp;#39;, -&amp;gt;
  x = new SearchView { collection : new PlaceCollection }
  x.collection.refresh $fixtures.placesNearby
  x.collection.status = 200
  x.render()
  expect(x.el.html()).toMatch /harvard square/i&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I use capt to populate my $fixtures object, so I can edit my fixture data in yaml or json, and then poke it into the view and check it renders correctly. This is the weakest selector I could use. Something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;expect(x.$(&amp;#39;a:first&amp;#39;)).toMatch /harvard square/i&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Might be better, or using the :content selector.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;#39;should render searching&amp;#39;, -&amp;gt;
  x = new SearchView { collection : new PlaceCollection }
  x.render()
  x.el.find(&amp;#39;input&amp;#39;).val(&amp;quot;Kirkla&amp;quot;).trigger(&amp;#39;keyup&amp;#39;)
  expect(x.query).toEqual(&amp;quot;Kirkla&amp;quot;)
  expect(x.el.html()).toMatch /loading.../i&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also trigger keyUp / keyDown and other events using jQuery &lt;a href='http://api.jquery.com/category/events/event-object/'&gt;event object&lt;/a&gt;. Note that in my case, this will trigger an ajax call to the server, which must be mocked out on the client so that the ajax call returns immediately and fires the success callback. I use the built in mocking support (spyOn) that comes with Jasmine for mocking.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Travelling</title>
   <link href="http://bnolan.github.com/2011/06/13/travelling.html"/>
   <updated>2011-06-13T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/13/travelling</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m writing this post from the above the wing of a 18 seater twinprop plane, with the sun going down to my left, setting over mount ruapehu, which looks to be getting a good coating of powder for this years ski season.&lt;/p&gt;

&lt;p&gt;Last month I decided to put my German trip on indefinite hiatus, and I&amp;#8217;m going to be honest, it was a hard decision. But now four weeks later and I&amp;#8217;m starting to enjoy this life. I&amp;#8217;m living in a lovely beach house with some good guys. Travelling to Wellington city regularly to get a fix of friends, tech and cafe culture. I&amp;#8217;ve been working with a great group of hackers based in Soho, London - apart from the early it&amp;#8217;s an excellent way to work.&lt;/p&gt;

&lt;p&gt;The next few months aren&amp;#8217;t planned out, but I know I&amp;#8217;ll be in Wellington for some of July, house-sitting my sisters lovely new house in Newtown, and I expect there&amp;#8217;ll be a mission down to the Southern Island - assuming it&amp;#8217;s still there after this newest round of earthquakes :(. Finally, my accountant reviewed my situation and helped me set a goal for the next two years, so maybe I&amp;#8217;ll be about to get a piece of dirt to call my own in a year or two.&lt;/p&gt;

&lt;p&gt;Anyway - hope everyone is healthy and happy and not persuing their dreams at the cost of their friendships.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Disconnected Sundays</title>
   <link href="http://bnolan.github.com/2011/06/11/disconnected-sundays.html"/>
   <updated>2011-06-11T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/11/disconnected-sundays</id>
   <content type="html">&lt;p&gt;Nick at &lt;a href='http://rankers.co.nz/respect/'&gt;Rankers&lt;/a&gt; turned me onto a new movement. It&amp;#8217;s disconnected Sundays. I&amp;#8217;ve raised it with Sam Minnee from &lt;a href='http://silverstripe.com/'&gt;Silverstripe&lt;/a&gt;. The goal is to not do any work, or to use the web on Sundays.&lt;/p&gt;

&lt;p&gt;Basically, avoid using your computer or iphone at all costs. It freaked me out the first Sunday - what am I going to do to entertain myself? Obviously you can just read books. Or if you feel the need to work on your project you can draw your UI plans with pen and paper - but whatever you do, as long as you&amp;#8217;re away from the computer, it&amp;#8217;s guaranteed to be a good day, and you&amp;#8217;ll come back extra charged up for Monday.&lt;/p&gt;

&lt;p&gt;Anyway - so here&amp;#8217;s to being unavailable on Sundays and spending it with friends, or with your mountain bike, or working on the garden, maybe jamming in the back yard with some guitars and a drumkit.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Backbone - get or fetch</title>
   <link href="http://bnolan.github.com/2011/06/10/backbone-get-or-fetch.html"/>
   <updated>2011-06-10T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/10/backbone-get-or-fetch</id>
   <content type="html">&lt;p&gt;A common mistake people make in Backbone apps, is writing a view that assumes that data exists in a collection, so that when the user reloads the page, the collection is empty and the view won&amp;#8217;t render.&lt;/p&gt;

&lt;p&gt;For example, you have a Posts collection and a controller:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Posts extends Backbone.collection
  # ...
  
class PostsController extends Backbone.Controller
  routes :
    &amp;quot;&amp;quot; : &amp;quot;index&amp;quot;
    &amp;quot;topics/:id&amp;quot; : &amp;quot;show&amp;quot;

  index: -&amp;gt;
    Posts.refresh {
      success: -&amp;gt;
        new PostsView { el : $(body), collection : Posts }
    }

  show: (id) -&amp;gt;
    new PostsShowView { el : $(body), model : Posts.get(id) }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The problem with this, is that when you reload the page and you access the index view, it fetches the data with refresh(), then waits until the posts collection has been fetched and renders the view. (This is a bit of a contrived example, but it demonstrates the behaviour).&lt;/p&gt;

&lt;p&gt;After the collection has been populated, you click on a post, and it redirects to #posts/12345, a post id that is in the collection. All good.&lt;/p&gt;

&lt;p&gt;The problem is when you hit command-r and reload &lt;code&gt;localhost:3000/#posts/12345&lt;/code&gt;. The show view will be called straight away, and the posts collection was never populated.&lt;/p&gt;

&lt;h1 id='getorfetch'&gt;GetOrFetch&lt;/h1&gt;

&lt;p&gt;I like to fix this with a little helper called getOrFetch:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Posts extends Backbone.collection
  url: &amp;quot;/posts&amp;quot;
    
  getOrFetch: (id) -&amp;gt;
    if @get(id)
      post = @get id
    else
      post = new Post { id : id }
      @add post
      post.fetch()

    post&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;#8217;s be honest, this isn&amp;#8217;t magic, but it means you can replace your show action with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;show: (id) -&amp;gt;
  new PostsShowView { el : $(body), model : Posts.getOrFetch(id) }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which means that no matter how you get to the show action, your model will be loaded from the server, or just use the local version.&lt;/p&gt;

&lt;h1 id='status'&gt;Status&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve taken to using http status codes to represent what the status of a model is. For example a model that has been initialized but not loaded is status 0, if it is being loaded it is status 100, if it is loaded it is 200, if there was an error or the id was not found, 500 or 404, etc. This means that your view can have some code like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;% if model.status &amp;lt;= 200: %&amp;gt;
  Loading...
&amp;lt;% else: %&amp;gt;
  &amp;lt;%= model.escape &amp;#39;name&amp;#39; %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Doing this in the mobile app I&amp;#8217;m working on at the moment gives a nice ios-ish interface. To make your model status update:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;getOrFetch: (id) -&amp;gt;
  if @get(id)
    post = @get id
  else
    post = new Post { id : id }
    @add post
    post.fetch {
      success : -&amp;gt;
        post.status = 200
        post.trigger &amp;#39;changed&amp;#39;
      error : (e) -&amp;gt;
        post.status = 500
        post.trigger &amp;#39;changed&amp;#39;
    }

  post&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Sunset view</title>
   <link href="http://bnolan.github.com/2011/06/06/sunset-view.html"/>
   <updated>2011-06-06T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/06/sunset-view</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve moved out to the east coast of New Zealand to work onsite with a &lt;a href='http://rankers.co.nz/'&gt;client&lt;/a&gt;. I&amp;#8217;ve been gardening, programming, brainstorming, prototyping, surfing, swimming and mountain biking. It&amp;#8217;s been a nice time.&lt;/p&gt;
&lt;img src='/images/view-out-window.jpg' /&gt;&lt;cite&gt;View out the window from the office&lt;/cite&gt;
&lt;p&gt;I&amp;#8217;ll probably be in Wellington for the month of July, but apart from that I&amp;#8217;m free to move around. If you have any interesting Javascript work on later in the year, I&amp;#8217;d be keen to do a 2-3 month stint onsite. Anywhere in the world is fine.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Offline Mapping in HTML5</title>
   <link href="http://bnolan.github.com/2011/06/03/offline-mapping.html"/>
   <updated>2011-06-03T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/06/03/offline-mapping</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been doing some research and development around offline mapping for a client of mine. Here&amp;#8217;s my notes on the current state of technology.&lt;/p&gt;

&lt;h1 id='tile_based_offline_mapping'&gt;Tile based offline mapping&lt;/h1&gt;

&lt;p&gt;The easiest way to do offline mapping is to use something like openlayers and store tiles offline. This is kind of gross at first glance, but in practise it works well. It&amp;#8217;s very simple, the technology is mature, and above a certain zoom level, it can actually be smaller to store the raster data than the underlying unprocessed vector data. However, it clearly doesn&amp;#8217;t work for high zoom levels.&lt;/p&gt;

&lt;p&gt;To map an area the size of New Zealand using offline tile caching to zoom level 15, a naive implementation would take about 25 gigabytes of storage. With a little development you could probably get it down to 1-2gb, and with some serious development (adaptive zoom levels based on feature detection in the underlying vector data) you could maybe get to a ~200mb download, but it&amp;#8217;s clearly not a trivial download.&lt;/p&gt;

&lt;p&gt;However - this isn&amp;#8217;t such a big problem if you&amp;#8217;re doing a small area like a city or a town, So - assuming you don&amp;#8217;t need ultra-high zoom levels, and you can solve the issues of download size, what technology exists to do offline mapping?&lt;/p&gt;

&lt;h1 id='delivering_offline_maps'&gt;Delivering offline maps&lt;/h1&gt;

&lt;p&gt;The team at &lt;a href='http://mapbox.com/'&gt;mapbox&lt;/a&gt; have created a suite of tools for offline mapping. Maps on a stick is an interesting tool that uses openlayers, firefox and html5 to create an offline mapping tool. It is written in javascript, and requires that you download the map tiles and store them on your local filesystem. The downside to this is that copying over 800,000 5kB tiles takes approximately forever. To solve this issue on their ipad app, Mapbox created the &lt;a href='http://mbtiles.org/'&gt;mbtiles&lt;/a&gt; format, which is involves putting all the maptiles into a sqlite database that modern filesystems can move around much easier.&lt;/p&gt;

&lt;p&gt;Sadly, maps on a stick doesn&amp;#8217;t support mbtiles, so I looked into what would be involved in adding mbtiles support to maps on a stick. Basically, it boils down to creating a firefox xpcom component (in javascript) that uses the firefox sqlite interface to expose the tiles to openlayers. It&amp;#8217;s doable, but fiddly.&lt;/p&gt;

&lt;p&gt;On the plus side, you could then wrap up maps on a stick, your mbtiles components and xulrunner to create an installable offline mapping tool. From my experiments with xulrunner and reading through the xpcom documentation, this is non-trivial.&lt;/p&gt;

&lt;h1 id='chrome_store'&gt;Chrome store?&lt;/h1&gt;

&lt;p&gt;You could just shortcut all the xulrunner / xpcom stuff and do your offline apps using the chrome app store, or safari html5 offline support. I prototyped this and made a phonegap-powered ipad app that downloaded tiles from &lt;a href='http://cloudmade.com/'&gt;cloudmade&lt;/a&gt; and stored them in the html5 web database store. The downside to this is downloading the tiles is sloooww, and although you can do multiple requests at once using multiple subdomains, you still get slower throughput than if all the tiles were globbed together into one sqlite database.&lt;/p&gt;

&lt;h1 id='vector_data_and_c'&gt;Vector data and C++&lt;/h1&gt;

&lt;p&gt;The best solution, if you were keen to do some serious development, would be to bust out your compiler and package up mapnik or another renderer to act as an xpcom component for firefox. You could still serve tiles, so you could use openlayers (or tile5 or leaflet), and you would have infinite zoom, nice small vector data (the OSM dataset for New Zealand is about 25mB) and you would win all the technical brownie points.&lt;/p&gt;

&lt;p&gt;Down this path also lies writing your UI in QT (ala Google Earth) or WX instead of using Firefox, so you could create a completely custom mapping tool.&lt;/p&gt;

&lt;h1 id='analysis'&gt;Analysis&lt;/h1&gt;

&lt;p&gt;I haven&amp;#8217;t finalized my decision yet, but it seems to me that there are no natural inflection points on the cost/benefit graph for offline mapping. If anything, I might lean towards xulrunner + something like &amp;#8220;maps on a stick&amp;#8221;, but it&amp;#8217;s neither here nor there.&lt;/p&gt;

&lt;p&gt;Basically, there are no good offline mapping solutions for netbooks / laptops, so maybe there&amp;#8217;s a market niche there.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Hutch - tile-based game engine</title>
   <link href="http://bnolan.github.com/2011/05/30/hutch.html"/>
   <updated>2011-05-30T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/30/hutch</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve opensourced the repository holding my &lt;a href='https://github.com/bnolan/island'&gt;tile-based game engine&lt;/a&gt;. I worked pretty solidly on it for about two months (and put a bunch of videos up at &lt;a href='http://reddit.com/r/hutch/'&gt;reddit.com/r/hutch/&lt;/a&gt;), but it&amp;#8217;s become a back-burnered project, so I&amp;#8217;ve donated it to the html5 gamedev community.&lt;/p&gt;

&lt;p&gt;The game was written before i developed capt, so all the code is located in &lt;a href='https://github.com/bnolan/island/tree/master/public/scripts'&gt;public/scripts/&lt;/a&gt; and hosted by rails. It&amp;#8217;s designed to work with the &lt;a href='http://www.lostgarden.com/2007/05/cutegod-prototyping-challenge.html'&gt;cutegod&lt;/a&gt; tiles, and it&amp;#8217;s probably a real PITA to get the thing set-up and running. I&amp;#8217;d like to extract the coffeescript source and convert it into a capt project, so that it&amp;#8217;d be easier for people to get the source up and running (and also start adding specs for everything), but don&amp;#8217;t hold your breath on that one.&lt;/p&gt;

&lt;h1 id='orthographic_3d'&gt;Orthographic 3d&lt;/h1&gt;

&lt;p&gt;The projection is orthographic, with y and z sharing the same axis (depth is faked using the z-index). The engine is designed in 3d, so positions are expressed as &lt;a href='https://github.com/bnolan/island/blob/master/public/scripts/models/vector.coffee'&gt;3-vectors&lt;/a&gt;. Collision detection is done in the &lt;a href='https://github.com/bnolan/island/blob/master/public/scripts/models/player.coffee'&gt;player model&lt;/a&gt; - if I started work on this again, I&amp;#8217;d probably go for an architecture where classes have components, instead of a o-o big hierachy tree.&lt;/p&gt;

&lt;h1 id='multiplayer'&gt;Multiplayer&lt;/h1&gt;

&lt;p&gt;There is some &lt;a href='https://github.com/bnolan/island/blob/master/lib/socket_connection.rb'&gt;websocket multiplayer&lt;/a&gt; support in the game. The ruby-based server was basically just to prototype and experiment with realtime multiplayer in the browser. In practise I&amp;#8217;d probably use a node-based server so that you didn&amp;#8217;t have to duplicate code from coffeescript to ruby (for example the vector class, player class, etc, etc).&lt;/p&gt;

&lt;h1 id='future'&gt;Future&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m still very interested in multiplayer games in the browser. I&amp;#8217;d love to build something like minecraft, second life or terrarium, where it&amp;#8217;s basically a sandbox for people to build worlds and gadgets for other people to explore - but it&amp;#8217;s obviously a massive project, and if I did more work on html5-gaming, it&amp;#8217;d probably be as part of a team.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Capt Tutorial</title>
   <link href="http://bnolan.github.com/2011/05/27/capt-tutorial.html"/>
   <updated>2011-05-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/27/capt-tutorial</id>
   <content type="html">&lt;p&gt;I got halfway through a tutorial on &lt;a href='/capt/'&gt;capt&lt;/a&gt;, my build tool for single page javascript applications using coffeescript, backbone.js, eco and less. The tutorial is available &lt;a href='/capt/tutorial.html'&gt;here&lt;/a&gt;, but it kind of stops halfway down. Feel free to fork the tutorial on github and submit patches, otherwise I&amp;#8217;ll finish it up when I have time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Wellywood</title>
   <link href="http://bnolan.github.com/2011/05/26/wellywood.html"/>
   <updated>2011-05-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/26/wellywood</id>
   <content type="html">&lt;p&gt;I joined the Greens party in the afternoon, met the leadership in the evening and then was interviewed by the film crew at the backbencher - because I support the Wellywood sign. Video below. It was a fun night.&lt;/p&gt;
&lt;iframe src='http://www.youtube.com/embed/UFlYBjdTHCM' allowfullscreen='true' frameborder='0' height='240' width='340'&gt;&amp;nbsp;&lt;/iframe&gt;</content>
 </entry>
 
 <entry>
   <title>Breakfast or lunch?</title>
   <link href="http://bnolan.github.com/2011/05/25/breakfast-or-lunch.html"/>
   <updated>2011-05-25T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/25/breakfast-or-lunch</id>
   <content type="html">&lt;p&gt;I give you a time of day, you give me a name for the appropriate meal. I was trying to work out how to do this with a case / switch statement - then came across this syntax which is kinda nice:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def time_of_day_to_meal_name(t = Time.now)
   {
     0..5 =&amp;gt; &amp;#39;Midnight snack&amp;#39;,
     6..10 =&amp;gt; &amp;#39;Breakfast&amp;#39;,
     11..14 =&amp;gt; &amp;#39;Lunch&amp;#39;,
     15..16 =&amp;gt; &amp;#39;Afternoon tea&amp;#39;,
     17..21 =&amp;gt; &amp;#39;Dinner&amp;#39;,
     22..24 =&amp;gt; &amp;#39;Late night snack&amp;#39;
   }.find { |k,v| k.include? t.hour}.last
 end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What would you like for &lt;a href='http://bonapp.com/'&gt;lunch&lt;/a&gt;?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Offline maps</title>
   <link href="http://bnolan.github.com/2011/05/23/offline-maps.html"/>
   <updated>2011-05-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/23/offline-maps</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve recently had a project morph from an online html5 mapping site, into an application that needs to run offline on netbooks and macbooks. So I&amp;#8217;m investigating taking an openlayers, backbone and coffeescript application and packaging it up with Firefox webrunner (or &lt;a href='https://addons.mozilla.org/en-us/firefox/addon/mozilla-labs-prism/'&gt;Prism&lt;/a&gt;) as an installable package for Windows and os x.&lt;/p&gt;

&lt;p&gt;Doing installable software isn&amp;#8217;t new territory to me. At &lt;a href='http://indigorenderer.com/'&gt;Indigo&lt;/a&gt; we built installable packages for Windows, OS X and Linux - so I&amp;#8217;m pretty happy to work my way through &lt;a href='http://www.jrsoftware.org/isinfo.php'&gt;innosetup&lt;/a&gt; or &lt;a href='http://nsis.sourceforge.net/Main_Page'&gt;nsis&lt;/a&gt;, and the os x packagemaker. For the map tiles, I might try and adapt the &lt;a href='http://mbtiles.org/'&gt;mbtiles&lt;/a&gt; specification from the guys at mapbox. This will be a problem, as the database will have to be jerry rigged into place where Firefox can see it. I&amp;#8217;m avoiding doing any binary firefox extensions for this project, although if things go well, there is the posibility of storing vector data locally and creating a mapnik build that operates as a firefox extension.&lt;/p&gt;

&lt;p&gt;Data will be stored locally using backbone and sqlite, with regular online syncing to the official point-of-interest repository. So far we only have the html5 protoype done, so there is a lot of ground to cover - but I&amp;#8217;ll try and keep you all updated on how things go.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Why Brisbane is the best startup town</title>
   <link href="http://bnolan.github.com/2011/05/18/why-brisbane-might-be.html"/>
   <updated>2011-05-18T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/18/why-brisbane-might-be</id>
   <content type="html">&lt;p&gt;This post comes as a surprise to me. When I planned to visit Brisbane for 8 weeks to spend some time with my girlfriends parents, I didn&amp;#8217;t expect the town would grow on me so much. My previous opinion of Brissie have been is as a cultural wasteland of chromed-up bars and old holdens.&lt;/p&gt;

&lt;p&gt;How wrong I was. I&amp;#8217;ve come to really like brisbane, and I think it may be one of the best towns to do a startup in Australia / New Zealand.&lt;/p&gt;

&lt;h1 id='great_technology_scene'&gt;Great technology scene&lt;/h1&gt;

&lt;p&gt;There is a great network of javascript, rails and other technology groups. They meet regularly, have some exceptionally strong developers (tile5, sproutcore and several other good opensource projects are maintained from brisbane). If you&amp;#8217;re boot strapping, there is good demand for web developers working on modern projects, so you can make a good packet consulting.&lt;/p&gt;

&lt;h1 id='support_for_startups'&gt;Support for startups&lt;/h1&gt;

&lt;p&gt;The complex of buildings along southbank are invaluable for people working from home or without a fixed office. The edge is a beautifully designed digital workshop where you can grab a couch and free wifi for a few hours. Next door is the national library which has hundreds of modern and beautifully designed workstations that are free. Both universities have modern study halls where you just walk in and grab a desk. Mobile broadband is much cheaper in Australia than in New Zealand, so you can work from anywhere. The weather is better than Wellington or Melbourne so you can easily work outdoors wherever you can find shade and somewhere comfy. You&amp;#8217;re just over an hour from Sydney by plane, so you can head down and pitch the collection of investors there, without having to live in Sydney.&lt;/p&gt;

&lt;h1 id='low_cost_of_living'&gt;Low cost of living&lt;/h1&gt;

&lt;p&gt;This is a comparative thing, but compared to Sydney or Melbourne (the only other two cities that could pay comparably to Brisbane) the cost of living here is much lower. A room in a cool part of town (within easy biking distance of the city) will cost you about $150 / week, which is less than half of what you&amp;#8217;d pay in Sydney. Food and transport is cheaper than New Zealand (better public transport), and houses are better designed for the weather (compared to Wellington / Dunedin) so your energy costs will be lower.&lt;/p&gt;

&lt;h1 id='great_standard_of_living'&gt;Great standard of living&lt;/h1&gt;

&lt;p&gt;This is the bit that really rubbed off on me. When you first get here it&amp;#8217;s all chromed up bars, bouncers and awful franchised cafes. But Brisbane has some gems, and it has enough gems that once you link them all up you can have a really good quality life here. It&amp;#8217;s not as epic a cafe scene as Wellington, and I miss some of the fast food in Melbourne (lord of the fries!), but Brisbane does really well.&lt;/p&gt;

&lt;h1 id='the_easy_long_term_view'&gt;The easy long term view&lt;/h1&gt;

&lt;p&gt;There are as many types of startups as there are types of people, but in the kind of &amp;#8220;startup&amp;#8221; I find myself working on (part time projects funded by occasional consulting gigs, where the project might turn into a business over time), Brisbane is a really good match. It&amp;#8217;s basically a overgrown country town, with all the advantages of affordability and relaxedness, combined with excellent modern infrastructure and a burgeoning creative sector.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Backbone Gotchas</title>
   <link href="http://bnolan.github.com/2011/05/17/backbone-gotchas.html"/>
   <updated>2011-05-17T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/17/backbone-gotchas</id>
   <content type="html">&lt;p&gt;If you&amp;#8217;re using Backbone and reusing the same div for all of your views (in a single-page iphone app for example), make sure you call .unbind() on the div when you call destroy the view, backbone doesn&amp;#8217;t do it for you, and if you don&amp;#8217;t unbind the div, you&amp;#8217;ll end up with a whole bunch of events (which are using delegate so they hang around) being trigger at strange and inopportune times.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Designing without thinking</title>
   <link href="http://bnolan.github.com/2011/05/16/designing-without-thinking.html"/>
   <updated>2011-05-16T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/05/16/designing-without-thinking</id>
   <content type="html">&lt;p&gt;This is the kind of post which is going to ensure I never get a job with the &lt;a href='http://www.google.com/'&gt;Aspergers Crowd&lt;/a&gt;, but I&amp;#8217;m going to put it out there - I sometimes program and design without thinking.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;s two aspects to this. One is when you&amp;#8217;re working on a hard project where the functionality is spread across several files and modules, and you need to do some rearchitecture. I&amp;#8217;ll often sit down, work out how I want it to work, then zone out and just refactor without reading the code on the page. Old-school lispers are famous for this, they can work out when to refactor and where the code is unbalanced by looking at the &lt;em&gt;shape of the code&lt;/em&gt;, due to all the parentheses. I do a similair thing, relying on syntax highlighting and compile-on-save to point out when I&amp;#8217;ve broken something.&lt;/p&gt;

&lt;p&gt;The second case is when you&amp;#8217;re prototyping a project, and you have to force yourself to not overthink things, to prevent becoming an &amp;#8216;architecture astronaut&amp;#8217; (abstracting everything away into a GenericFactoryFactoryGenereratorCreator), and instead just deciding &amp;#8216;I want to to X, so I&amp;#8217;ll copy this code here and just search / replace until everything works&amp;#8217;. I&amp;#8217;ve been doing a bunch of this lately with a backbone mobile project I&amp;#8217;m working on. I&amp;#8217;ve got about a dozen lines of code that I&amp;#8217;m copying and pasting into every model I create. I &lt;em&gt;should&lt;/em&gt; create a new base class, and inherit from that, instead of cargo-culting (which is error prone and tedious), but I&amp;#8217;m not going to do that until copying/pasting becomes unbearably tedious. By refactoring prematurely, I&amp;#8217;m bound to make annoying assumptions that I&amp;#8217;ll end having to code around anyway. So don&amp;#8217;t overthink it and just copy / paste away until the extraction to make is painfully clear.&lt;/p&gt;

&lt;p&gt;Obviously both of these techniques only work in a well tested environment, and I can put aside some time the next day to go over what you did and identify the bits that were left out or done badly.&lt;/p&gt;

&lt;p&gt;Oh - and there is obviously that third type of coding without thinking, which is when you need to get something done that you really don&amp;#8217;t want to, so you grab a few beers and create variables named &lt;code&gt;the_variable_which_is_a_number_and_gets_incremented&lt;/code&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Proof of work in Javascript</title>
   <link href="http://bnolan.github.com/2011/04/28/proof-of-work-in-js.html"/>
   <updated>2011-04-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/28/proof-of-work-in-js</id>
   <content type="html">&lt;p&gt;&lt;a href='http://www.thefengs.com/wuchang/work/puzzles/globalinternet08_kapow.pdf'&gt;Proof of work&lt;/a&gt; is the idea of getting a client to do some computational work that is expensive to perform, but cheap to verify.&lt;/p&gt;

&lt;p&gt;For example - if you send a client a random number, and then ask the client to keep increasing that number until the md5 hash of the number starts with four zeroes, it will take on average 2^16 attempts to find the matching number. Then the client sends the number back to the server and the server verifies that the hash starts with 0000&amp;#8230;&lt;/p&gt;

&lt;p&gt;The idea is to make the computation expensive enough that it makes it less worthwhile for spammers to attack your system. It&amp;#8217;s a nice alternative to a captcha because it doesn&amp;#8217;t require any user intervention.&lt;/p&gt;

&lt;h1 id='example_proofofwork_solver'&gt;Example proof-of-work solver&lt;/h1&gt;

&lt;pre&gt;&lt;code&gt;var x = parseInt(Math.random() * 0xFFFFFFFF),
  doWork = function(){
    var count = 100, y, h;
    while(--count &amp;gt; 0){
      x += 1;
      y = x.toString();
      h = hex_md5(y);
      if(h.match(/^0000/)){
        console.log(&amp;quot;Solved... &amp;quot; + x);
        return;
      }
    }
    setTimeout(doWork, 25)
  };

doWork();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This code generates a random number, then increases it until a suitable hash is found. The work unit is broken up into 100 tests at a time, with a timeout between subsequent work so that the browser doesnt warn about script timeouts. This runs fine on a modern browser, but I imagine it would nail ie6. For production code you&amp;#8217;d probably want to profile the doWork function and adapt the work unit size to keep the browser responsive.&lt;/p&gt;

&lt;h1 id='native_solvers'&gt;Native solvers&lt;/h1&gt;

&lt;p&gt;One of the obvious downsides is that any javascript implementation of a hashing function is going to be much slower than a native implementation, so if a spammer wrote a native solver for your proof-of-work, they would be able to trivially solve your work requests.&lt;/p&gt;

&lt;p&gt;For example - firefox takes about 8 seconds to solve my proof of work prototype, firefox takes about 6 seconds, and ruby can solve it in 0.23 seconds.&lt;/p&gt;

&lt;h1 id='alternative_work_algorithms'&gt;Alternative work algorithms&lt;/h1&gt;

&lt;p&gt;Many hashes is a well known and provably computationally difficult proof-of-work technique, but given the problem that a browser will never be able to solve them as fast as a modern GPU, it would be worth investigating other work that a browser could solve that could not be solved faster by any other method, for example calculating the size of an HTML layout.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Capt 0.5.3</title>
   <link href="http://bnolan.github.com/2011/04/21/capt-0.5.3.html"/>
   <updated>2011-04-21T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/21/capt-0.5.3</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve just pushed &lt;a href='/capt/'&gt;capt&lt;/a&gt; 0.5.3. Code generation works properly now &lt;code&gt;generate controller&lt;/code&gt; and &lt;code&gt;generate model&lt;/code&gt;, and the capt watch and capt server commands actually work (I was a bit premature announcing on Tuesday). I&amp;#8217;m using this on two projects now and it has been a really nice toolchain.&lt;/p&gt;

&lt;p&gt;Autogeneration of spec classes is good for maintainability too. I kinda wish I had been BDD-ing &lt;a href='https://github.com/buddycloud/channel-webclient'&gt;Buddycloud&lt;/a&gt; at the moment. That&amp;#8217;s some complicated stuff.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Wanted - A local startup</title>
   <link href="http://bnolan.github.com/2011/04/21/a-local-startup.html"/>
   <updated>2011-04-21T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/21/a-local-startup</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve worked on &amp;#8220;local&amp;#8221; for a really long time, it&amp;#8217;s something that&amp;#8217;s got under my skin. Whether it&amp;#8217;s creating mapping engines, url hierarchy for places or analyzing aggregate user trends, I just really love it. I started a startup in 2006 doing local. We almost got hire-acquired up by Google, but didn&amp;#8217;t, long story.&lt;/p&gt;

&lt;p&gt;Are there any early stage local startups out there?&lt;/p&gt;

&lt;p&gt;Like one or two technical people that are working on something cool and want another hacker on board? Something part time would be a great start for me, I&amp;#8217;m happy to toodle along for a while on a cool idea while we work out to get traction.&lt;/p&gt;

&lt;p&gt;Things I&amp;#8217;m interested in:&lt;/p&gt;

&lt;h1 id='quora_for_local'&gt;Quora for local&lt;/h1&gt;

&lt;p&gt;People ask &amp;#8216;where&amp;#8217;s a good place to get a beer in wellington?&amp;#8217; and you reply &amp;#8220;[Hashigo Zake] and [The Hop Garden]&amp;#8221; and the UI pops up little boxes saying &amp;#8216;Did you mean Hashigo Zake at 25 Taranaki Streeet&amp;#8217;? And you click yes and it turns your square brackets into a link.&lt;/p&gt;

&lt;h1 id='reddit_for_local'&gt;Reddit for local&lt;/h1&gt;

&lt;p&gt;People can click on places in a city (reverse geocode to buildings and natural features using a combination of google local search and openstreetmap gazetter) and each place has a discussion board. Going to a city level shows all the conversations going on in the city, sorted by recentness. Build a url scheme like &lt;code&gt;/paris/la-cite/notre-dame&lt;/code&gt;. I&amp;#8217;ve written a prototype of this.&lt;/p&gt;

&lt;h1 id='delicious_for_local'&gt;Delicious for local&lt;/h1&gt;

&lt;p&gt;Write a bookmarklet that lets you bookmark a webpage, and it hunts out any geodata in the page and saves it to a map for you. You can use this to plan your trips by saving all the interesting looking webpages and then accessing the list of places offline on your iphone. I&amp;#8217;ve written this bookmarklet already.&lt;/p&gt;

&lt;h1 id='greplin_for_local'&gt;Greplin for local&lt;/h1&gt;

&lt;p&gt;The user signs in using oauth to foursquare, google my maps, facebook, gowalla and twitter. Index all the places the user has been and all the places their friends go. Use this to generate a &amp;#8216;personal black book&amp;#8217; of places to go while travelling the world. So you go to berlin, fire up &amp;#8216;GeoGreplin&amp;#8217; and it shows you all the places your friends want to visit / have checked in to / have saved to a map.&lt;/p&gt;

&lt;h1 id='twitter_local_browser'&gt;Twitter local browser&lt;/h1&gt;

&lt;p&gt;Suck down the twitter geo-firehose and plot all the tweets onto maps. Break the tweets down into cities and suburbs. Aggregate the tweets together (using some kind of &lt;a href='http://bennolan.com/2010/09/10/contour-maps.html'&gt;2d histogram&lt;/a&gt;) to show where the interesting stuff is in your city. People can discover people nearby and see what&amp;#8217;s going on. I&amp;#8217;ve built a prototype for this too.&lt;/p&gt;

&lt;p&gt;Anyway - that&amp;#8217;s the interesting ideas. Anyone working on stuff like this? Or any angel list types want to fund me to find a cofounder and build one of these?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>There comes a time in every project...</title>
   <link href="http://bnolan.github.com/2011/04/20/there-comes-a-time.html"/>
   <updated>2011-04-20T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/20/there-comes-a-time</id>
   <content type="html">&lt;p&gt;There comes a time in every project - after days of prototyping, design, tweaking, rigorous speccing and bdd, after several deployments to staging and a/b testing with beta users, after polls and roundtables and whiteboarding - that you have to admit that the project isn&amp;#8217;t any fun to use.&lt;/p&gt;

&lt;p&gt;And that&amp;#8217;s the opportunity to sit back and reimagine it, then make some small (usually not huge) tweaks until it starts to come together again.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Channel Activity</title>
   <link href="http://bnolan.github.com/2011/04/20/channel-activity.html"/>
   <updated>2011-04-20T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/20/channel-activity</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s hard to discover new activity in Buddycloud, time to fix that.&lt;/p&gt;
&lt;img src='/images/poke/channel-list.png' /&gt;&lt;cite&gt;The channel list in buddycloud&lt;/cite&gt;
&lt;p&gt;Log into diaspora-x and there&amp;#8217;s no indication of what activity is happening on your channels. Simon said to put the channel list on the left and bubble activity to the top. Let&amp;#8217;s try.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;span{
  display: inline-block;
  height: 20px;
  width: 20px;
  text-align: center;
  font-size: 0.8em;
  background: #999;
  color: white;
  border-radius: 10px;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Okay - add a litte badge showing the number of posts, and reorder the channel list by number of posts.&lt;/p&gt;
&lt;img src='/images/poke/channel-list-imp.png' /&gt;&lt;cite&gt;A sorted list of channels with new activity&lt;/cite&gt;
&lt;p&gt;Nice.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Diaspora-x ui work</title>
   <link href="http://bnolan.github.com/2011/04/19/diaspora-x-ui.html"/>
   <updated>2011-04-19T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/19/diaspora-x-ui</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been doing some work on buddycloud / diaspora-x user interface. Screenshots follow:&lt;/p&gt;
&lt;img src='/images/sam-friends.png' /&gt;&lt;cite&gt;You have to be friends&lt;/cite&gt;
&lt;p&gt;I have to admit that the buddycloud ui looks a lot nicer, with blues and colors, but I&amp;#8217;ll be sticking with the grey and black ui that diaspora-x features.&lt;/p&gt;
&lt;img src='/images/the-ministry.png' /&gt;&lt;cite&gt;The ministry of interesting posts&lt;/cite&gt;
&lt;p&gt;I&amp;#8217;m getting ready to deploy the latest diaspora-x.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Capt is in npm</title>
   <link href="http://bnolan.github.com/2011/04/18/capt-is-in-npm.html"/>
   <updated>2011-04-18T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/18/capt-is-in-npm</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve resumed work on &lt;a href='http://bennolan.com/capt/'&gt;capt&lt;/a&gt;, since my &lt;a href='http://diaspora-x.com/'&gt;diaspora-x&lt;/a&gt; codebase relies on capt, and although I expect &lt;a href='http://brunchwithcoffee.com/'&gt;brunch&lt;/a&gt; or &lt;a href='http://cincojs.com/'&gt;cinco&lt;/a&gt; will take over as the build tool of choice for coffeescript / backbone apps - capt works for me now.&lt;/p&gt;
&lt;img src='/images/capt.png' /&gt;&lt;cite&gt;Logo indicates far more polish than the project has.&lt;/cite&gt;
&lt;p&gt;Capt is a tool for development and deploying javascript single page apps. It takes care of including all your javascripts in the right order, and compiling your static html pages. It has some support for jasmine, coffeescript and less. It&amp;#8217;s very creaky, but my collaborators on the diaspora-x / Buddycloud web client needed to be able to use it, so I&amp;#8217;ve packaged up capt as an npm.&lt;/p&gt;

&lt;p&gt;So you can install capt with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;npm install capt&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once it&amp;#8217;s installed, create a new app and serve it using the built in server.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;capt new myproject
cd myproject
capt server
open http://localhost:4000/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And enjoy the capt goodness. I&amp;#8217;ve put up a &lt;a href='http://bennolan.com/capt/'&gt;basic webpage&lt;/a&gt; explaining how to use capt. I imagine this release is pretty broken, it&amp;#8217;s only really intended for diaspora-x development, but give it a go. I&amp;#8217;ve been doing small commits on capt for a while now, so it&amp;#8217;ll eventually turn into a decent tool I hope.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Coffeescript supersedes Rails</title>
   <link href="http://bnolan.github.com/2011/04/15/coffeescript-supersedes-rails.html"/>
   <updated>2011-04-15T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/15/coffeescript-supersedes-rails</id>
   <content type="html">&lt;p&gt;This is a bit of a &lt;a href='https://github.com/rails/rails/compare/9333ca7...23aa7da'&gt;contentious post&lt;/a&gt; (that commit is comedy gold) but I think people talking about rails using coffeescript as the new default client-side language are missing the point that coffeescript doesn&amp;#8217;t complement rails, it supersedes it.&lt;/p&gt;

&lt;p&gt;I come from a biased position, since I&amp;#8217;m known for front end development, but I&amp;#8217;ve been doing rails since version 0.6, and most of my contract gigs have a ruby on rails component. Rails is a great tool for building middleware, and when it was invented it was a perfect solution.&lt;/p&gt;

&lt;h1 id='2006'&gt;2006&lt;/h1&gt;

&lt;p&gt;Common technology was MySQL and PHP. Front end development was pretty low-impact, mostly you generated html on the server and sent it to the client, sometimes you sent html fragment back and forth for some ajax-interactivity.&lt;/p&gt;

&lt;p&gt;Into this environment, rails was amazing. It was a great framework for building apps, gave you conventions on how to structure your app, forms and data models. And then rails came out with the ajax helpers and people went crazy for it. Over time rails added excellent json support and people started using it to create pure json api sites (like twitter does these days), but fastforward to 2011&amp;#8230;&lt;/p&gt;

&lt;h1 id='2011'&gt;2011&lt;/h1&gt;

&lt;p&gt;We now have pure json databases (couchdb, mongodb), localStorage and thousands of public APIs. And any truly modern app will probably be written in pure javascript (and rendering their static html by a node.js instance for disabled browsers). Into this environment, Rails makes less sense. If you&amp;#8217;re building a facebook add-in, you can probably do it entirely using FBJS. If you&amp;#8217;re using the foursquare api you can do that in the client, same with twitter. If you need to do an app that stores tonnes of data - get a free couchdb instance from couchone. If you need &amp;#8220;web scale&amp;#8221; - you can use amazon simple db.&lt;/p&gt;

&lt;p&gt;Rails doesn&amp;#8217;t need to feature in any of this. And although rails will live on forever (like php does), and it&amp;#8217;ll probably adapt to it&amp;#8217;s new role as an authentication and permissions layer between the client and the database, I would be surprised if a better solution doesn&amp;#8217;t come along. It could be a more mature CouchDB authentication / permissioning framework, or Postgres might release a json interface and people go back to writing stored procedures to authenticate / secure requests.&lt;/p&gt;

&lt;h1 id='middleware_is_becoming_less_important'&gt;Middleware is becoming less important&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m sure its just a cyclical thing, we go back and forth between thin client to thick client architectures, but it seems to me that rails might be on the downswing, to be replaced by some hot new tech that takes less work to create pure javascript apps.&lt;/p&gt;

&lt;p&gt;Note that I&amp;#8217;m not saying node.js is going to replace rails. I think there&amp;#8217;s less need for middleware these days.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Planning in the open</title>
   <link href="http://bnolan.github.com/2011/04/14/planning-in-the-open.html"/>
   <updated>2011-04-14T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/14/planning-in-the-open</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been designing today. The current &lt;a href='http://buddycloud.com/'&gt;Buddycloud&lt;/a&gt; site needs a refresh - so I busted out Jekyll (the tool I use to generate bennolan.com), some css3 and the blueprint css framework.&lt;/p&gt;
&lt;img src='/images/bc-website-shot.png' /&gt;&lt;cite&gt;The in development buddycloud site&lt;/cite&gt;
&lt;p&gt;It came together quite nicely, and because we&amp;#8217;re hosting the repository for the site on github - you too can go &lt;a href='http://buddycloud.github.com/'&gt;visit the site&lt;/a&gt; - even though it&amp;#8217;s unfinished.&lt;/p&gt;

&lt;p&gt;Which brings a dilemma. Do we make the repository private - remove the hosted instance and only require people working with Buddycloud to view the in-development site? There&amp;#8217;s sure some interesting / awkward stuff in there - a lot of lorem ipsum text and some rough guesses of price points and a business model.&lt;/p&gt;

&lt;p&gt;Well - to be honest, what kills most small businesses (which is what Buddycloud is at the moment) is obscurity or apathy, not giving interested parties too much insight into your business. So we&amp;#8217;ll leave it up for now, and then everyone can see the site when it&amp;#8217;s ready for &amp;#8216;public&amp;#8217; deployment.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Localstorage for speed</title>
   <link href="http://bnolan.github.com/2011/04/13/localstorage-for-speed.html"/>
   <updated>2011-04-13T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/13/localstorage-for-speed</id>
   <content type="html">&lt;p&gt;The Buddycloud web client is &lt;a href='https://github.com/buddycloud/channel-webclient'&gt;available on github&lt;/a&gt;. I started with the Diaspora-x codebase, and have been backporting in features from the codebase that was started by &lt;a href='http://astro.soup.io/'&gt;Stefan Maka&lt;/a&gt; (another Buddycloud contributor).&lt;/p&gt;
&lt;img src='/images/channelinfo.png' /&gt;&lt;cite&gt;Channel metadata display&lt;/cite&gt;
&lt;h1 id='using_localstorage_to_accelerate_load_time'&gt;Using localStorage to accelerate load time&lt;/h1&gt;

&lt;p&gt;When you fire up &lt;a href='http://diaspora-x.com/'&gt;diaspora-x&lt;/a&gt;, it takes about 15 seconds to finish loading the #home page. Obviously this isn&amp;#8217;t going to play in a world where page loads should take &lt;a href='http://www.useit.com/alertbox/response-times.html'&gt;less than 1000ms&lt;/a&gt;. Ideally I&amp;#8217;d like the page to load in about 100ms. Assuming we can get everything cached locally, that gives a pretty generous time for the browser to cache and run the javascript payload.&lt;/p&gt;

&lt;p&gt;The first part of the optimization was to prevent unnecessary requests to the XMPP server. Once you&amp;#8217;ve requested all a users posts, there&amp;#8217;s no need to re-request the same posts. We can use &lt;a href='http://xmpp.org/extensions/xep-0059.html'&gt;Result Set Management&lt;/a&gt; to only ask for posts newer than the last post we recieved, and then we can use &lt;a href='https://github.com/jeromegn/Backbone.localStorage'&gt;backbone-localStorage&lt;/a&gt; to save the posts in localStorage in the current browser.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ChannelCollection extends Backbone.Collection
  model: Channel

  initialize: -&amp;gt;
    @localStorage = new Store(&amp;quot;ChannelCollection&amp;quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then before we start the app&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Channels = new ChannelCollection
Channels.fetch()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then remember to clear localStorage when the user logs out.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;localStorage.clear()&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Distributed Social Networking</title>
   <link href="http://bnolan.github.com/2011/04/12/distributed-social-networking.html"/>
   <updated>2011-04-12T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/12/distributed-social-networking</id>
   <content type="html">&lt;p&gt;Normally when a client rings up and wants you to build a replacement for Facebook, you smile politely and say that you&amp;#8217;re full up for the next 18 months.&lt;/p&gt;

&lt;p&gt;But, &lt;a href='http://www.facebook.com/simon.tennant'&gt;Simon&lt;/a&gt; from &lt;a href='http://buddycloud.com/'&gt;Buddycloud&lt;/a&gt; has asked me really nicely to build the front end for his distributed social network, so I said I&amp;#8217;d give him 5 weeks and see what we can pull off.&lt;/p&gt;

&lt;h1 id='buddycloud'&gt;Buddycloud&lt;/h1&gt;

&lt;p&gt;The buddycloud protocol is an extension for XMPP, the system that gtalk uses. Buddycloud takes the existing XMPP extensions (publish / subscribe, rosters, federation) and builds a social network around them. Buddycloud is an opensource protocol, Simon and others are trying to get the protocol in front of the xmpp standards committee.&lt;/p&gt;

&lt;p&gt;There are three implementations of buddycloud-compliant servers at the moment, one for ejabberd, one for prosody, and a new one that uses node.js and plugs into any standards-compliant jabber server.&lt;/p&gt;

&lt;h1 id='web_front_end'&gt;Web front end&lt;/h1&gt;

&lt;p&gt;Back in December, I created &lt;a href='http://diaspora-x.com/'&gt;Diaspora-x&lt;/a&gt;, which was a first cut at building a social network on top of XMPP. It is a pure HTML5 app, just javascript, html and css - the backend service is provided by the XMPP servers (running &lt;a href='http://www.ejabberd.im/'&gt;ejabberd&lt;/a&gt; and &lt;a href='http://prosody.im/'&gt;prosody&lt;/a&gt; at &lt;a href='https://beta.buddycloud.com/http-bind/'&gt;beta.buddycloud.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This was an interesting experiment, and showed it is possible to build a responsive social network that gets all it&amp;#8217;s data from an xmpp network.&lt;/p&gt;

&lt;h1 id='twitter_facebook_and_buddycloud'&gt;Twitter, Facebook and Buddycloud&lt;/h1&gt;

&lt;p&gt;It&amp;#8217;s interesting to note that &lt;a href='http://engineering.twitter.com/2010/09/tech-behind-new-twittercom.html'&gt;new twitter&lt;/a&gt; uses the exact same engineering as Diaspora-x, in that when you visit the website, you&amp;#8217;re actually loading a large javascript application. The tweets and profile data that you see is transferred afterwards by an XMLHttprequest.&lt;/p&gt;

&lt;p&gt;The existing Diaspora-x client (which is the basis for the new Buddycloud web client) does the same thing, it&amp;#8217;s a Javascript app, powered by Backbone, jQuery and Underscore.js - which instead of loading tweets from api.twitter.com, it subscribes to an XMPP channel over BOSH (XMPP over http protocol), and messages from your contacts are pushed down to the browser.&lt;/p&gt;

&lt;p&gt;The current Facebook UI does a similair thing, it loads a small amount of static html when you load the page, then most of the rest of the page is constructed from Javascript running in the browser. (Facebook is a bit different because it uses their &lt;a href='http://www.facebook.com/note.php?note_id=307069903919'&gt;Primer&lt;/a&gt; tool that downloads html, instead of doing the templating in the browser - but similar concept).&lt;/p&gt;

&lt;h1 id='building_the_buddycloud_web_client'&gt;Building the Buddycloud Web Client&lt;/h1&gt;

&lt;p&gt;The Buddycloud web client will be an Opensource project, so you&amp;#8217;ll be able to watch my progress at github once the repository is up. I&amp;#8217;ll try and blog regularly here, so watch for progress&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A* in coffeescript</title>
   <link href="http://bnolan.github.com/2011/04/11/astar-in-coffeescript.html"/>
   <updated>2011-04-11T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/11/astar-in-coffeescript</id>
   <content type="html">&lt;p&gt;I put together this astar solver in coffeescript. It expects that nodes have a &lt;code&gt;key()&lt;/code&gt; function that generates a unique id for the node, and an &lt;code&gt;getAdjacentNodes()&lt;/code&gt; function that returns valid adjacent nodes.&lt;/p&gt;

&lt;p&gt;It seems to work nicely.&lt;/p&gt;

&lt;p&gt;Also - it&amp;#8217;s my birthday today! Woo! :)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AStar
  constructor: -&amp;gt;
    @openNodes = {} # List of openNodes nodes (nodes to be inspected)
    @closedNodes = {} # List of closedNodes nodes (nodes we&amp;#39;ve already inspected)

    # The maximum potential trip length we would consider
    @maxHeuristic = Point.origin().squareDistanceTo(new Point(5, 5))

  findPath: (start, destination) -&amp;gt;
    # g = 0 #Cost from start to current node
    # h = heuristic(start, destination) #Cost from current node to destination
    # var f = g+h #Cost from start to destination going through the current node

    start.f = @heuristic(start, destination)

    # Push the start node onto the list of openNodes nodes
    # openNodes.push(start) 
    @openNodes[start.key()] = start

    #Keep going while there&amp;#39;s nodes in our openNodes list
    while @openNodes
      #Find the best openNodes node (lowest f value)

      #Alternately, you could simply keep the openNodes list sorted by f value lowest to highest,
      #in which case you always use the first node

      node = { f : Infinity }

      for key, n of @openNodes
        if n.f &amp;lt; node.f
          node = n
  
      # No nodes remain in openNodes
      if node.f == Infinity
        # No path could be found...
        console.log &amp;quot;No path could be found&amp;quot;
        return null
        # console.log @closedNodes
  
      # Check if we&amp;#39;ve reached our destination
      if node.equals(destination)
        path = [destination]
  
        while (node != start) # &amp;amp;&amp;amp; (node.parentKey)
          node = @closedNodes[node.parentKey]
          path.push node

        path.reverse()
    
        return path
    
      # Remove the current node from our openNodes list
      delete @openNodes[node.key()]

      # Push it onto the closedNodes list
      @closedNodes[node.key()] = node

      # Expand our current node
      for n in node.getAdjacentNodes() when (!@closedNodes[n.key()]) &amp;amp;&amp;amp; (!@openNodes[n.key()]) 
        # console.log(n.key())
        n.f = @heuristic(n, destination)
        n.parentKey = node.key()
    
        # Prevent really long paths
        if n.f &amp;lt; @maxHeuristic
          @openNodes[n.key()] = n
        # else 
        #   @closedNodes[n.key()] = n

  # An A* heurisitic must be admissible, meaning it must never overestimate the
  # distance to the goal. In other words, it must either underestimate or return 
  # exactly the distance to the goal.
  heuristic: (a, b) -&amp;gt;
    a.position.squareDistanceTo(b.position)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here are the specs so you can see that it does actually work, but the require a bunch of other classes that I&amp;#8217;ve been working on - and I don&amp;#8217;t have time to tidy them up for release right now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;describe &amp;#39;astar&amp;#39;, -&amp;gt;

  describe &amp;#39;square map&amp;#39;, -&amp;gt;
    # Create a big square tile
    map = new Map
    bounds = new Bounds(Point.origin(), new Point(10,10))
    for point in bounds.getPoints()
      map.set(point, new Tile)
    origin = map.get(Point.origin())

    it &amp;quot;should work horizont&amp;quot;, -&amp;gt;
      a = new AStar
      x2 = map.get(new Point(0,5))
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 6

    it &amp;quot;should work vertical&amp;quot;, -&amp;gt;
      a = new AStar
      x2 = map.get(new Point(5,0))
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 6

    it &amp;quot;should work diagonal&amp;quot;, -&amp;gt;
      a = new AStar
      x2 = map.get(new Point(5,5))
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 11
  
      path = for tile in path
        tile.toString()
    
      expect(path.join(&amp;quot; -&amp;gt; &amp;quot;)).toEqual(&amp;quot;0, 0 -&amp;gt; 1, 0 -&amp;gt; 1, 1 -&amp;gt; 2, 1 -&amp;gt; 2, 2 -&amp;gt; 3, 2 -&amp;gt; 3, 3 -&amp;gt; 4, 3 -&amp;gt; 4, 4 -&amp;gt; 5, 4 -&amp;gt; 5, 5&amp;quot;)

    it &amp;quot;should several times&amp;quot;, -&amp;gt;
      x2 = map.get(new Point(5,5))

      a = new AStar
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 11

      a = new AStar
      path = a.findPath(x2,origin)
      expect(path.length).toEqual 11

      a = new AStar
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 11

      a = new AStar
      path = a.findPath(x2,origin)
      expect(path.length).toEqual 11

      a = new AStar
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 11

      a = new AStar
      path = a.findPath(x2,origin)
      expect(path.length).toEqual 11

    it &amp;quot;should work on a single step&amp;quot;, -&amp;gt;
      a = new AStar
      x2 = map.get(new Point(1,0))
      path = a.findPath(origin,x2)
      expect(path.length).toEqual 2

    it &amp;quot;should work on origin-&amp;gt;origin&amp;quot;, -&amp;gt;
      a = new AStar
      path = a.findPath(origin,origin)
      expect(path.length).toEqual 1

    it &amp;quot;should return empty when impossible&amp;quot;, -&amp;gt;
      map.set(new Point(100, 0), new Tile)

      a = new AStar
      x2 = map.get(new Point(100, 0))
      path = a.findPath(origin,x2)
      expect(path).toEqual null&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Against me nervous energies sessions</title>
   <link href="http://bnolan.github.com/2011/04/09/nervous-energies.html"/>
   <updated>2011-04-09T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/09/nervous-energies</id>
   <content type="html">&lt;p&gt;For future reference, the &lt;a href='http://www.youtube.com/results?search_query=against+me+nervous+energies&amp;amp;aq=f'&gt;against me nervous energies sessions&lt;/a&gt; are linked in this post.&lt;/p&gt;

&lt;p&gt;My favourite band of all time. Make sure you also check out &lt;a href='http://www.youtube.com/watch?v=kmUKY0JEArA'&gt;borne&lt;/a&gt; and most importantly, &lt;a href='http://www.youtube.com/watch?v=X9iTNNi8Gh0&amp;amp;playnext=1&amp;amp;list=PLCBE065BE058723BF'&gt;don&amp;#8217;t lose touch&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Native maps speed in Javascript</title>
   <link href="http://bnolan.github.com/2011/04/08/native-maps-speed-in-javascript.html"/>
   <updated>2011-04-08T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/08/native-maps-speed-in-javascript</id>
   <content type="html">&lt;p&gt;Whenever I use &lt;a href='http://openlayers.org/'&gt;OpenLayers&lt;/a&gt; or even &lt;a href='http://www.tile5.org/'&gt;Tile5&lt;/a&gt;, it annoys me that no matter how much you optimize your javascript code, your html5 map will never be as smooth and fluid as the native iphone maps app. I decided to try and fix that today.&lt;/p&gt;

&lt;p&gt;&lt;a href='/experiments/nativemaps/'&gt;This demo&lt;/a&gt; is only a proof of concept, but if you try it on an iphone (even my 1st generation iphone), you&amp;#8217;ll see that it pans as quickly as the native client. It uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A 60fps interval to update the map position&lt;/li&gt;

&lt;li&gt;Damped map velocity movement (flicking)&lt;/li&gt;

&lt;li&gt;Translate3d to use hardware acceleration&lt;/li&gt;

&lt;li&gt;Suppresses touch events and user-select events to prevent the user interaction slowdown&lt;/li&gt;

&lt;li&gt;Zepto.js for event management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#8217;m discussing with Damon from tile5 to get this code put into tile5 (since writing an entire javascript mapping library isn&amp;#8217;t on the cards for me today), but I wanted to show the performance that javascript mapping libraries should be aiming for.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Smallest turing complete language</title>
   <link href="http://bnolan.github.com/2011/04/06/smallest-turing-complete-language.html"/>
   <updated>2011-04-06T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/06/smallest-turing-complete-language</id>
   <content type="html">&lt;p&gt;I was wondering what the smallest set of opcodes would be for a turing complete language.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://en.wikipedia.org/wiki/Brainfuck'&gt;Brainfuck&lt;/a&gt; seems to indicate that you need 8 opcodes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move the data pointer left or right&lt;/li&gt;

&lt;li&gt;Increment / decrement the data pointer&lt;/li&gt;

&lt;li&gt;Write the data pointer to the output&lt;/li&gt;

&lt;li&gt;Read input to the data pointer&lt;/li&gt;

&lt;li&gt;Loop until the data pointer is zero&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>AI smallest program</title>
   <link href="http://bnolan.github.com/2011/04/05/ai-smallest-program.html"/>
   <updated>2011-04-05T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/05/ai-smallest-program</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been thinking about AI a bit lately, and a question I&amp;#8217;ve had, is what is the smallest non trivial programming loop you could make? What number of opcodes would it be? I guess it&amp;#8217;d have to be a program that took evolving inputs and iterated to approach an optimal solution.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m thinking of a program that has changing inputs, so that there is no one optimal solution, the best the program can do is constantly seek to a solution. It&amp;#8217;s a thought experiment, in that that you can calculate an upper bound for how quickly a genetic program could evolve by working out the simplest non trivial program, and calculating how fast it could be run on a modern cpu.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Simple English</title>
   <link href="http://bnolan.github.com/2011/04/04/simple-english.html"/>
   <updated>2011-04-04T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/04/04/simple-english</id>
   <content type="html">&lt;p&gt;Simple english has only 800 words, and I&amp;#8217;ve found an english -&amp;gt; basic english &lt;a href='http://www.basic-english.org/down/idp.zip'&gt;translator&lt;/a&gt;. I think it&amp;#8217;s a good vocabulary for a chatbot.&lt;/p&gt;

&lt;h1 id='hypergraphs'&gt;Hypergraphs&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve been reading about hypergraphs, which is what OpenCog uses as a knowledge store. It&amp;#8217;s a graph where instead of edges being between nodes, edges can have have an infinite number of nodes. You could look at it as a &amp;#8216;set store&amp;#8217;, where you have many many sets of different &amp;#8216;strengths&amp;#8217;, surrounding a fixed pool of nodes. Anyway, I&amp;#8217;m not totally sure I understand the theory, but it seems like an interesting idea.&lt;/p&gt;

&lt;p&gt;My naive implementation of a knowledge store for a chatbot, is to create nodes for terms, and then have bidirectional relationships between terms, and relationships are strengthened when the analyser is fed two terms in sequence. As far as i can tell, this is like the hypergraphs.&lt;/p&gt;

&lt;h1 id='metropolishasting'&gt;Metropolis-Hasting&lt;/h1&gt;

&lt;p&gt;After working on &lt;a href='http://indigorenderer.com/'&gt;Indigo Renderer&lt;/a&gt; and having many conversations with Nick Chapman, I have a sense that when doing a random walk through the AI&amp;#8217;s knowledgebase, that it&amp;#8217;d be worth calculating a probability that the path would have been selected.&lt;/p&gt;

&lt;p&gt;So for example - the AI queries it&amp;#8217;s knowledge store for the term &amp;#8216;dog&amp;#8217;, and the knowledge store would query for a thousand random chains of related terms from dog. It would then rank those chains in terms of likelihood of those chains having been taught to the machine.&lt;/p&gt;

&lt;p&gt;So - train the bot:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dog is animal
dog is pet
horse is animal&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the knowledge store might return:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;0.2 dog is animal
0.2 dog is pet
0.15 dog is animal is pet
0.1 dog is animal is
0.1 dog is pet is
0.1 dog is pet is dog
0.01 dog is animal is horse&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Brunch</title>
   <link href="http://bnolan.github.com/2011/03/23/brunch.html"/>
   <updated>2011-03-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/03/23/brunch</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve stopped developing capt, my javascript build tool. I&amp;#8217;m instead contributing to &lt;a href='http://brunchwithcoffee.com/'&gt;brunch&lt;/a&gt;, a tool built by Jan and Thomas. It&amp;#8217;s still early stages, but it is already ahead of where capt was. My todo list for brunch is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add jasmine testing to clients&lt;/li&gt;

&lt;li&gt;Port static html generation templates from capt&lt;/li&gt;

&lt;li&gt;Add code generation for classes / models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It&amp;#8217;s an interesting project, hopefully a good alternative to the upcoming framework from @sstephenson.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The golden ratio in CSS</title>
   <link href="http://bnolan.github.com/2011/03/22/golden-ratio.html"/>
   <updated>2011-03-22T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/03/22/golden-ratio</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been designing a new mapping interface for a product I&amp;#8217;m releasing shortly. I&amp;#8217;ve copied the design of the twitter app for ipad, which has multiple sliding panes. I was trying to work out the widths of each pane so that the app looked a bit more cohesive, when I decided to try out the golden ratio.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m using &lt;a href='http://learnboost.github.com/stylus/'&gt;stylus&lt;/a&gt; - which is an excellent css toolkit, similar to sass or less.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;golden-ratio = 1.61803399
base-width = 48px&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The base-width is the width of the skinniest column on the left side of the page. I then use multiples of the golden-ratio and the base-width to chose the widths of the other columns.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.modes-presenter
  width base-width

.places-list-pane
  width (golden-ratio ** 4 * base-width) - 40px

.place-show-presenter
  width (golden-ratio ** 4 * base-width) - 40px&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;m not sure if it was a placebo effect - but the end result was quite pleasing to me.&lt;/p&gt;
&lt;img src='/images/golden-ratio.png' /&gt;&lt;cite&gt;Early prototype with GR-sized columns&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Back from holiday</title>
   <link href="http://bnolan.github.com/2011/03/21/back-from-holiday.html"/>
   <updated>2011-03-21T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2011/03/21/back-from-holiday</id>
   <content type="html">&lt;p&gt;On the 1st of February, Riss and I moved out of our apartment on Mount Victoria, and into our little green van. We had a bed in the back, gas bbq, chillibin and a box of food. We spent the next 7 weeks travelling around the South and North islands of New Zealand.&lt;/p&gt;
&lt;img src='/images/P1050248.jpg' /&gt;&lt;cite&gt;Totaranui, Golden Bay. Beautiful place.&lt;/cite&gt;
&lt;p&gt;I had created a rough map of where to go using a beta version of Weheartplaces, but in the end we just travelled using the lonely planet and my ipad to look up places on the go. As it was, it turned out that a place bookmarking service would&amp;#8217;ve been really awesome, especially in finding freedom camping sites, as they are scattered throughout the internet and hard to find.&lt;/p&gt;

&lt;p&gt;(As it happens, I&amp;#8217;m working on a solution on finding freedom camping sites as we speak).&lt;/p&gt;

&lt;p&gt;Camping in New Zealand is beautiful. The doc campsites are the best places to go. They&amp;#8217;re remote, cheap, relaxed and have the best locations. My favourite three places were Totaranui, Whananaka North and Aoraki campgrounds. I&amp;#8217;m still working on culling and uploading all the photos from the trip - but it was a very fun time - and it&amp;#8217;s great to be back.&lt;/p&gt;

&lt;p&gt;Gear review:&lt;/p&gt;

&lt;p&gt;Nissan 4wd Van - excellent. Big enough to sleep in (although we had a bit too much stuff), small enough to get into all the great little campsites. 4wd was good for rallying up.&lt;/p&gt;

&lt;p&gt;iPad w/ 3G - excellent. Hugely useful, but not so capable that I could do any more than briefly reply to emails (can&amp;#8217;t do any coding on it, which is good). Vodafone coverage is fucking awful, telecom 3g is much better.&lt;/p&gt;

&lt;p&gt;Chilli bin - good. Buy some ice every few days and you&amp;#8217;ve got a cheap, easy to use fridge. Only thing missing was it didnt have a tap at the bottom to let out the melted water, and it couldnt fit heaps of beers.&lt;/p&gt;

&lt;p&gt;Gas cooker - excellent. You need a twin burner, so you can make fancy meals. We ate really well, and making coffee with the burr grinder and stovetop espresso, while sitting on a remote beach, is really awesome.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Desaturated google maps</title>
   <link href="http://bnolan.github.com/2011/01/27/desaturated.html"/>
   <updated>2011-01-27T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/27/desaturated</id>
   <content type="html">&lt;p&gt;You&amp;#8217;re building your site, you do it nice, you have regular line spacing, lots of white space, even gaps, nicely kerned typography. You took your triplet css values &lt;code&gt;#ccc&lt;/code&gt; to &lt;code&gt;#c3c3c3&lt;/code&gt; for that perfect shade of grey, changed all the borders from dotted to solid. Your website is maybe starting to look like the pages of a design magazine. Then you add google maps to the page.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s like smearing playdough on your furniture.&lt;/p&gt;

&lt;p&gt;Try using google styled maps and desaturate the map to get something that looks more like this. Still functional, but easier on the eye and suitable to my bauhaus sensibilities.&lt;/p&gt;
&lt;img src='/images/desaturated.png' /&gt;&lt;cite&gt;Desaturated, label opacity reduced&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Fix myspace in 5 steps</title>
   <link href="http://bnolan.github.com/2011/01/25/fix-myspace.html"/>
   <updated>2011-01-25T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/25/fix-myspace</id>
   <content type="html">&lt;p&gt;I have a bit of a thing for trying to fix broken social networks (see &lt;a href='/2010/12/07/diaspora-x.html'&gt;Diaspora-x&lt;/a&gt;), so when I recieved an invite to friend someone on Myspace, it jogged my memory that the company is up for sale, so I thought I&amp;#8217;d make my list of 5 things the new owner could to to stem the decline and maybe even compete with the #1 social network.&lt;/p&gt;

&lt;h1 id='become_a_flat_engineeroriented_organisation'&gt;Become a flat engineer-oriented organisation&lt;/h1&gt;

&lt;p&gt;From reading this &lt;a href='http://www.reddit.com/r/IAmA/comments/f09rk/iama_myspace_employee_about_to_be_laid_off_today/'&gt;reddit iama&lt;/a&gt;, it seems that the engineering teams aren&amp;#8217;t communicating effectively. Given the glacial speed of improvements to the site, I imagine that the development process is pure corporate-bullshit, where any improvement or tweak must go up through a layer of bureaucracy before being built.&lt;/p&gt;

&lt;p&gt;Instead, let engineers discuss a feature with their team lead, build it and deploy it in the same day. The same way facebook does. And make the default answer to be &amp;#8216;yes do it&amp;#8217;, not - &amp;#8216;uhh lets think about that&amp;#8217;. Companies fail because the employees can&amp;#8217;t innovate, not because the employees fuck up.&lt;/p&gt;

&lt;h1 id='become_design_and_user_experience_focussed'&gt;Become design and user experience focussed&lt;/h1&gt;

&lt;p&gt;The myspace user experience is poor when compared to Facebook. It&amp;#8217;s hard to tell where you are in the site, it&amp;#8217;s hard to find information, it&amp;#8217;s hard to work out how to do simple tasks. The biggest things that need fixing with the UI right now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Myspace style guide. All myspace pages, from the developer guide to the front page to the sitewide UI should obey the same style guidelines for consistency.&lt;/li&gt;

&lt;li&gt;Focus on page load time and browser stability. Deprecate flash, promote and develop html5 solutions for the current widgets. Don&amp;#8217;t autoplay any media.&lt;/li&gt;

&lt;li&gt;Add summaries of profile sub pages on the main profile page (show top 3 photo thumbnails, links to the top 3 tracks on the music page, create a summary field that shows the user / artists most recent activity) to encourage users to explore deeper into the profile and not just hit &amp;#8216;back&amp;#8217;.&lt;/li&gt;

&lt;li&gt;Add more explorability. Make record label links go to a &amp;#8216;label page&amp;#8217; that shows other artists. Make the &amp;#8216;location&amp;#8217; field a hyperlink that shows a page with all public profiles located in that area.&lt;/li&gt;

&lt;li&gt;Hire pixel-perfect designers. You don&amp;#8217;t have the facebook ui template library, so make developers forward a screenshot of any new UI (be it a &amp;#8216;you are logged in&amp;#8217; alert or a &amp;#8216;changes saved&amp;#8217; interstitial) to your design team, and give the design team a mandate to sit in with developers and show them how the pixels should be moved around until everything lines up.&lt;/li&gt;
&lt;/ol&gt;
&lt;img src='/images/badlayout.png' /&gt;&lt;cite&gt;Galloping baseline, overlapping elements, multiple colors, inconsistent spacing, no avatar image.&lt;/cite&gt;
&lt;h1 id='become_more_open'&gt;Become more open&lt;/h1&gt;

&lt;p&gt;Myspace should move their APIs over to the opengraph and do a staged deprecation of their current APIs. The focus should be on letting third party developers access the myspace data. Creative commons licences should be promoted and liberal licences should be granted to myspace data. Users should have control over their privacy, but anything that has been elected to be public should be shared freely and instantly, no more summary-only rss feeds, no obfuscated URLS, all public content should be freely and easily available.&lt;/p&gt;

&lt;h1 id='make_better_tools_for_bands'&gt;Make better tools for bands&lt;/h1&gt;

&lt;p&gt;The tools for bands to edit their tour schedule, keep in contact with the fans or maintain their page should have a UI overhaul. A nice, simple, ajaxified design that lets them get in, update their tour and music and then get out again. The bands data should be made available through APIs if the band decides too - so that myspace becomes the central location they manage their social media presence. For example, their myspace page should have a podcast url, their tour data should be syndicated out to upcoming, last.fm, they should be able to set creative commons (or other) licences on all their media.&lt;/p&gt;

&lt;h1 id='start_a_dialog_with_your_community'&gt;Start a dialog with your community&lt;/h1&gt;

&lt;p&gt;Most people think that Myspace is fucked. You need to start communicating on the myspace blog, often and always, and show the work that is being done to make Myspace a better place. You need to point out where Facebook fucked up and you did it right. You need to be seen to respond to users concerns about spam, about it being hard to delete profiles. You need to post screenshots of the new nicer user interface you&amp;#8217;re working on (here&amp;#8217;s the new inbox! here&amp;#8217;s a video of how the profile editor works).&lt;/p&gt;

&lt;p&gt;Finally, I don&amp;#8217;t know how the MySpace revenue model works, but they should invest in their advertising technology so that they can provide the best possible solution to their existing advertisers and attract new ones. The site needs to be profitable and strong on it&amp;#8217;s own account and that should be by high quality, targetted and effective advertising that doesn&amp;#8217;t detract from the user experience of the site.&lt;/p&gt;

&lt;p&gt;So that&amp;#8217;s my thoughts on building an a more agile, more profitable and more enjoyable Myspace. Competition is good and MS has the best opportunity of sticking it to FB.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Thoughts from someone leaving NZ</title>
   <link href="http://bnolan.github.com/2011/01/24/thoughts-from-someone-leaving.html"/>
   <updated>2011-01-24T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/24/thoughts-from-someone-leaving</id>
   <content type="html">&lt;p&gt;Since my girlfriend and I are leaving New Zealand for good probably, I decided I&amp;#8217;d write about the New Zealand economy from my opinion as a 30 year old. Take this with a grain of salt, as it is purely anecdotal, I don&amp;#8217;t have time to lookup citations for my observations.&lt;/p&gt;

&lt;h1 id='me'&gt;Me&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve started two business in New Zealand. One, Indigo, generated about 100k€ of export revenue in the first year, employed 5 staff and is growing faster than ever. My co-founder has just left New Zealand with the rest of the company so they can be closer to their export markets in Europe. My other business, Zoomin, employed a half dozen people and was part of the Wellington startup cluster that jumpstarted in 2006. Rissa and I are now off travelling around New Zealand in a van, then moving to Brisbane for a few months before travelling to either the US or Europe.&lt;/p&gt;

&lt;h1 id='its_expensive_here'&gt;It&amp;#8217;s expensive here&lt;/h1&gt;

&lt;p&gt;Food and entertainment are expensive. It&amp;#8217;s cheaper to shop at a Tengelmann supermarket in Munich using New Zealand dollars, than it is to shop at a New Zealand supermarket in New Zealand dollars. New Zealand cheese is cheaper in Australian supermarkets than in New Zealand supermarkets. It&amp;#8217;s interesting talking to European backpackers who are astounded at how expensive it is to travel around in New Zealand. $42 / night for a campground? $8 for sausages? $5 for a loaf of bread? $18 for a six-pack of beer?&lt;/p&gt;

&lt;h1 id='housing_is_expensive_here'&gt;Housing is expensive here&lt;/h1&gt;

&lt;p&gt;As an investment, I feel uncomfortable taking on an extra two years worth of salary as debt, when you don&amp;#8217;t need to take that much debt to buy a house in another country. It seems especially perverse because there is so much good available land that is undeveloped. We&amp;#8217;re not Japan or Germany.&lt;/p&gt;

&lt;h1 id='the_economy_is_overinvested_in_property_and_finance'&gt;The economy is overinvested in property and finance&lt;/h1&gt;

&lt;p&gt;The UK learnt that relying purely on investment in property and the financial markets wasn&amp;#8217;t a good idea over the past decade. They look at producing countries (like Germany, Japan and China) and realise that there is actual value in inventing technology, processes and processing businesses. New Zealand really only invests in the primary market and property. There are some well known exporters like Xero, but they&amp;#8217;re about 0.01% of our industry. And New Zealand doesn&amp;#8217;t seem to have realized yet that they need to become a strong economy in secondary industries (like processing, manufacturing, designing).&lt;/p&gt;

&lt;h1 id='new_zealand_should_have_a_distance_discount'&gt;New Zealand should have a distance discount&lt;/h1&gt;

&lt;p&gt;Being so far from our customers, investors and partners, people should have a discount to work in New Zealand. Instead it&amp;#8217;s more expensive to live in Wellington than to live in Munich.&lt;/p&gt;

&lt;h1 id='its_lovely_here'&gt;It&amp;#8217;s lovely here&lt;/h1&gt;

&lt;p&gt;I used to hate on New Zealand a bit much and I&amp;#8217;m sorry for that. It&amp;#8217;s really a beautiful country. The people are nice, the coffee is awesome. When things are slow, affordable and easy this is a wonderful country. The diving, beaches and mountain biking are off the hook.&lt;/p&gt;

&lt;h1 id='well_be_back'&gt;We&amp;#8217;ll be back&lt;/h1&gt;

&lt;p&gt;I hope that we&amp;#8217;ll be back in New Zealand to live, or at least for our holidays. My prediction is that the property market will stagnate for half a decade, while salaries slowly creep up to bring affordability back. This relies on the government taking steps to squash investment property (since investment property tax advantages make an investment property a more affordable purchase than a first home).&lt;/p&gt;

&lt;h1 id='affordability_is_good_for_everyone'&gt;Affordability is good for everyone&lt;/h1&gt;

&lt;p&gt;Part of the problem with the gap increasing between rich and poor, with people having to spend 120% of their salary to pay a mortgage, is that people are stressed out. I don&amp;#8217;t want to live on a street full of renters who live in cold, substandard housing. I don&amp;#8217;t want to live in a street of people who are working all hours and stressed out to meet their repayments.&lt;/p&gt;

&lt;h1 id='the_labour_government_was_atrocious'&gt;The labour government was atrocious&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m a Greens supporter, so in theory I should support Labour more than National, but Labour did absolutely nothing to protect New Zealands quality of life from the stupidity of the consumer debt bubble. It was John Key who did the first (half assed and limp wristed) attempts to redirect investment from the property sector into industry.&lt;/p&gt;

&lt;p&gt;In a perfect (unlikely) world, property investment would be limited purely to apartment complexes and fresh developments in subdivisions, and tax-breaks would be geared to encourage owner-occupiers in existing properties.&lt;/p&gt;

&lt;p&gt;Let&amp;#8217;s see what happens.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Heroku or Linode</title>
   <link href="http://bnolan.github.com/2011/01/20/heroku-or-linode.html"/>
   <updated>2011-01-20T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/20/heroku-or-linode</id>
   <content type="html">&lt;p&gt;The biggest problem I have with keeping my projects going is paying for and maintaining my servers. When you&amp;#8217;re consulting, $60/mo for a dedicated server isn&amp;#8217;t a big deal, but when it&amp;#8217;s seeing no real traffic growth and you have to be responsible for backups, updates and admin - I find that after 3-4 months I usually mothball a project and have one less thing to administer.&lt;/p&gt;

&lt;p&gt;Thus Twitterplaces, which was running on a dual-core 4gb box so it could index all the geo-tweets in the world. I left it run for about 6 months before taking it down. I&amp;#8217;m planning on releasing weheartplaces to the appstore before I head off on holiday - so I need to set up a production environment for it. My options as far as I can tell are:&lt;/p&gt;

&lt;h2 id='heroku'&gt;&lt;a href='http://heroku.com/'&gt;Heroku&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Pros:&lt;/em&gt; Managed rails hosting, don&amp;#8217;t have to do any admin, everything is backed up.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cons:&lt;/em&gt; Expensive (minimum of $50/month), no postgis.&lt;/p&gt;

&lt;h2 id='linode'&gt;&lt;a href='http://linode.com/'&gt;Linode&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Pros:&lt;/em&gt; Affordable ($20/month), can install whatever I like (Postgis / R / FastCGI scripts).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cons:&lt;/em&gt; Have to sysadmin and back it up myself.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m leaning towards linode at the moment since I already have one running diaspora-x.com, but I&amp;#8217;d like some feedback on this. I know that at some level I should put my app on Heroku - but maybe I can have it running on my 512mb linode for a few months while I see if there is any uptake in weheartplaces at all?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Quantitive measurement of bus drivers</title>
   <link href="http://bnolan.github.com/2011/01/19/bus-drivers.html"/>
   <updated>2011-01-19T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/19/bus-drivers</id>
   <content type="html">&lt;p&gt;I live in Wellington, New Zealand - and we&amp;#8217;re unlikely to get modern tramways for a while, but we do have an extensive bus network. Busses are pretty average compared to trams, but I don&amp;#8217;t think it has to be that way, and I&amp;#8217;d like to propose some quantitive measurements that can be done to ensure the quality of drivers of the busses.&lt;/p&gt;

&lt;p&gt;The main trick is to install a device in each bus that records the bus driver, the route, the timeliness of the route, comfort and fuel efficiency. You could use something like an android or iphone, since they have gps, accelerometers, a user interface and 3g connectivity.&lt;/p&gt;

&lt;h1 id='bus_driver'&gt;Bus driver&lt;/h1&gt;

&lt;p&gt;The bus driver gets on the bus, types their name into the phone and they are logged in. They then specify which route they are running and the measurement system can work out where the bus should be.&lt;/p&gt;

&lt;h1 id='timeliness'&gt;Timeliness&lt;/h1&gt;

&lt;p&gt;Measure the location of the bus against the measured stops. Use this data to show a timeliness report (as they do in Melbourne) and use this data to decide what changes need to be made to routes, traffic lights and bus lanes. Instead of drivers having to rely on anecdotal evidence, they can show why changes need to be made to each route, for example, a sector may need to be made longer or shorter, route timings changed.&lt;/p&gt;

&lt;p&gt;This could be done on an ongoing basis as traffic patterns change season by season.&lt;/p&gt;

&lt;h1 id='comfort'&gt;Comfort&lt;/h1&gt;

&lt;p&gt;This is a big one. The major problem with busses after timeliness, are bad drivers. The main factors of a bad driver:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Accelerate really hard, causing a huge amount of noise. If you&amp;#8217;ve ever seen a baby sitting in a pram on lambton quay when one of the old diesel busses accelerates away you&amp;#8217;ll know what I mean. This is uncomfortable for passengers, adds unneeded noise to the city, is dangerous for people on the street, promotes aggressive driving, and wastes fuel.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Drive too fast through corners. Some bus drivers drive their busses like race cars. And some driver their busses really carefully and considerately. The considerate drivers need to be rewarded.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Break too hard into a corner, don&amp;#8217;t predict the lights and coast to a stop.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By measuring the gps location and instantaneous acceleration 10 times a second, with the phone, or measurement device, mounted in a rigid cradle at the front of the bus, it would be possible to create a measurement for how smooth and efficient a bus driver was.&lt;/p&gt;

&lt;p&gt;It would be easy to measure when a bus driver wasn&amp;#8217;t driving smoothly and comfortable.&lt;/p&gt;

&lt;h1 id='learning_and_improving'&gt;Learning and improving&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m not sure what the best way to use this data would be. It seems like paying bonuses or penalizing bad drivers would be the most effective way to ensure a competition for smoothest driver, but I imagine there are kinder ways of rewarding correct behaviour.&lt;/p&gt;

&lt;p&gt;It would be very important for all measurements to be compared correctly against other drivers on the same route, on the same bus, and at the same time of day, as some routes would be by necessity more intense than others. If you&amp;#8217;ve taken the bus through vogeltown or roseneath you&amp;#8217;ll know it&amp;#8217;s a pretty windy path.&lt;/p&gt;

&lt;p&gt;It would also be important for the data to be used to make changes at the roading and management level as well, instead of just passing the buck onto bus drivers and expecting them to do miracles. Wellington City Council should improve busways where needed, relying on real data, not anecdotes. And the bus company management should be made accountable as well.&lt;/p&gt;

&lt;p&gt;Especially for buying the bad old MAN busses that are wheelchair-hostile and noisy as hell.&lt;/p&gt;

&lt;h1 id='public_data'&gt;Public data&lt;/h1&gt;

&lt;p&gt;Finally, all this data should be publically available (in an suitably anonymized, aggregate form) so that ratepayers know that they are getting value for money from their subsidised bus service.&lt;/p&gt;

&lt;p&gt;(If anyone actually wants this thing to be built and exist, I&amp;#8217;d recommend getting a local company like youdo, southgate or silverstripe to build it)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Weheartiphone</title>
   <link href="http://bnolan.github.com/2011/01/18/weheartiphone.html"/>
   <updated>2011-01-18T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/18/weheartiphone</id>
   <content type="html">&lt;p&gt;I got inspired by the design of &lt;a href='http://itunes.apple.com/nz/app/plaintext-dropbox-text-editing/id391254385?mt=8'&gt;plaintext&lt;/a&gt; and redesigned my phonegap app. Weheartplaces is an app for bookmarking places and accessing them on the go. It syncs with your facebook account so that in the future you&amp;#8217;ll be able to see your friends bookmarks and send bookmarks to friends.&lt;/p&gt;
&lt;img src='/images/weheart.png' /&gt;</content>
 </entry>
 
 <entry>
   <title>Koala for facebook</title>
   <link href="http://bnolan.github.com/2011/01/17/koala-for-facebook.html"/>
   <updated>2011-01-17T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/17/koala-for-facebook</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been using &lt;a href='https://github.com/arsduo/koala/wiki/'&gt;Koala&lt;/a&gt; + Facebook connect for facebook development in rails. It&amp;#8217;s an awesome tool for exploring the graph API using pure rails. You don&amp;#8217;t need to use devise to do your authentication, just facebook connect, then take the access token and then you have access to the facebook api as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@oauth = Koala::Facebook::OAuth.new(app_id, code, callback_url)
@oauth.get_user_info_from_cookies(cookies)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s interesting when deciding where to use APIs like facebook or the google maps geocoder api. Should you do it client side, and reduce load on your server, but add the complexity of handling state and large amounts of data in an environment that&amp;#8217;s not really designed for it - or do you do it client side and increase your ops cost?&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s still a hairy one I haven&amp;#8217;t decided. One of the classic problems is when people search on a social mapping site (like weheartplaces):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/places/search?query=Eiffel+Tower
/places/search?query=Nelson,+New+Zealand&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You want to look for any places called &lt;code&gt;eiffel tower&lt;/code&gt; in your database (probably using tsearch2), but you also want to run the search through a geocoder to see if the user actually searched for a city. And you need to do some kind of combinatorial weighting function to work out what was the most likely result for a given query.&lt;/p&gt;

&lt;p&gt;The best way to do that is to gather data on the server side so that you can train your weighting function based on previous results and what the user was actually looking for.&lt;/p&gt;

&lt;p&gt;Pure javascript and focus on the UI? Or a strong back-end service and focus on the data quality? Or both? And never finish the project.&lt;/p&gt;

&lt;p&gt;;D&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Capt in production</title>
   <link href="http://bnolan.github.com/2011/01/14/capt-production.html"/>
   <updated>2011-01-14T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/14/capt-production</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve added some features to &lt;a href='http://github.com/bnolan/capt'&gt;capt&lt;/a&gt;, it&amp;#8217;s still very rough and needs a lot more work, but it&amp;#8217;s coming together. Added recently:&lt;/p&gt;

&lt;h1 id='build_command'&gt;Build command&lt;/h1&gt;

&lt;p&gt;Run &lt;code&gt;capt build iphone&lt;/code&gt; to create a build in &lt;code&gt;builds/iphone&lt;/code&gt; that will compile all coffeescript, concatenate and minify all scripts, compile all the less into css and run the yui compressor over it, then create an index.html from your index.jst, with only two files as an include.&lt;/p&gt;

&lt;h1 id='added_support_for_targets_in_the_configyml'&gt;Added support for targets in the config.yml&lt;/h1&gt;

&lt;p&gt;I have this on my config.yml:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;iphone:
  lib/phonegap.js
  platforms/iphone.coffee&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are included only when developing against the iphone, and are all merged into one file for production. I do the same for nokia (which requires json.js and some special code to deal with the nokia webruntime).&lt;/p&gt;

&lt;h1 id='more_test_support'&gt;More test support&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve improved the testing templates, but I still need to get a command line test environment running - basically type &lt;code&gt;capt test&lt;/code&gt; and have it run the whole test suite using node.js and jsdom.&lt;/p&gt;

&lt;h1 id='future_of_capt'&gt;Future of capt&lt;/h1&gt;

&lt;p&gt;I doubt the first decent release of capt will be prior to April, since I&amp;#8217;m heading away on a campervan holiday of new zealand for 2 months, but keep an eye out then, and feel free to fork and send pull requests in the meantime.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Jquery Mobile or not</title>
   <link href="http://bnolan.github.com/2011/01/13/jquery-mobile-or-not.html"/>
   <updated>2011-01-13T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/13/jquery-mobile-or-not</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working on &lt;a href='http://weheartplaces.com/'&gt;weheartplaces&lt;/a&gt; again, trying to get it into the appstores and out the door. I used capt to build the bundled and compressed javascript, and using jquery mobile, the closure compiled code was 161k.&lt;/p&gt;

&lt;p&gt;I removed jquery and jquery mobile and replaced it with zepto.js. It took about an hour or so to recode a minimal CSS theme that replaces all the jquery mobile functionality (with the exception of fixed position viewports) and the resulting closure compiled code was 41k.&lt;/p&gt;

&lt;p&gt;The huge difference was in application startup time, and in less crashes on the actual device. On the simulator, the javascript compiles instantly, but on my 2g iphone (same as a 3g iphone processor), the app starts in 4 seconds, instead of the previous 8. It&amp;#8217;s also smoother page to page and the user interactivity is quicker.&lt;/p&gt;

&lt;p&gt;jQuery mobile is fantastic and I may end up going back to it - but for now I&amp;#8217;m going to do my mobile development using jquery.js (zepto doesn&amp;#8217;t work on Nokia), backbone.js and a custom stylesheet. I&amp;#8217;ll put up some screenshots of the new weheartplaces mobile app shortly.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>2011 - the year of pure javascript apps</title>
   <link href="http://bnolan.github.com/2011/01/12/pure-javascript-apps.html"/>
   <updated>2011-01-12T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/12/pure-javascript-apps</id>
   <content type="html">&lt;p&gt;Pure javascript apps, or apps that use javascript for all the presentation have been coming to prominence for years.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google maps 2007&lt;/li&gt;

&lt;li&gt;Phonegap 2008&lt;/li&gt;

&lt;li&gt;Facebook 2009&lt;/li&gt;

&lt;li&gt;Twitter 2010&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It&amp;#8217;s an obvious prediction, but 2011 will probably have a lot more javascript apps being released. From mobile - where phonegap is so important to smaller companies that can&amp;#8217;t afford to redevelop an app natively in Java and Objective C - through to &amp;#8216;desktop&amp;#8217; web apps like the twitter client.&lt;/p&gt;

&lt;p&gt;Some of the key technologies that I peg for uptake this year:&lt;/p&gt;

&lt;h1 id='coffeescript'&gt;CoffeeScript&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m a big fan of this. It&amp;#8217;s easy to learn (if you&amp;#8217;re open minded and don&amp;#8217;t try to be too clever), and makes javascript immeasurably more pleasurable to write. It&amp;#8217;s basically a whitespace aware javascript compiler, so it does away with all the curly brackets, replaces &lt;code&gt;function&lt;/code&gt; with &lt;code&gt;-&amp;gt;&lt;/code&gt; and has very nice built in prototype-based class support.&lt;/p&gt;

&lt;h1 id='couchdb'&gt;CouchDB&lt;/h1&gt;

&lt;p&gt;This one I&amp;#8217;m not so sure about. Couch is really amazing for creating pure javascript apps, since you don&amp;#8217;t require a middleware, you can put business logic into the database layer (rules are written in javascript) and they talk JSON to your javascript app. The downsides with couch are that it is a bit of a mindfuck to get used to, coming from a relational background. Also, the couchapps / authentication / client-facing parts of couch are relatively new and I think there needs to be a lot of work on documentation and frameworks to make client-facing couch apps easier. So, couch for indie developers making pure javascript apps - watch out for this.&lt;/p&gt;

&lt;h1 id='backbonejs'&gt;Backbone.js&lt;/h1&gt;

&lt;p&gt;There are a dozen or so javascript MVC frameworks. I imagine they&amp;#8217;ll all take off (javascriptmvc, backbone, ext..), but the one I really like is backbone. It&amp;#8217;s pure javascript, plays nicely with Zepto (a tiny implementation of jquery for webkit-mobile) and works well with coffeescript. It&amp;#8217;s very event based, so some parts are really great (like redraweing the UI when an item in a collection changes), but it&amp;#8217;ll be interesting to see how it progresses over the year, hopefully some great tutorials come out of it and it&amp;#8217;ll become a dominant force in javascript development.&lt;/p&gt;

&lt;h1 id='phonegap'&gt;Phonegap&lt;/h1&gt;

&lt;p&gt;I know that mobile apps written in phonegap are seldom as good as native apps, and a well written native app will always be better than an html+css app, but phonegap is just going to get better and better this year. If you look through the &lt;a href='https://github.com/purplecabbage/phonegap-plugins'&gt;phonegap plugins&lt;/a&gt; for each platform, there are some great bits, like the email connector and child browsers.&lt;/p&gt;

&lt;h1 id='nodejs'&gt;Node.js&lt;/h1&gt;

&lt;p&gt;To finish off, node.js. Node is a bit of a mixed bad. It&amp;#8217;s awesome because everything is async, it compiles easily, is very fast and seems to be reliable. On the downside, the API changes like a bitch, constantly. Any code you wrote for node 6 weeks ago, probably won&amp;#8217;t work anymore. I appreciate that it&amp;#8217;s a pre 1.0 project, and they&amp;#8217;re trying to work out how to do everything in the best possible way, but if development really needs to stabilise around some core areas soon (like socket programming).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CouchDB OAuth</title>
   <link href="http://bnolan.github.com/2011/01/11/couchdb-oath.html"/>
   <updated>2011-01-11T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/11/couchdb-oath</id>
   <content type="html">&lt;p&gt;I think couchdb is a good solution for creating pure javascript apps, but there are a few big problems with using a service like clouddb, particulary around authentication. There already exists a couchdb oauth module, but afaict, it&amp;#8217;s for authenticating against couchdb, not for creating a couchdb account against a twitter or facebook account.&lt;/p&gt;

&lt;p&gt;If someone like couchone added a simple way to implement an oauth consumer in their apps, it&amp;#8217;d be a really fantastic way to prototype apps. You could authenticate using javascript against twitter, google or facebook - create the users account and database, and then return them to your application, all without writing any server side code.&lt;/p&gt;

&lt;p&gt;The current couchdb authentication is a bit basic and doesn&amp;#8217;t support password reset or email verification, and you can&amp;#8217;t really build such things as couch apps.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Couchdb behind Apache</title>
   <link href="http://bnolan.github.com/2011/01/10/couchdb-behind-apache.html"/>
   <updated>2011-01-10T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/10/couchdb-behind-apache</id>
   <content type="html">&lt;p&gt;I had some issues getting couchdb to work correctly behind Apache. The big problem I was getting was that cross-domain requests were being &amp;#8220;preflighted&amp;#8221; where the browser sends an &lt;code&gt;OPTIONS&lt;/code&gt; request to the server, which was being proxied to Couchdb - which was returning error 405, since couch doesn&amp;#8217;t support the OPTIONS method.&lt;/p&gt;

&lt;p&gt;Here is the complete virtualhost setup for giving your localhost apps cross-domain access to couchone.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;VirtualHost *:80&amp;gt;
        ServerName mycouch.com

        Header set Access-Control-Allow-Origin &amp;quot;*&amp;quot;
        Header set Access-Control-Allow-Headers Content-Type
        Header set Access-Control-Allow-Methods &amp;quot;GET, PUT, OPTIONS, DELETE, POST&amp;quot;
        Header set Access-Control-Max-Age 3600

        ProxyPass / http://mycouch.couchone.com/ nocanon
        ProxyPassReverse / http://mycouch.couchone.com/

        RewriteEngine On
        RewriteCond %{REQUEST_METHOD} ^OPTIONS
        RewriteRule .* /index.html [L]
&amp;lt;/VirtualHost&amp;gt;&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Backbone and couchdb</title>
   <link href="http://bnolan.github.com/2011/01/07/backbone-couchdb.html"/>
   <updated>2011-01-07T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2011/01/07/backbone-couchdb</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been using the &lt;a href='https://github.com/janmonschke/backbone-couchdb'&gt;backbone-couchdb&lt;/a&gt; connector by Jan and I&amp;#8217;ve been impressed. The real showstopper is realtime updates using the &lt;em&gt;changes feed from couchdb.&lt;/em&gt;&lt;/p&gt;

&lt;h1 id='background'&gt;Background&lt;/h1&gt;

&lt;p&gt;For complex geospatial apps, you can&amp;#8217;t go past rails + postgis as a toolchain, but for simpler apps where you do all of the work on the front end and basically need a hash store, rails is overkill.&lt;/p&gt;

&lt;p&gt;Instead of having to run &lt;code&gt;rake migrate&lt;/code&gt; everytime you want to add a column, you just write to the backbone model, call save and it&amp;#8217;s serialized away into your document store.&lt;/p&gt;

&lt;h1 id='schemaless_stores'&gt;Schemaless stores&lt;/h1&gt;

&lt;p&gt;It&amp;#8217;s possible to use postgres in a schemaless way by either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Autogenerating columns as they are referred to&lt;/li&gt;

&lt;li&gt;Serializing all the columns into a blob&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it makes sense to investigate databases that are designed for the purpose. The two I have experience with are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MongoDB&lt;/li&gt;

&lt;li&gt;CouchDB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are good solutions, I&amp;#8217;ve used MongoDB extensively with node and it&amp;#8217;s json support is very good. I was interested in trying out couch since it is an almost pure-javascript solution, with javascript views and support for couchapps.&lt;/p&gt;

&lt;p&gt;CouchDB also runs well without any middleware, your app talks directly to the database.&lt;/p&gt;

&lt;h1 id='backbonecouchdb'&gt;Backbone-couchdb&lt;/h1&gt;

&lt;p&gt;&lt;a href='http://documentcloud.github.com/backbone/'&gt;Backbone&lt;/a&gt;, if you haven&amp;#8217;t seen it - is an excellent tool to give structure to your javascript applications. I use it extensively. One of the great benefits of backbone is the use of models and collections, both of which emit events when their contents change.&lt;/p&gt;

&lt;p&gt;So say you have a list of &lt;code&gt;posts&lt;/code&gt; on the left side of your page, you bind your &lt;code&gt;render()&lt;/code&gt; (or redraw) function to the &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; events of the Posts collection and the list will always be up-to-date. For example - if you opened your javascript console and typed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Posts.add(new Post(content : &amp;quot;Hello world!&amp;quot;))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All the dom elements will be automatically created and the posts list redrawn.&lt;/p&gt;

&lt;p&gt;Backbone by default doesn&amp;#8217;t come with any persistence layer. Models and collections are stored as javascript variables and they are lost when the page is refreshed. You can persist using the build-in sync methods that submits json to a server. Backbone uses the rails idioms for this, although it&amp;#8217;s easy enough to update Backbone.sync to work with other datastores / application frameworks.&lt;/p&gt;

&lt;p&gt;You can also use the localStorage plugin to persist your models to the browser. The &lt;a href='https://github.com/janmonschke/backbone-couchdb'&gt;backbone-couchdb&lt;/a&gt; persists your models to the couchdb store, so whenever you call save, it posts your model to the server - and when you reload the page, it loads all your models from the server.&lt;/p&gt;

&lt;p&gt;And because it&amp;#8217;s couchdb, all you have to do is create the database record in futon (one click) and all the models are automatically saved away, the database doesn&amp;#8217;t need to be aware of what you&amp;#8217;re saving, it just saves.&lt;/p&gt;

&lt;h1 id='the_magic_of_realtime'&gt;The magic of realtime&lt;/h1&gt;

&lt;p&gt;The magic part of this is the &lt;code&gt;_changes&lt;/code&gt; feed from couchdb. A client can request the _changes feed by doing an ajax request. Couchdb will then block (ala long polling) until there are changes on the database, at which point it will send down json and close the connection. The client processes these changes (updating collections and models as needed) and then reopens the connection to the &lt;em&gt;changes feed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And because you are already re-rendering your UI whenever a collection changes, you can see in realtime what anyone else is doing on the same dataset that you are using.&lt;/p&gt;

&lt;h1 id='couchone'&gt;Couchone&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m using &lt;a href='http://couchone.com/'&gt;couchone&lt;/a&gt; to host my couch databases. It&amp;#8217;s a great service, the only downside is that you can&amp;#8217;t set &lt;a href='http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/'&gt;Access-Control-Allow-Origin&lt;/a&gt; headers, which would let you do cross-domain ajax calls (so you can host your app at github and store your database at couchone). I got around this by proxing through my linode box, but this kills performance. Hopefully the couchone guys will give you the option to change the headers (they could use varnish or similar).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Diaspora-X speedups</title>
   <link href="http://bnolan.github.com/2010/12/30/diaspora-x-speedups.html"/>
   <updated>2010-12-30T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/30/diaspora-x-speedups</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m back from a week on the Australian beaches (I recommend surf lessons at Coolum and the breaks down at Burleigh heads) and at a wicked little festival (Blah blah blah is a highly recommended party), so it&amp;#8217;s time to fix up a few issues that were raised while I was away.&lt;/p&gt;

&lt;p&gt;About two weeks ago I wrote &lt;a href='https://github.com/bnolan/diaspora-x2'&gt;Diaspora x²&lt;/a&gt;, a port of the Diaspora UI to pure Javascript. My original Diaspora-xmpp port used rails and xmpp4r to federate by XMPP. It was a good idea, but I&amp;#8217;m much more at home using javascript that rails, and there was a lot of work required to get the xmpp connector working reliably at high loads.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s why I got strophe.js, which is a javascript library for doing xmpp over the http transport, &lt;a href='http://xmpp.org/extensions/xep-0206.html'&gt;bosh&lt;/a&gt;. The result was diaspora-x2, which is now online at diaspora-x.com.&lt;/p&gt;

&lt;p&gt;All well and good - but the first release was REALLY slow. Todays fixups:&lt;/p&gt;

&lt;h2 id='queue_rendering_calls'&gt;Queue rendering calls&lt;/h2&gt;

&lt;p&gt;My views watch the posts collection for add and remove events. So an xmpp message comes in, it gets added to the posts collection, and then the view re-renders. The problem is, the way bosh batches messages together means that I often iterate over a 100+ messages, and add them one by one to the collection. This then triggers a 100+ &lt;code&gt;render()&lt;/code&gt; calls, each of which constructs a big string, the string is parsed, then the elements are added to the dom, then they&amp;#8217;re all deleted and it starts again.&lt;/p&gt;

&lt;p&gt;Super easy fix that it applicable to a lot of backbone apps:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;render: -&amp;gt;
  @el.html(@template())&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Replace with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;render: -&amp;gt;
  if @renderTimeout
    clearTimeout @renderTimeout
  
  @renderTimeout = setTimeout( =&amp;gt;
    @el.html(@template())
  , 50)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only downside to this is that you have to make your view tests async.&lt;/p&gt;

&lt;h2 id='better_rendering'&gt;Better rendering&lt;/h2&gt;

&lt;p&gt;The bigger problem is that because the entire posts wall gets re-rendered everytime theres an update means that anything you were typing into an inline textbox will get annihilated. I&amp;#8217;ll be fixing this by progressively inserting and removing dom elements when the collection changes. Ordering will be done by having a &lt;code&gt;data-created-at&lt;/code&gt; attribute on the elements, so you select the dom elements, then move down the list until you get to the correct element and insert.&lt;/p&gt;

&lt;h2 id='embedly'&gt;Embed.ly&lt;/h2&gt;

&lt;p&gt;This will let me re-enable embed.ly, so that we can have cool inline media, like soundcloud tracks, youtube videos or flickr photos.&lt;/p&gt;

&lt;h2 id='media_upload'&gt;Media upload&lt;/h2&gt;

&lt;p&gt;I want to enable &lt;a href='http://html5doctor.com/native-drag-and-drop/'&gt;drag and drop&lt;/a&gt; media sharing, where the user selects which service they want to host the media. By default we could support imgur, then the user drag/drops images up and they get uploaded to imgur and then post the text link.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A good cofounder</title>
   <link href="http://bnolan.github.com/2010/12/19/a-good-cofounder.html"/>
   <updated>2010-12-19T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/19/a-good-cofounder</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve had the good fortune to have had a co-founder in both of the startups I&amp;#8217;ve been involved with. Given the option, I would always elect to start a business with someone else.&lt;/p&gt;

&lt;p&gt;However - before you meet your next cofounder, there will be a period of time where you work on your own idea. Before I founded Zoomin (which we almost, but not quite, sold to a multinational), I worked on the prototype (a social mapping site) for about 4 months.&lt;/p&gt;

&lt;p&gt;In a lot of projects, you will have to be a one man band for a while. You&amp;#8217;ll have to promote yourself, develop the software, motivate yourself everyone morning.&lt;/p&gt;

&lt;p&gt;From prior experience, I know that I can do all of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Talk to people and investigate the market (research)&lt;/li&gt;

&lt;li&gt;Code, architect and design (development)&lt;/li&gt;

&lt;li&gt;Sysadmin, keep records and pay taxes (operations)&lt;/li&gt;

&lt;li&gt;&amp;#8220;Do marketing&amp;#8221; and write blog posts (promotion)&lt;/li&gt;

&lt;li&gt;Set a price and ensure people pay (revenue)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The things is&amp;#8230; &lt;em&gt;I don&amp;#8217;t think anyone who tries to build a business ever realizes how hard it is going to be - before they set out.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>This week</title>
   <link href="http://bnolan.github.com/2010/12/17/this-week.html"/>
   <updated>2010-12-17T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/17/this-week</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s time to drink a beer and write a blog post. This week I worked on diaspora-x squared, an xmpp client written using javascript. It uses strophe.js and backbone.js. I had a few issues that needed attention with backbone:&lt;/p&gt;

&lt;h1 id='multiple_render_calls'&gt;Multiple render calls&lt;/h1&gt;

&lt;p&gt;I was receiving xmpp stanzas and inserting them into a backbone collection. The collection was firing the &lt;code&gt;add&lt;/code&gt; event and I had hooked that to call &lt;code&gt;this.render&lt;/code&gt;. That meant that I was calling render (and the browser was parsing html, creating dom nodes and reflowing the layout) about 30 times in a row, which is fucking inefficient (even though the browser never rendered the nodes).&lt;/p&gt;

&lt;p&gt;This could be fixed by putting in a 20ms timeout before calling &lt;code&gt;this.render&lt;/code&gt;, and canceling the timeout when a subsequent update request came in (you need to make the timeouts at least 20ms or some browsers will call the timeout immediately).&lt;/p&gt;

&lt;h1 id='localstorage'&gt;LocalStorage&lt;/h1&gt;

&lt;p&gt;I didn&amp;#8217;t implement localStorage to cache the previously received xmpp stanzas, mainly because there is no localStorage support built into backbone. I know that backbone is meant to stay lightweight and tiny, but it would be nice if the localStorage store was &amp;#8220;officially supported&amp;#8221;, then I&amp;#8217;d use it more often.&lt;/p&gt;

&lt;h1 id='confusion_about_submitting_forms'&gt;Confusion about submitting forms&lt;/h1&gt;

&lt;p&gt;When I write form submission code, I do it in a view - so the view has a &lt;code&gt;submit&lt;/code&gt; method which is hooked using the delegateEvents method on form submission. I end up processing the form entry, saving the model, adding it to a collection and then doing a redirect (using window.location.hash), all in the view. Some of this code feels like it should be in the controller, but I&amp;#8217;m not sure how to do that. Maybe I&amp;#8217;m just getting confused with the rails way of doing things.&lt;/p&gt;

&lt;h1 id='adding_production_support_to_capt'&gt;Adding production support to capt&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve used &lt;code&gt;capt&lt;/code&gt; (my code generation / development mode server tool for creating backbone apps) to build two apps now and it really is a good tool. I need to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production mode (concatenate files in order, run through closure)&lt;/li&gt;

&lt;li&gt;Server side coffeescript processing (not really needed, but a nice to have, esp. with growl support)&lt;/li&gt;

&lt;li&gt;Working test framework (I am generating test cases but haven&amp;#8217;t been running them, need an easier way to do so)&lt;/li&gt;

&lt;li&gt;Documentation and promotion (so that people learn about it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interesting week all the same. I had two really good days in the flow (2000 loc on thursday, about 800 loc today). Invented two nice things, an xmpp-pubsub social network (diaspora-x2) and a bookmarklet that scrapes geodata from a currently open page (for adding places to weheartplaces).&lt;/p&gt;

&lt;h1 id='two_levels_deep'&gt;Two levels deep&lt;/h1&gt;

&lt;p&gt;In my weheartplaces bookmarklet, I use this bit of code to search the dom for any google maps instances in the first two layers of the dom, and then extract the lat/long of the map and use it for the bookmarklet:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if google? and google.maps? and google.maps.Map
  maps = []

  # Search two levels deep...

  for k,v of window when v instanceof Object
    if v instanceof google.maps.Map
      maps.push v
    else
      for i,j of v when j instanceof Object
        if j instanceof google.maps.Map
          maps.push j

  for map in maps when map.getCenter
    try
      attributes.geo.push [map.getCenter().lat(), map.getCenter().lng()].join(&amp;quot;, &amp;quot;)    
    catch e
      # ...

  for map in maps when map.getCenterLatLng
    try
      attributes.geo.push [map.getCenterLatLng().lat(), map.getCenterLatLng().lng()].join(&amp;quot;, &amp;quot;)    
    catch e
      # ...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Works really well. Quite stoked. I&amp;#8217;ll try and release the weheartplaces bookmarklet next week.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Attacked by wheelchair!</title>
   <link href="http://bnolan.github.com/2010/12/14/attacked-by-wheelchair.html"/>
   <updated>2010-12-14T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/14/attacked-by-wheelchair</id>
   <content type="html">&lt;p&gt;Bwahahaha &lt;a href='http://bit.ly/f9SzAH'&gt;the bbc&lt;/a&gt;. The world media is really doing a great job of acting like fucks at the moment. My favourite quotes from this video: &amp;#8220;There are allegations you were rolling your wheelchair towards the police&amp;#8221; and (to the cerebal palsy sufferer) &amp;#8220;There were people throwing chunks of concrete at the police. Were you throwing things at the police&amp;#8221;.&lt;/p&gt;
&lt;object height='240' width='360'&gt;&lt;param name='movie' value='http://www.youtube.com/v/tXNJ3MZ-AUo?fs=1&amp;amp;hl=en_US' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;embed src='http://www.youtube.com/v/tXNJ3MZ-AUo?fs=1&amp;amp;hl=en_US' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='240' width='360' /&gt;&lt;/object&gt;
&lt;p&gt;Those riot police do earn their money though. Just imagine standing there, in the open, having a guy in a wheelchair rolling towards you.&lt;/p&gt;

&lt;p&gt;Fucking terrifying.&lt;/p&gt;

&lt;p&gt;To be honest, the police did have riot gear to protect themselves.&lt;/p&gt;

&lt;p&gt;And there were hundreds of them.&lt;/p&gt;

&lt;p&gt;But the dude had a FUCKING WHEELCHAIR!&lt;/p&gt;

&lt;p&gt;Those wheelchairs are pretty much a deadly weapon.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Capt, a tool for backbone.js</title>
   <link href="http://bnolan.github.com/2010/12/13/capt-a-tool-for-backbone.html"/>
   <updated>2010-12-13T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/13/capt-a-tool-for-backbone</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working on &lt;a href='http://github.com/bnolan/capt'&gt;capt&lt;/a&gt; for a few days now, so I wanted to write an introductory post. Capt is a tool for generating and serving backbone.js projects in development mode. It&amp;#8217;s currently tooled for my personal toolchain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jQuery&lt;/li&gt;

&lt;li&gt;Backbone.js&lt;/li&gt;

&lt;li&gt;Underscore.js&lt;/li&gt;

&lt;li&gt;QUnit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can imagine capt as a combination of jamit and the rails code generators. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; $ capt new blogproject
 * Creating folders
 * Downloading libraries&lt;/code&gt;&lt;/pre&gt;
&lt;cite&gt;Create a new project&lt;/cite&gt;
&lt;pre&gt;&lt;code&gt;$ find blogproject
blogproject
blogproject/app
blogproject/app/controllers
blogproject/app/models
blogproject/app/views
blogproject/app/views/jst
blogproject/config.yml
blogproject/index.jst
blogproject/lib
blogproject/lib/backbone.js
blogproject/lib/coffeescript.js
blogproject/lib/jquery.js
blogproject/lib/underscore.js
blogproject/public
blogproject/public/stylesheets
blogproject/test
blogproject/test/controllers
blogproject/test/fixtures
blogproject/test/models
blogproject/test/qunit.css
blogproject/test/qunit.js
blogproject/test/views&lt;/code&gt;&lt;/pre&gt;
&lt;cite&gt;File structure&lt;/cite&gt;
&lt;pre&gt;&lt;code&gt;$ capt generate model post
Created app/models/post.coffee
Created test/models/post.coffee
Created test/fixtures/post.yml

$ capt generate model comment
Created app/models/comment.coffee
Created test/models/comment.coffee
Created test/fixtures/comment.yml&lt;/code&gt;&lt;/pre&gt;
&lt;cite&gt;Create models and tests&lt;/cite&gt;
&lt;pre&gt;&lt;code&gt;$ capt server
node-router server instance at http://*:3000/&lt;/code&gt;&lt;/pre&gt;
&lt;cite&gt;Start a webserver in production mode&lt;/cite&gt;
&lt;p&gt;Capt is written in coffeescript and uses node.js (I&amp;#8217;ll distribute it by npm once it&amp;#8217;s done), but at the moment is just for client work, it does server side processing to automatically include the correct files, but you&amp;#8217;re not meant to develop node apps with it, it&amp;#8217;s for developeing client apps.&lt;/p&gt;

&lt;p&gt;You can then browse to /index.html and it&amp;#8217;ll automatically include all the correct files in the order specified in config.yml. You can also browse to /test/ and it&amp;#8217;ll run the auto generated tests.&lt;/p&gt;
&lt;img src='/images/capt-test.png' /&gt;&lt;cite&gt;The default generated tests running in qunit&lt;/cite&gt;
&lt;p&gt;It&amp;#8217;ll be a while until there&amp;#8217;s a good first release (I might take the current random code and covert it to use Cake for example), but here&amp;#8217;s a headsup if anyone it working on something similar.&lt;/p&gt;

&lt;h1 id='production_targets_and_textmate'&gt;Production targets and textmate&lt;/h1&gt;

&lt;p&gt;Once I&amp;#8217;ve got things going - I want to have a few production targets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nokia WRT&lt;/li&gt;

&lt;li&gt;Phonegap&lt;/li&gt;

&lt;li&gt;HTML5 standalone w/ manifest&lt;/li&gt;

&lt;li&gt;Web deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a one line command to package up the project into one closure-ified project. I also want to create a textmate bundle for running the tests from within textmate by hitting command+r - like you can do with rspec. I&amp;#8217;d like the tests to run within the node jsdom project, so you don&amp;#8217;t need to remote control a browser, but I&amp;#8217;m not sure how well that will work on large projects.&lt;/p&gt;

&lt;p&gt;Anyway - I&amp;#8217;ll keep you updated.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Visa is down</title>
   <link href="http://bnolan.github.com/2010/12/09/visa-is-down.html"/>
   <updated>2010-12-09T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/09/visa-is-down</id>
   <content type="html">&lt;p&gt;Visa.com and mastercard.com are down (as of 3pm Thursday in New Zealand) from the &lt;a href='https://github.com/NewEraCracker/LOIC/downloads'&gt;anonymous&lt;/a&gt; &lt;a href='http://en.wikipedia.org/wiki/Denial-of-service_attack'&gt;ddos&lt;/a&gt;. For my part, I made a protest sign that shows my feeling about how Sweden is acting as an independent and sovereign nation with respect to Julian Assange:&lt;/p&gt;
&lt;img src='/images/sweden.png' /&gt;&lt;cite&gt;Sweden, Americas Bitch&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Social network over XMPP</title>
   <link href="http://bnolan.github.com/2010/12/08/Social-network-over-xmpp.html"/>
   <updated>2010-12-08T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/08/Social-network-over-xmpp</id>
   <content type="html">&lt;p&gt;I thought I&amp;#8217;d do a post showing how a social network over XMPP works. This isn&amp;#8217;t any invention of mine, I&amp;#8217;ll just point to the relevant specs and give my understanding of how it can work. I&amp;#8217;m not an XMPP &lt;a href='http://www.buddycloud.com/'&gt;expert&lt;/a&gt; though, so take this with a pinch of salt.&lt;/p&gt;

&lt;h1 id='user_ids'&gt;User IDS&lt;/h1&gt;

&lt;p&gt;Users are identified by their jabber id, which looks like an email address - eg: &lt;code&gt;bnolan@gmail.com&lt;/code&gt; or &lt;code&gt;ben@diaspora-x.com&lt;/code&gt;. Users have to be associated with a jabber server, but they can use any client they want. For example I could use diaspora-x.com to access my bnolan@gmail.com jabber account.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;nb:&lt;/em&gt; Diaspora-x won&amp;#8217;t support gmail as a jabber server until gtalk supports &lt;a href='http://www.google.com/support/forum/p/Talk/thread?tid=2c8f523795126684&amp;amp;hl=en'&gt;oauth&lt;/a&gt;, since otherwise a diaspora-x seed would have to store google account passwords.&lt;/p&gt;

&lt;h1 id='pubsub'&gt;Pubsub&lt;/h1&gt;

&lt;p&gt;XMPP supports publish/subscribe via &lt;a href='http://xmpp.org/extensions/xep-0060.html'&gt;XEP-0060&lt;/a&gt;. This means that you can send a message to your xmpp server, with no to address specified. Everyone on your roster who is subscribing for those kind of events will get your message. If someone on your roster is offline, their xmpp server will store your message until they come back online.&lt;/p&gt;

&lt;h1 id='personal_eventing_protocol'&gt;Personal eventing protocol&lt;/h1&gt;

&lt;p&gt;&lt;a href='http://xmpp.org/extensions/xep-0163.html'&gt;XEP-0163&lt;/a&gt; describes how any jabber user can act as a virtual pubsub service, and send their own status / events.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;iq from=&amp;#39;juliet@capulet.lit/balcony&amp;#39; type=&amp;#39;set&amp;#39; id=&amp;#39;pub1&amp;#39;&amp;gt;
  &amp;lt;pubsub xmlns=&amp;#39;http://jabber.org/protocol/pubsub&amp;#39;&amp;gt;
    &amp;lt;publish node=&amp;#39;http://jabber.org/protocol/tune&amp;#39;&amp;gt;
      &amp;lt;item&amp;gt;
        &amp;lt;tune xmlns=&amp;#39;http://jabber.org/protocol/tune&amp;#39;&amp;gt;
          &amp;lt;artist&amp;gt;Gerald Finzi&amp;lt;/artist&amp;gt;
          &amp;lt;length&amp;gt;255&amp;lt;/length&amp;gt;
          &amp;lt;source&amp;gt;Music for &amp;quot;Love&amp;#39;s Labors Lost&amp;quot; (Suite for small orchestra)&amp;lt;/source&amp;gt;
          &amp;lt;title&amp;gt;Introduction (Allegro vigoroso)&amp;lt;/title&amp;gt;
          &amp;lt;track&amp;gt;1&amp;lt;/track&amp;gt;
        &amp;lt;/tune&amp;gt;
      &amp;lt;/item&amp;gt;
    &amp;lt;/publish&amp;gt;
  &amp;lt;/pubsub&amp;gt;
&amp;lt;/iq&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;cite&gt;Sending a song update using the tunes extension&lt;/cite&gt;&lt;br /&gt;
&lt;p&gt;This pubsub activity is commonly used by &lt;a href='http://xmpp.org/extensions/xep-0118.html'&gt;user tunes&lt;/a&gt; so you can see what your friends are listening to. If you&amp;#8217;ve ever seen someone updating their adium status with song names from itunes, they might&amp;#8217;ve been using XEP-0118.&lt;/p&gt;

&lt;p&gt;Another use of publish / subscribe is microblogging - described in &lt;a href='http://xmpp.org/extensions/xep-0277.html'&gt;XEP-0277&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='microblogging'&gt;Microblogging&lt;/h1&gt;

&lt;p&gt;Microblogging over xmpp create a node &lt;code&gt;urn:xmpp:microblog:0&lt;/code&gt; on each user, and then provides a protocol for sending atom messages over xmpp. This protocol has been expanded upon by the &lt;a href='http://http://onesocialweb.org/'&gt;Vodafone research group&lt;/a&gt; as &lt;a href='http://onesocialweb.org/spec/1.0/osw-activities.html'&gt;Activity Streams over XMPP&lt;/a&gt; which lets you publish, update and delete posts. It also gives a &lt;a href='http://activitystrea.ms/schema/1.0/activity-schema-01.html'&gt;vocabulary of verbs&lt;/a&gt; that you can use to describe your activity, so you can like, bookmark or group posts.&lt;/p&gt;

&lt;p&gt;A client doesn&amp;#8217;t have to implement all the verbs. Diaspora*x only implements the like and post protocols (replies to posts are posts as well), but as you fill out the functionality, you have a predefined vocabulary so that clients can work together.&lt;/p&gt;

&lt;h1 id='alternate_clients'&gt;Alternate clients&lt;/h1&gt;

&lt;p&gt;I have a few goals for diaspora*x, if I keep working on it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get federation working reliably with other servers, currently the xmpp connector is incomplete, although it shouldn&amp;#8217;t take long to get going. I&amp;#8217;d also like to test the federation against another social network, maybe buddycloud, or onesocialweb.&lt;/li&gt;

&lt;li&gt;Create a desktop client using strophe.js, that connects to the jabber server directly (via BOSH) and shows how a client can be implemented in the simplest possible way.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A part of my job I think, is to demistify social networking over xmpp, as it&amp;#8217;s quite a simple idea and easy to implement on the current specs.&lt;/p&gt;

&lt;p&gt;I also have to read up on ostatus and work out if and how diaspora*x should work with ostatus. If it makes sense to add ostatus support, that would mean anyone on the status.net network would be friendable via a disapora*x seed.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Diaspora*x</title>
   <link href="http://bnolan.github.com/2010/12/07/diaspora-x.html"/>
   <updated>2010-12-07T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/07/diaspora-x</id>
   <content type="html">&lt;p&gt;I like Facebook, and at the moment I think it does a great job of managing privacy on the Facebook site. My only concern is that of censorship. If the US government asks Facebook to censor something, Facebook has to acquiesce to their request.&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t believe this is a problem in the short term (if the wikileaks facebook page goes offline no one is going to die), but I do think the idea of having a distributed social network - where there is no central point of control or central point of failure - is a cool idea.&lt;/p&gt;

&lt;p&gt;So I was excited to learn about Diaspora. It&amp;#8217;s clearly something people are interested in, their fundraising was 20x oversubscribed. So when they did a public release, I was keen to check out the code and try it out.&lt;/p&gt;

&lt;p&gt;The current alpha release of Diaspora is interesting, but it clearly has a ways to go before it&amp;#8217;s ready for day-to-day use. The biggest problem I found with it is that it doesn&amp;#8217;t support XMPP for communication between different seeds. XMPP is also known as Jabber, and it&amp;#8217;s the protocol that gtalk and ichat use to communicate. Even facebook uses &lt;a href='http://developers.facebook.com/blog/post/110'&gt;xmpp&lt;/a&gt; in places to allow you to interact with facebook chat.&lt;/p&gt;

&lt;h1 id='adding_xmpp_support_to_diaspora'&gt;Adding XMPP support to Diaspora&lt;/h1&gt;

&lt;p&gt;So I grabbed a few bits out of the Diaspora trunk and built a &lt;a href='http://github.com/bnolan/diaspora-x'&gt;little app&lt;/a&gt; to demonstrate how a basic distributed social network could work. You can try out my result of a few days coding here:&lt;/p&gt;

&lt;h2 id='_diasporaxcom'&gt;&amp;#187; &lt;a href='http://diaspora-x.com/'&gt;diaspora-x.com&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;m not sure how much more work I&amp;#8217;m going to do on this project, I&amp;#8217;ve proven the idea works to myself, and I&amp;#8217;d like Diaspora proper to start work on XMPP support for the main project.&lt;/p&gt;

&lt;p&gt;However - if you want me to add a feature to the diaspora-x website, put your requests into the &lt;a href='https://github.com/bnolan/diaspora-x/issues'&gt;github issue tracker&lt;/a&gt; and I&amp;#8217;ll see what I can do.&lt;/p&gt;

&lt;p&gt;There are installation instructions &lt;a href='https://github.com/bnolan/diaspora-x/blob/master/doc/install.md'&gt;here&lt;/a&gt; if you want to try running Diaspora*x yourself.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Offending people</title>
   <link href="http://bnolan.github.com/2010/12/06/offending-people.html"/>
   <updated>2010-12-06T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/12/06/offending-people</id>
   <content type="html">&lt;p&gt;Any time you click a broken link (like this one for the &lt;a href='https://joindiaspora.com/2010/10/29/october-update.html'&gt;october update&lt;/a&gt;) on the &lt;a href='http://www.joindiaspora.com/'&gt;Diaspora&lt;/a&gt; site, you get this guy staring back at you.&lt;/p&gt;
&lt;img src='/images/diaspora-404.png' /&gt;&lt;cite&gt;Oops. My bad.&lt;/cite&gt;
&lt;p&gt;Except, well I didn&amp;#8217;t do anything wrong, except I clicked a link that you broke on your site. And now I feel like a fool.&lt;/p&gt;

&lt;p&gt;Cool graphic design. Really bad user experience.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>On how things stay the same</title>
   <link href="http://bnolan.github.com/2010/11/30/things-stay-the-same.html"/>
   <updated>2010-11-30T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/30/things-stay-the-same</id>
   <content type="html">&lt;p&gt;When you&amp;#8217;re young and you have problems or obstacles, you are comforted by the fact that you&amp;#8217;ll get through this and in the future you won&amp;#8217;t have such problems.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s interesting how no water how as you get older and more experienced, you get much better at solving your problems (oh it&amp;#8217;s a X so i&amp;#8217;ll do a Y), but that feeling of &amp;#8216;my god, what the fuck am i going to do&amp;#8217; doesn&amp;#8217;t go away. It just is more brief before you accept &amp;#8216;oh well, i&amp;#8217;ll just have to use a self tapping bit and use an oversized thread.&lt;/p&gt;

&lt;p&gt;Well, that&amp;#8217;s how it&amp;#8217;s been so far - be interesting to see what the next 20 years of problem solving will reveal.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Horizontal sharding on Postgres</title>
   <link href="http://bnolan.github.com/2010/11/29/horizontal-sharding-postgres.html"/>
   <updated>2010-11-29T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/29/horizontal-sharding-postgres</id>
   <content type="html">&lt;p&gt;Working on &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt; I get around 2 million tweets per day. The importer is a streaming curl session that I pipe into a ruby script that analyzes the tweet and sticks it into a postgres database.&lt;/p&gt;

&lt;h1 id='tweet_analysis'&gt;Tweet analysis&lt;/h1&gt;

&lt;p&gt;Some of the analysis I do for each tweet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is it an @ reply?&lt;/li&gt;

&lt;li&gt;What place_id is being referred to?&lt;/li&gt;

&lt;li&gt;Does the user seem spammy?&lt;/li&gt;

&lt;li&gt;What neighbourhood does this tweet belong to?&lt;/li&gt;

&lt;li&gt;What city does this tweet belong to?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This has worked really well and even though its low tech, when combined with a monit script, it&amp;#8217;s easy to control and robust.&lt;/p&gt;

&lt;h1 id='the_problem'&gt;The problem&lt;/h1&gt;

&lt;p&gt;The problem is that after 20 days, you have more than 50 million tweets and postgres starts to grind to a halt when inserting data.&lt;/p&gt;

&lt;p&gt;If you had forgotten all of your university level mathematics - you might model the relationship between time to insert and the number of tweets like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;lim T(insert_tweet) as SUM(tweets) &amp;amp;rarr; 50m = &amp;amp;#8734;&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='the_solution'&gt;The solution&lt;/h1&gt;

&lt;p&gt;The obvious solution is to delete the old tweets out of the database. Maybe a cron job like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;delete from tweets where created_at &amp;gt; 7.days.ago&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Except every time you do that (and the VACUUM that you have to run afterwards), postgres will stop responding for about an hour, giving a theoretical uptime limit of 0.95. Since I&amp;#8217;m aiming for a uptime of at least 3 sixes (0.9666), I decided to look int other options.&lt;/p&gt;

&lt;h1 id='nosql'&gt;NoSQL&lt;/h1&gt;

&lt;p&gt;The sexy thing to do would be to use mongodb, couchdb or cassandra. But that migration, and writing all the map-reduce functions, plus removing activerecord and rewriting all my views - would probably take more than the 60 minutes I assigned to this problem.&lt;/p&gt;

&lt;p&gt;So&amp;#8230; What can we do with postgres?&lt;/p&gt;

&lt;h1 id='daily_sharding'&gt;Daily sharding&lt;/h1&gt;

&lt;p&gt;The easiest solution is a &lt;a href='http://stackoverflow.com/questions/994882/what-is-a-good-way-to-horizontal-shard-in-postgresql'&gt;variant on this&lt;/a&gt;, where you use table inheritance to insert each days tweets into a distinct table, and then query the parent table to get an aggregate view.&lt;/p&gt;

&lt;p&gt;So you just have a daily cronjob to drop any tweet tables more than 7 days old, and then create a new table for tomorrows tweets. Since tables are stored seperately on disk, the drop table is essentially free.&lt;/p&gt;

&lt;h1 id='performance_concerns'&gt;Performance concerns&lt;/h1&gt;

&lt;p&gt;Indexes can&amp;#8217;t be built up across multiple tables (and if you did do that, you&amp;#8217;d need to rebuild them each day when you dropped 1/8th of the indexed data), so badly written queries could end up with a sequential scan across all tables. I&amp;#8217;ve only had the new system running for a few hours, so I&amp;#8217;ll know more about performance implications later this week, but since most of my queries run on only the last 24 hours, I hope I can hint postgres to query the most recent table (using the daily indexes) first and only then move back to the second most recent table.&lt;/p&gt;

&lt;h1 id='the_code'&gt;The code&lt;/h1&gt;

&lt;p&gt;Nice and simple - a cronjob to create tomorrows table&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def self.create_tomorrows_table
  date = 1.days.from_now.to_date
  date_string = date.to_s.gsub(/-/,&amp;#39;_&amp;#39;)

  sql =&amp;lt;&amp;lt; EOF
    CREATE TABLE tweets_#{date_string} ( 
      CHECK ( DATE(created_at) = DATE(&amp;#39;#{date}&amp;#39;) )
     ) INHERITS (tweets);
  EOF

  ActiveRecord::Base.connection.execute sql

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then a sharded save method (note that I have a very customized tweet import job, so I don&amp;#8217;t have to worry about tweet ids / saving associations).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def sharded_save!
  date = self.created_at.to_date
  date_string = date.to_s.gsub(/-/,&amp;#39;_&amp;#39;)

  quoted_attributes = attributes_with_quotes

  sql = &amp;lt;&amp;lt; EOF
    INSERT INTO 
      tweets_#{date_string} (#{quoted_column_names.join(&amp;#39;, &amp;#39;)})
    VALUES
      (#{quoted_attributes.values.join(&amp;#39;, &amp;#39;)})
  EOF

  ActiveRecord::Base.connection.execute sql
end&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='to_be_continued'&gt;To be continued&amp;#8230;&lt;/h1&gt;

&lt;p&gt;So this is just day one, I&amp;#8217;ll find out more about this scheme later in the week, but I (yet again) was impressed by how nice a modern postgresql installation is. Well done the postgres team.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Jquery mobile on Nokia</title>
   <link href="http://bnolan.github.com/2010/11/25/jquery-mobile-on-nokia.html"/>
   <updated>2010-11-25T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/25/jquery-mobile-on-nokia</id>
   <content type="html">&lt;p&gt;My Nokia 5230 arrived today. What a cool phone for 120€! It has satellite navigation (with a suction cup to stick it on the windscreen), a big screen, decent browser and facebook right on the front page. It&amp;#8217;s no iphone, but it&amp;#8217;s 1/5th the price.&lt;/p&gt;

&lt;p&gt;As well as using the phone to navigate our way to the some quiet beaches north of Brisbane, I&amp;#8217;m using it to debug &lt;a href='http://www.weheartplaces.com/'&gt;weheartplaces&lt;/a&gt;, so I can get my app on the Ovi store.&lt;/p&gt;

&lt;h2 id='first_attempt'&gt;First attempt&lt;/h2&gt;

&lt;p&gt;I loaded up jquerymobile.com on the nokia and was sorely disapointed, the current alpha of Jquery mobile doesn&amp;#8217;t support Nokia S60 v5 (s60 v5 is the touch-screen interface for Nokias) browsers. I quickly set about to see how much work was needed to get things going.&lt;/p&gt;

&lt;h2 id='an_hour_later'&gt;An hour later&lt;/h2&gt;
&lt;img src='/images/nokiamobile.png' /&gt;&lt;cite&gt;The backbone mobile demo running on a 5230&lt;/cite&gt;
&lt;p&gt;It &lt;a href='http://bennolan.com/science/backbone-mobile/'&gt;works&lt;/a&gt;! I created and solved two issues on the Jquery Mobile github - one about &lt;a href='https://github.com/jquery/jquery-mobile/issuesearch?state=open&amp;amp;q=history#issue/543'&gt;history&lt;/a&gt; and another about &lt;a href='https://github.com/jquery/jquery-mobile/issuesearch?state=open&amp;amp;q=screen.height#issue/542'&gt;window.innerHeight&lt;/a&gt; - and suddenly it all started working.&lt;/p&gt;

&lt;p&gt;There are a few things missing in the current S60 implementation, there is no inter-screen animation and some of the CSS looks a bit rough on the symbian browser, but it&amp;#8217;s totally functional and looks nice enough.&lt;/p&gt;

&lt;h2 id='fixes_needed_to_jquery_mobile_for_s60'&gt;Fixes needed to jquery mobile for s60&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Promote s60 v5 to a grade a browser&lt;/li&gt;

&lt;li&gt;Fix the history tracking (solution at issue 542)&lt;/li&gt;

&lt;li&gt;Fix window.innerHeight in jquery (solution at issue 542 )&lt;/li&gt;

&lt;li&gt;Fix inter page animations&lt;/li&gt;

&lt;li&gt;Fix png / css ugliness&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='one_code_base_at_least_three_platforms'&gt;One code base, at least three platforms&lt;/h2&gt;
&lt;img src='/images/iphonemobile.png' /&gt;&lt;cite&gt;The backbone mobile demo running on iPhone&lt;/cite&gt;
&lt;p&gt;It&amp;#8217;s exciting to be able to write an application once, in a comfortable development environment (Safari on the desktop), then deploy the same code to iPhone, Android and Nokia. I expect start-ups will begin using this toolchain to build apps for multiple appstores at once. To try out the jquery mobile + backbone app on your Nokia (you&amp;#8217;ll need a s60 v5 device), Android or iPhone, go to &lt;a href='http://bennolan.com/science/backbone-mobile/'&gt;my backbone mobile demo&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Backbone Mobile Example</title>
   <link href="http://bnolan.github.com/2010/11/24/backbone-jquery-demo.html"/>
   <updated>2010-11-24T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/24/backbone-jquery-demo</id>
   <content type="html">&lt;p&gt;After my post &lt;a href='http://bennolan.com/2010/11/23/backbone-and-jquery-mobile.html'&gt;yesterday&lt;/a&gt; - I decided to extract out an example app from my current work.&lt;/p&gt;
&lt;img src='/images/bbmobile.png' /&gt;&lt;cite&gt;A backbone mobile app running in Safari&lt;/cite&gt;
&lt;p&gt;You can &lt;a href='http://bennolan.com/science/backbone-mobile/'&gt;try the app&lt;/a&gt; in your browser, or view the &lt;a href='https://github.com/bnolan/backbone-mobile'&gt;source code on github&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='technology'&gt;Technology&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m using the Foursquare API, Backbone.js, Underscore.js, CoffeeScript, jQuery and jQuery Mobile. The application is written in CoffeeScript - if you make changes to &lt;a href='https://github.com/bnolan/Backbone-Mobile/blob/master/application.coffee'&gt;application.coffee&lt;/a&gt; - you will need to rerun coffeescript to recompile application.js.&lt;/p&gt;

&lt;p&gt;If you aren&amp;#8217;t up to date with coffeescript you can probably read through application.js and understand most of the code. I also cached a foursquare venue API search result as foursquare.json. The foursquare API doesn&amp;#8217;t support JSONP so I couldn&amp;#8217;t use it directly.&lt;/p&gt;

&lt;h1 id='patch_to_jquery_mobile'&gt;Patch to jQuery Mobile&lt;/h1&gt;

&lt;p&gt;There is only patch require to the libraries - one that I discussed in my &lt;a href='http://bennolan.com/2010/11/23/backbone-and-jquery-mobile.html'&gt;previous post&lt;/a&gt; to make jQuery route the URLs correctly.&lt;/p&gt;

&lt;h1 id='indexhtml'&gt;&lt;a href='https://github.com/bnolan/Backbone-Mobile/blob/master/index.html'&gt;Index.html&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;The index.html has very little in it, just the outline HTML for the first page to be displayed. The actual page content is generated by HomeView in application.coffee. If you haven&amp;#8217;t seen the data-role stuff before, I recommend you read through the jquery mobile docs.&lt;/p&gt;

&lt;h1 id='applicationcoffee'&gt;&lt;a href='https://github.com/bnolan/Backbone-Mobile/blob/master/application.coffee'&gt;Application.coffee&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Pretty much the entire application is written in application.coffee.&lt;/p&gt;

&lt;h2 id='app'&gt;app&lt;/h2&gt;

&lt;p&gt;A namespace with a few helpers I use to work with jquery mobile better. &lt;code&gt;activePage&lt;/code&gt; returns the currently displayed page. &lt;code&gt;reapplyStyles&lt;/code&gt; make jQuery mobile convert elements tagged with data-role=&amp;#8221;whatever&amp;#8221; into correctly displayed jquery mobile widgets. The next version of jQuery mobile might fix the .page() method, and so reapplyStyles can be removed.&lt;/p&gt;

&lt;h2 id='venue_class'&gt;Venue class&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class Venue extends Backbone.Model
  getName: -&amp;gt;
    @get(&amp;#39;name&amp;#39;)

  getAddress: -&amp;gt;
    [@get(&amp;#39;address&amp;#39;), @get(&amp;#39;city&amp;#39;), @get(&amp;#39;state&amp;#39;)].join &amp;quot;, &amp;quot;

  getImageUrl: -&amp;gt;
    @get(&amp;#39;photo_url&amp;#39;)

  getLatitude: -&amp;gt;
    @get(&amp;#39;geolat&amp;#39;)

  getLongitude: -&amp;gt;
    @get(&amp;#39;geolong&amp;#39;)

  getMapUrl: (width, height) -&amp;gt;
    width ||= 300
    height ||= 220

    &amp;quot;http://maps.google.com/maps/api/staticmap?center=#{@getLatitude()},#{@getLongitude()}&amp;amp;zoom=14&amp;amp;size=#{width}x#{height}&amp;amp;maptype=terrain&amp;amp;markers=color:red|#{@getLatitude()},#{@getLongitude()}&amp;amp;sensor=false&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a backbone model that takes a hash of data and makes it available with a few helper methods.&lt;/p&gt;

&lt;h2 id='venuecollection'&gt;VenueCollection&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class VenueCollection extends Backbone.Collection
  model : Venue

  constructor: -&amp;gt;
    @refresh($FOURSQUARE_JSON)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is instantiated as Venues (try running Venues.models in your javascript console and you&amp;#8217;ll see all the loaded venues). When the collection is created, I call refresh with the FOURSQUARE_JSON (which is loaded from foursquare.js) which populates the collection immediately.&lt;/p&gt;

&lt;h2 id='editvenueview'&gt;EditVenueView&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class EditVenueView extends Backbone.View
  constructor: -&amp;gt;
    super

    # Get the active page from jquery mobile. We need to keep track of what this
    # dom element is so that we can refresh the page when the page is no longer active.
    @el = app.activePage()

    @template = _.template(&amp;#39;&amp;#39;&amp;#39;
    &amp;lt;form action=&amp;quot;#venue-&amp;lt;%= venue.cid %&amp;gt;-update&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;

      &amp;lt;div data-role=&amp;quot;fieldcontain&amp;quot;&amp;gt;
        &amp;lt;label&amp;gt;Name&amp;lt;/label&amp;gt;
        &amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&amp;lt;%= venue.getName() %&amp;gt;&amp;quot; name=&amp;quot;name&amp;quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
  
      &amp;lt;div data-role=&amp;quot;fieldcontain&amp;quot;&amp;gt;
        &amp;lt;label&amp;gt;Address&amp;lt;/label&amp;gt;
        &amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&amp;lt;%= venue.get(&amp;#39;address&amp;#39;) %&amp;gt;&amp;quot; name=&amp;quot;address&amp;quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
  
      &amp;lt;div data-role=&amp;quot;fieldcontain&amp;quot;&amp;gt;
        &amp;lt;label&amp;gt;City&amp;lt;/label&amp;gt;
        &amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&amp;lt;%= venue.get(&amp;#39;city&amp;#39;) %&amp;gt;&amp;quot; name=&amp;quot;city&amp;quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
  
      &amp;lt;div data-role=&amp;quot;fieldcontain&amp;quot;&amp;gt;
        &amp;lt;label&amp;gt;State&amp;lt;/label&amp;gt;
        &amp;lt;input type=&amp;quot;text&amp;quot; value=&amp;quot;&amp;lt;%= venue.get(&amp;#39;state&amp;#39;) %&amp;gt;&amp;quot; name=&amp;quot;state&amp;quot; /&amp;gt;
      &amp;lt;/div&amp;gt;
  
      &amp;lt;button type=&amp;quot;submit&amp;quot; data-role=&amp;quot;button&amp;quot;&amp;gt;Save&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;#39;&amp;#39;&amp;#39;)

    # Watch for changes to the model and redraw the view
    @model.bind &amp;#39;change&amp;#39;, @render

    # Draw the view
    @render()

  events : {
    &amp;quot;submit form&amp;quot; : &amp;quot;onSubmit&amp;quot;
  }

  onSubmit: (e) -&amp;gt;
    @model.set {
      name : @$(&amp;quot;input[name=&amp;#39;name&amp;#39;]&amp;quot;).val(),
      address : @$(&amp;quot;input[name=&amp;#39;address&amp;#39;]&amp;quot;).val(),
      city : @$(&amp;quot;input[name=&amp;#39;city&amp;#39;]&amp;quot;).val(),
      state : @$(&amp;quot;input[name=&amp;#39;state&amp;#39;]&amp;quot;).val()
    }

    @model.trigger(&amp;#39;change&amp;#39;)

    app.goBack()

    e.preventDefault()
    e.stopPropagation()

  render: =&amp;gt;
    # Set the name of the page
    @el.find(&amp;#39;h1&amp;#39;).text(&amp;quot;Editing #{@model.getName()}&amp;quot;)

    # Render the content
    @el.find(&amp;#39;.ui-content&amp;#39;).html(@template({venue : @model}))

    # A hacky way of reapplying the jquery mobile styles
    app.reapplyStyles(@el)

    # Delegate from the events hash
    @delegateEvents()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first view. It sets the active page to the @el attribute, so that it can refresh the page later on (remember that the activePage may change when the user navigates to another page, so we need to be able to refer to what element we drew the form in). Then we create a template using underscore.template. The underscore template library uses ERB style syntax to generate HTML. Remember that the ERBs are evaluated using the javascript interpreter, not coffeescript, so there&amp;#8217;s a bit of mixing and matching of coding styles going on here.&lt;/p&gt;

&lt;p&gt;We bind to the &lt;code&gt;change&lt;/code&gt; event on the model so that if model is updated somewhere else, this form is automatically re rendered. We watch for the submit event on the form (by calling @delegateEvents), so that we can handle the form submission ourselves in &lt;code&gt;onSubmit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;onSubmit&lt;/code&gt; sets some properties on the model by reading them out of the inputs, then triggers &lt;code&gt;change&lt;/code&gt; on the model. This would normally be a call to @model.save(), but we don&amp;#8217;t have a datastore to save the data too - so we just throw away the changes. In my own apps I use localStorage to persist the changes to the data, and then have a sync method that synchronises the local store with my production servers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;render&lt;/code&gt; sets the title of the page, renders the template into the .ui-content div, calls reapplyStyles so that jquery mobile can do it&amp;#8217;s magic, and then calls delegateEvents so that the events listed in the @events hash is applied to all the created elements.&lt;/p&gt;

&lt;h2 id='showvenueview'&gt;ShowVenueView&lt;/h2&gt;

&lt;p&gt;Simpler than the EditVenueView, except it generates some internal urls:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;#venues-&amp;lt;%= venue.cid %&amp;gt;-edit&amp;quot;&amp;gt;Edit&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This URL is recognized by backbone (see the routes in the controller) and will cause the edit method on the HomeController to be called. We also bind to &lt;code&gt;change&lt;/code&gt; here as well, so that when you save changes to the form, it automatically redraws the form. This is one of the main advantages of backbone.js - you can loosely couple views and not have to think of what views need to be redrawn when you make a change to a model, it happens automatically.&lt;/p&gt;

&lt;h2 id='homeview'&gt;HomeView&lt;/h2&gt;

&lt;p&gt;Displays the list of places. Uses the &lt;code&gt;.each()&lt;/code&gt; method that underscore.js makes available (or delegates to the native browser implementation) to iterate over all the venues and create a link to them.&lt;/p&gt;

&lt;h2 id='homecontroller'&gt;HomeController&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class HomeController extends Backbone.Controller
  routes :
    &amp;quot;venues-:cid-edit&amp;quot; : &amp;quot;edit&amp;quot;
    &amp;quot;venues-:cid&amp;quot; : &amp;quot;show&amp;quot;
    &amp;quot;home&amp;quot;  : &amp;quot;home&amp;quot;

  constructor: -&amp;gt;
    super
    @_views = {}

  home : -&amp;gt;
    @_views[&amp;#39;home&amp;#39;] ||= new HomeView

  show: (cid) -&amp;gt;
    @_views[&amp;quot;venues-#{cid}&amp;quot;] ||= new ShowVenueView { model : Venues.getByCid(cid) }

  edit: (cid) -&amp;gt;
    @_views[&amp;quot;venues-#{cid}-edit&amp;quot;] ||= new EditVenueView { model : Venues.getByCid(cid) }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I only have one controller in this app, but you could easily split it into two (a home controller and a venues controller). First up - we define the routes that we match. Note the routes have to be in an order of decreasing specificity, otherwise &lt;code&gt;venues-:cid&lt;/code&gt; would gobble up &lt;code&gt;venues-1235-edit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I created &lt;code&gt;@_views&lt;/code&gt; hash that I use to keep track of all the views that I have created, since I don&amp;#8217;t want to generate two instances of the same view. This is quite a naive implementation, because views can be created dozens of times if the user clicked on every single Venue. We would either want to expire old views, or re-use views - but I haven&amp;#8217;t worked out a way to manage that yet.&lt;/p&gt;

&lt;p&gt;Home, show and edit are all called by the Backbone router (see Backbone.history) when the anchor part of the current url (event &lt;code&gt;hashchange&lt;/code&gt;) changes. Each action is called with the parameters extracted from the routing hash. So all we have to do is instantiate the view and our app is ready to go.&lt;/p&gt;

&lt;p&gt;Finally, when the document is ready we start the backbone router and render the initial view.&lt;/p&gt;

&lt;h1 id='conclusion'&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;ve done less than a weeks development with jquery mobile (I&amp;#8217;d done a lot more using jqTouch), but it seems like a nice complement to backbone.js. It&amp;#8217;s fantastic that you can build an app using your current web experience, that can be sold in the Ovi Store (via Nokia Webruntime), Android Marketplace or iTunes Store (Phonegap).&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll try and keep things updated as I build out &lt;a href='http://www.weheartplaces.com/'&gt;my own app&lt;/a&gt;, and see how things scale up.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Backbone.js and Jquery mobile</title>
   <link href="http://bnolan.github.com/2010/11/23/backbone-and-jquery-mobile.html"/>
   <updated>2010-11-23T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/23/backbone-and-jquery-mobile</id>
   <content type="html">&lt;p&gt;The idea behind &lt;a href='http://weheartplaces.com/'&gt;Weheartplaces&lt;/a&gt; is that I want to be able to bookmark places to go on my desktop computer, and then sync these places to my mobile so I can access them offline.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve created a json API to weheartplaces, here are my bookmarks in &lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks.json'&gt;json format&lt;/a&gt;. I&amp;#8217;m loading these bookmarks using &lt;a href='http://documentcloud.github.com/backbone/'&gt;backbone.js&lt;/a&gt; and then displaying them using &lt;a href='http://jquerymobile.com/'&gt;jquery mobile&lt;/a&gt;. Here&amp;#8217;s a little breakdown of how I&amp;#8217;m doing it:&lt;/p&gt;

&lt;h1 id='list_view'&gt;List view&lt;/h1&gt;

&lt;p&gt;Create a list view like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;ul data-role=&amp;quot;listview&amp;quot; data-inset=&amp;quot;true&amp;quot; data-theme=&amp;quot;c&amp;quot; data-dividertheme=&amp;quot;b&amp;quot;&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is automatically converted into a nice looking list view by jquery mobile. You then iterate over all the elements in your Backbone collection to add them to the list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for bookmark in Bookmarks.models
  a = $(&amp;quot;&amp;lt;a /&amp;gt;&amp;quot;)

  a.text(bookmark.get(&amp;#39;place&amp;#39;).name)
  a.attr &amp;#39;href&amp;#39;, &amp;quot;#bookmarks-#{bookmark.cid}&amp;quot;

  a.wrap(&amp;quot;&amp;lt;li /&amp;gt;&amp;quot;).parent().appendTo(ul)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice the url that each bookmark points to - #bookmarks-12345. I use backbone routes to recognize this URL and display the correct content.&lt;/p&gt;

&lt;h1 id='combining_the_jquery_and_backbone_routers'&gt;Combining the jquery and backbone routers&lt;/h1&gt;

&lt;p&gt;When you click a link - jquery mobile intercepts the click and looks for a div with the same name as the anchor fragment of the url you just clicked on. So for example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;#home&amp;quot;&amp;gt;Home&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Will cause jquery to show this div:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&amp;quot;home&amp;quot;&amp;gt;some content...&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The problem is that in my list view, I&amp;#8217;m linking to pages that don&amp;#8217;t exist yet - so I have to add some code to the jquery mobile routing code to create and show an empty div.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// This code goes in $.mobile.changePage...

if( url ){
	to = $( &amp;quot;[id=&amp;#39;&amp;quot; + url + &amp;quot;&amp;#39;]&amp;quot; ),
	fileUrl = getFileURL(url);

  if(to.length == 0){ // Page could not be found
    console.log(&amp;quot;Routing to &amp;quot; + url + &amp;quot;...&amp;quot;);
    
    to = $(&amp;quot;&amp;lt;div data-role=&amp;#39;page&amp;#39; id=&amp;#39;&amp;quot; + url + &amp;quot;&amp;#39;&amp;gt;&amp;lt;div data-role=&amp;#39;header&amp;#39;&amp;gt;&amp;lt;h1&amp;gt;&amp;amp;nbsp;&amp;lt;/h1&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;div data-role=&amp;#39;content&amp;#39;&amp;gt;&amp;lt;img src=&amp;#39;images/ajax-loader.png&amp;#39; /&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;).appendTo(&amp;#39;body&amp;#39;)
    
    enhancePage();
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Jquery will display this page, and change the anchor fragment of the current URL. Backbone detects the URL change by watching for a &lt;code&gt;hashchange&lt;/code&gt; event, and will then call your matching route - in my case:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class HomeController extends Backbone.Controller
  routes :
    &amp;quot;home&amp;quot;  : &amp;quot;home&amp;quot;
    &amp;quot;bookmarks-:cid&amp;quot; : &amp;quot;show&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='showing_the_bookmark'&gt;Showing the bookmark&lt;/h1&gt;

&lt;p&gt;Once that magic has happened, the show method on the HomeController will be called:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;show: (cid) -&amp;gt;
  new ShowBookmarkView { model : Bookmarks.getByCid(cid) }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a new ShowBookmarkView, and that view generates the HTML (using underscore.js templates) that is inserted into the currently active page.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$(&amp;quot;.ui-page-active&amp;quot;).html(@template({bookmark : @model}))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If I get time I will put a small demo file up on github to show how all this hangs together - but feel free to post questions below.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Back from Hiatus</title>
   <link href="http://bnolan.github.com/2010/11/22/back-from-hiatus.html"/>
   <updated>2010-11-22T00:00:00-08:00</updated>
   <id>http://bnolan.github.com/2010/11/22/back-from-hiatus</id>
   <content type="html">&lt;p&gt;Sorry I&amp;#8217;ve neglected my blog for two weeks. I was finishing up a contract, and then took a week break to work on some personal projects, as well as sort out various life things.&lt;/p&gt;

&lt;h1 id='travelling_around_new_zealand'&gt;Travelling around New Zealand&lt;/h1&gt;
&lt;img src='http://www.weheartplaces.com/system/uploads/10/large/800px-Cathedral_Cove,_Coromandel.JPG?1290122997' /&gt;&lt;cite&gt;&lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks/702622968'&gt;Cathedral Cove&lt;/a&gt;&lt;/cite&gt;
&lt;p&gt;In February, my girlfriend and I are travelling around New Zealand for 2 months, before heading off to Brisbane, then various other destinations around the world. To get the most out of our trip, we&amp;#8217;ve been planning a bunch of places to go on weheartplaces. It&amp;#8217;s still early days - but if you go to my &lt;a href='http://www.weheartplaces.com/users/110237153/guides'&gt;guides page&lt;/a&gt; you can see pictures and addresses for some of the campgrounds, breweries and beaches we want to visit while we&amp;#8217;re travelling around.&lt;/p&gt;

&lt;p&gt;The DOC (Department of Conservation) campsites are the best, since they cost only $6-$10 a night, and tend to be in more remote areas.&lt;/p&gt;

&lt;p&gt;I had an interesting talk with some New Zealand based travel guys about making their campsite data accessible offline, so if that comes up, Rissa and I should be able to travel around with a full database of every nice freedom or DOC campsite available.&lt;/p&gt;

&lt;h1 id='my_favourite_places_in_the_world'&gt;My favourite places in the world.&lt;/h1&gt;

&lt;p&gt;I made a quick list of my &lt;a href='http://www.weheartplaces.com/users/110237153/guides/5'&gt;Favourite places in the world&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks/702622926'&gt;Midnight Espresso&lt;/a&gt;, &lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks/702622967'&gt;Hofbraükeller&lt;/a&gt;, &lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks/702622968'&gt;Cathedral Cove&lt;/a&gt;, and &lt;a href='http://www.weheartplaces.com/users/110237153/bookmarks/702622969'&gt;Ferchensee&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='nokia_5230'&gt;Nokia 5230&lt;/h1&gt;

&lt;p&gt;I bought another new Nokia, this time a Nokia 5230, which has the more modern Web Runtime 7.2, so that I can build some backbone.js applications that run on IOS, Android or Nokia.&lt;/p&gt;

&lt;p&gt;Compared to some of my other projects, which are pure ruby on rails, no javascript at all - my Phonegap / Web Runtime apps have a gnarly technology stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coffeescript&lt;/li&gt;

&lt;li&gt;Backbone.js&lt;/li&gt;

&lt;li&gt;Jquery mobile&lt;/li&gt;

&lt;li&gt;Less CSS&lt;/li&gt;

&lt;li&gt;Qunit&lt;/li&gt;

&lt;li&gt;Phonegap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#8217;ll talk more about phonegap and backbone.js + jquery mobile later this week.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Level Interaction</title>
   <link href="http://bnolan.github.com/2010/11/04/level-interaction.html"/>
   <updated>2010-11-04T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/11/04/level-interaction</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve just posted a &lt;a href='http://www.youtube.com/watch?v=YWzGjUiL4LY'&gt;new video&lt;/a&gt; of Hutch. New features include terrain generation, better collision detection, item interaction, tile interaction. I&amp;#8217;ve been looking around the web and also found a few people doing truly amazing javascript stuff:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://rumpetroll.com/'&gt;Rumpetroll&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://rocketpack.fi/'&gt;Rocketpack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It really looks like Javascript gaming is about to take off!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Game design</title>
   <link href="http://bnolan.github.com/2010/11/03/game-design.html"/>
   <updated>2010-11-03T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/11/03/game-design</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been playing around with &lt;a href='http://www.youtube.com/watch?v=BS27XGxwMes'&gt;Hutch&lt;/a&gt; lately, and have been reading some game design articles. I found this &lt;a href='http://www.graftgold.com/'&gt;pearl of wisdom&lt;/a&gt; from the developer of some old Commodore 64 games that I used to love as a kid.&lt;/p&gt;

&lt;p&gt;(As an aside, said C64 developer now writes insurance software because it pays better).&lt;/p&gt;

&lt;p&gt;The most interesting part of the article I thought was the developers game design process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We investigated the platform and designed and wrote graphics architecture to exploit some feature of the machine.&lt;/li&gt;

&lt;li&gt;We considered game environments that utilised that feature.&lt;/li&gt;

&lt;li&gt;We create a player in a prototype level and worked on the control and movement.&lt;/li&gt;

&lt;li&gt;We decided on the game idea and added enemies to the test level.&lt;/li&gt;

&lt;li&gt;We worked on real levels constantly coming up with new ideas as we progressed.&lt;/li&gt;

&lt;li&gt;We reviewed the levels , adding new ideas in where necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is very similar to how I&amp;#8217;ve been working on Hutch. Invent the graphics engine, think up game environments you can render in realtime, add player movement and control. The next stage is to add items and enemies.&lt;/p&gt;

&lt;p&gt;Hopefully I&amp;#8217;ll get time to do that later in the week.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Twitterplaces</title>
   <link href="http://bnolan.github.com/2010/10/28/twitterplaces.html"/>
   <updated>2010-10-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/28/twitterplaces</id>
   <content type="html">&lt;p&gt;I went to a R users group in melbourne and got all turned on by data analysis, so I went home and started crawling all the tweets in the world and sticking them into a Postgres database. I then went and build this &lt;a href='http://www.twitterplaces.com/'&gt;site&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I keep playing around with the site and adding random features and new pages, but I&amp;#8217;d like some feedback on what I could do so that people actually found the site useful. It&amp;#8217;s cool building a site for myself, but it&amp;#8217;d be cool if more than 10 people a day used the site. What do you lot think would be some concrete features to add to the site?&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s some of the current pages that I think are interesting but could do with some work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;http://www.twitterplaces.com/muc&lt;/li&gt;

&lt;li&gt;http://www.twitterplaces.com/users/dens&lt;/li&gt;

&lt;li&gt;http://www.twitterplaces.com/sfo/twitter-hq&lt;/li&gt;

&lt;li&gt;http://www.twitterplaces.com/sfo/mission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some technical infos:&lt;/p&gt;

&lt;p&gt;I crawl the data using the streaming API, all geotagged tweets in the world (about 2m/day). The crawler is written in ruby and does a bunch of caching so it doesn&amp;#8217;t have to hit up postgres too much.&lt;/p&gt;

&lt;p&gt;I use postgis so I can lookup bounding neighbourhoods and cities for points based on lat / long.&lt;/p&gt;

&lt;p&gt;Some of the queries are insanely slow (eg which users travel the world the most), so I need to work out a better way of generating results.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s running on a AMD X4 box with 4gb of ram, so seems to keep chugging along.&lt;/p&gt;

&lt;p&gt;I use varnish on the front of the site to cache html for a few minutes after each visit.&lt;/p&gt;

&lt;p&gt;TLDR: Have &lt;a href='http://www.twitterplaces.com/'&gt;site&lt;/a&gt;, what features should I add?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Additions to Backbone views</title>
   <link href="http://bnolan.github.com/2010/10/27/additions-to-backbone-views.html"/>
   <updated>2010-10-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/27/additions-to-backbone-views</id>
   <content type="html">&lt;p&gt;I took Matt McCrays excellent &lt;a href='http://mattmccray.blogspot.com/2010/10/using-backbonejs-in-coffeescript.html?spref=tw'&gt;Coffeescript glue&lt;/a&gt; for Backbone.js and moved my &lt;code&gt;saveChanges&lt;/code&gt; function into it.&lt;/p&gt;

&lt;p&gt;The function serializes all the form elements in the rendered elements and updates the associated model. You can use this code by binding to &amp;#8216;submit form&amp;#8217; using &lt;code&gt;@handleEvents&lt;/code&gt; and calling saveChanges and suppressing the default form submission.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class View
  constructor: -&amp;gt;
    Backbone.View.apply(this, arguments)

  saveChanges: -&amp;gt;
    properties = {}

    for input in @el.find(&amp;#39;input,textarea&amp;#39;)
      value = $(input).val()
      properties[input.name] = value

    @model.set properties
    @model.save()

    app.saving()

_.extend(View::, Backbone.View.prototype)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A small example from &lt;a href='http://weheartplaces.com/'&gt;Weheartplaces&lt;/a&gt;&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class TripInspector extends App.View
  constructor: -&amp;gt;
    super
    @template= JST[&amp;quot;trip_inspector/show&amp;quot;] 
    @render() if @model?

  render: -&amp;gt;
    @el.html(@template { trip : @model })

    @handleEvents {
      &amp;#39;submit form&amp;#39; : &amp;#39;submit&amp;#39;
    }

  submit: (e) =&amp;gt;
    e.preventDefault()
    @saveChanges()

this.TripInspector = TripInspector&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Tagging</title>
   <link href="http://bnolan.github.com/2010/10/26/tagging.html"/>
   <updated>2010-10-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/26/tagging</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been doing some work on getting the private beta of &lt;a href='http://weheartplaces.com/'&gt;Weheartplaces&lt;/a&gt; out. I&amp;#8217;m using tagging as a way to categorize places, so you can quickly add a place and tag as &amp;#8216;todo&amp;#8217;, &amp;#8216;cafe&amp;#8217; or possibly &amp;#8216;avoid&amp;#8217;.&lt;/p&gt;
&lt;img src='/images/taggingplaces.png' /&gt;&lt;cite&gt;Places tagging interface for Weheartplaces&lt;/cite&gt;
&lt;p&gt;I found &lt;a href='http://github.com/rafudu/Tagbox'&gt;tagbox&lt;/a&gt; by Rafudu still works okay with current jquery. It&amp;#8217;s a bit creaky, but with some CSS tweaks it worked okay out of the box.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Gisborne</title>
   <link href="http://bnolan.github.com/2010/10/22/gisborne.html"/>
   <updated>2010-10-22T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/22/gisborne</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been away from the internet for a bit - chewing through some work for the good folks at &lt;a href='http://youdo.co.nz/'&gt;Youdo&lt;/a&gt; (you should try their ITIL tool - &lt;a href='http://beetil.com/'&gt;Beetil&lt;/a&gt;) and doing various business development work. One of the most enjoyable business trips I&amp;#8217;ve ever been on can be summarised by this photo:&lt;/p&gt;
&lt;img src='/images/rankers.jpg' /&gt;&lt;cite&gt;A remote beach on the east cape of NZ&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Four for four</title>
   <link href="http://bnolan.github.com/2010/10/15/four-for-four.html"/>
   <updated>2010-10-15T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/15/four-for-four</id>
   <content type="html">&lt;p&gt;I just sat down at my Mac. Here&amp;#8217;s a recap of the last hour.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Thirty minute bike ride on muddy singletrain&lt;/li&gt;

&lt;li&gt;It stopped raining and the sun came out&lt;/li&gt;

&lt;li&gt;As I got out of the shower my girlfriend rang up to ask what I wanted her to bring for lunch&lt;/li&gt;

&lt;li&gt;I pressed play on iTunes and got some pimping &lt;a href='http://www.youtube.com/watch?v=pOjw9rAWt2E'&gt;Murs&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yeeeeeeeeeeah.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A modern webapp</title>
   <link href="http://bnolan.github.com/2010/10/14/a-modern-webapp.html"/>
   <updated>2010-10-14T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/14/a-modern-webapp</id>
   <content type="html">&lt;p&gt;Want to write a modern webapp using lots of javascript? Here&amp;#8217;s my recommended toolkit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://jashkenas.github.com/coffee-script/'&gt;CoffeeScript&lt;/a&gt; for brevity&lt;/li&gt;

&lt;li&gt;&lt;a href='http://jquery.com/'&gt;Jquery&lt;/a&gt; for sanity&lt;/li&gt;

&lt;li&gt;&lt;a href='http://jqueryui.com/'&gt;Jquery UI&lt;/a&gt; (with &lt;a href='http://taitems.tumblr.com/post/482577430/introducing-aristo-a-jquery-ui-theme'&gt;Aristo&lt;/a&gt;) for your design and widgets&lt;/li&gt;

&lt;li&gt;&lt;a href='http://documentcloud.github.com/underscore/'&gt;Underscore.js&lt;/a&gt; for your views (see _.template)&lt;/li&gt;

&lt;li&gt;&lt;a href='http://documentcloud.github.com/backbone/'&gt;Backbone.js&lt;/a&gt; for your models andd controllerts&lt;/li&gt;

&lt;li&gt;&lt;a href='http://documentcloud.github.com/jammit/'&gt;Jammit&lt;/a&gt; for asset packaging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&amp;#8217;ve only recently discovered backbone and jammit, but I have a lot of respect for &lt;a href='http://github.com/jashkenas/'&gt;Jeremy&lt;/a&gt; so they&amp;#8217;re my &lt;a href='http://weheartplaces.com/'&gt;bet&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Splatter</title>
   <link href="http://bnolan.github.com/2010/10/12/splatter.html"/>
   <updated>2010-10-12T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/12/splatter</id>
   <content type="html">&lt;p&gt;After watching &lt;a href='http://www.banksyfilm.com/'&gt;Exit Through The Gift Shop&lt;/a&gt; last night, I wanted to do something creative, so I played around with isometric projection using css3 and applying stencils to canvas. I came up with something vaguely similair to what I was imagining&amp;#8230;.&lt;/p&gt;
&lt;img src='/images/splatter.png' /&gt;&lt;cite&gt;Designing a little world&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>My jqtouch fork</title>
   <link href="http://bnolan.github.com/2010/10/08/my-jqtouch-fork.html"/>
   <updated>2010-10-08T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/08/my-jqtouch-fork</id>
   <content type="html">&lt;p&gt;Sorry for not blogging this week. I&amp;#8217;ve been in a client office and furiously working on getting a sprint out. On Monday I had my product development day, so I started work on &lt;a href='http://weheartplaces.com/'&gt;weheartplaces&lt;/a&gt;. The first iteration of WHP is due out by the end of October, and I plan to have it working on Iphone, Nokia and Android. To do this I&amp;#8217;m using &lt;a href='http://blog.jqtouch.com/'&gt;jqtouch&lt;/a&gt; which hasn&amp;#8217;t seen a lot of work in the past year.&lt;/p&gt;

&lt;p&gt;I forked jqtouch onto my &lt;a href='http://github.com/bnolan/'&gt;github&lt;/a&gt; and have been pushing a few changes. They aren&amp;#8217;t all ready for the primetime yet - but the main design changes I&amp;#8217;ll be making:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL routing scheme, so you can have controllers and actions to handle requests&lt;/li&gt;

&lt;li&gt;Use pushState to have proper urls (instead of #location urls)&lt;/li&gt;

&lt;li&gt;Specced and tested using &lt;a href='http://github.com/pivotal/jasmine'&gt;Jasmine&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;Better form support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also have some ideas about how I can make an analog to jqtouch that will work with the Web Runtime that Nokia supports for development on their phones. I&amp;#8217;m doing my jQTouch modifications in pure javascript, but the Weheartplaces application is written using Coffeescript.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Silverstripe hosting</title>
   <link href="http://bnolan.github.com/2010/10/05/silverstripe-hosting.html"/>
   <updated>2010-10-05T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/05/silverstripe-hosting</id>
   <content type="html">&lt;p&gt;I have a little joke going that I think a hosted &lt;a href='http://silverstripe.com/'&gt;silverstripe&lt;/a&gt; would be quite a good competitor to wordpress.&lt;/p&gt;
&lt;img src='/images/brownstripe.png' /&gt;&lt;cite&gt;The silverstripe admin interface with a few tweaks&lt;/cite&gt;
&lt;p&gt;Silverstripe is an excellent CMS built by some of my friends in Wellington. They have a big company now, over 30 people, lots of big clients - and they even have a product - &lt;a href='http://silverstripe.com/dawn/'&gt;Dawn&lt;/a&gt;. Wordpress.com is the free hosting provider that runs &lt;a href='http://mu.wordpress.org/'&gt;Wordpress MU&lt;/a&gt; and has approximately a &lt;a href='http://ma.tt/2010/09/msn-spaces-closing-becomes-wp-com/#comments'&gt;bajillion&lt;/a&gt; blogs on it.&lt;/p&gt;

&lt;p&gt;The revenue stream is that on wp.com, you have to pay to get &lt;a href='http://en.wordpress.com/products/'&gt;premium features&lt;/a&gt;, like CSS editing, premium themes, custom domain names. I think it&amp;#8217;s an awesome business model that the Silverstripe team should take a look at.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A preview of new design</title>
   <link href="http://bnolan.github.com/2010/10/01/new-menu.html"/>
   <updated>2010-10-01T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/10/01/new-menu</id>
   <content type="html">&lt;p&gt;I have a new menu and header design coming for twitterplaces. A preview:&lt;/p&gt;
&lt;img src='/images/previewmenu.png' /&gt;</content>
 </entry>
 
 <entry>
   <title>Random Walk</title>
   <link href="http://bnolan.github.com/2010/09/30/random-walk.html"/>
   <updated>2010-09-30T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/30/random-walk</id>
   <content type="html">&lt;p&gt;For &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt;, I&amp;#8217;ve been using the Random Walk theory of software development. I pick up the software each day, and work on whatever feature I feel like. There&amp;#8217;s no plan, no vision, no long term overarching story that directs my work.&lt;/p&gt;

&lt;p&gt;I just go to a page that looks scruffier than the rest, then tidy it up. Or play with the data and find another interesting report, then put that in the site somewhere. Occasionally I may have to do a bit of architecture or scaling work, but i don&amp;#8217;t plan for it - I just do it when required. And I&amp;#8217;m always pushing to make the code easily understandable. A random walk doesn&amp;#8217;t mean spaghetti code.&lt;/p&gt;

&lt;p&gt;It just means, don&amp;#8217;t beat on feature &lt;span&gt;a&lt;/span&gt; until it&amp;#8217;s done. Work on a,b,c and invent feature d. That way you won&amp;#8217;t wear out and you won&amp;#8217;t become uninspired.&lt;/p&gt;

&lt;p&gt;Sure this won&amp;#8217;t work for your on-spec, on deadline project, but for your own projects, or experimentation in user interface design, just random walk through your project.&lt;/p&gt;

&lt;p&gt;You may be surprised where you end up.&lt;/p&gt;
&lt;img src='/images/graphviz.png' /&gt;&lt;cite&gt;A graphviz plot of adjacent commits on twitterplaces&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Against Me!</title>
   <link href="http://bnolan.github.com/2010/09/29/against-me.html"/>
   <updated>2010-09-29T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/29/against-me</id>
   <content type="html">&lt;p&gt;My favourite band in the world cancelled their Australian and New Zealand tour.&lt;/p&gt;
&lt;object height='385' width='480'&gt;&lt;param name='movie' value='http://www.youtube.com/v/mAkSIJ9BSi8?fs=1&amp;amp;hl=en_US' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;embed src='http://www.youtube.com/v/mAkSIJ9BSi8?fs=1&amp;amp;hl=en_US' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='385' width='480' /&gt;&lt;/object&gt;
&lt;p&gt;Sad face.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The Art of Happiness</title>
   <link href="http://bnolan.github.com/2010/09/28/the-art-of-happiness.html"/>
   <updated>2010-09-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/28/the-art-of-happiness</id>
   <content type="html">&lt;p&gt;I think this sums it up for me:&lt;/p&gt;
&lt;quote&gt;
  When you feel lacking in happiness.
  Don't delay feeling happy 
  for when some future 
  achievement has happened.
  Let yourself feel happy now.
&lt;/quote&gt;
&lt;p&gt;&lt;a href='http://en.wikipedia.org/wiki/Deferred_gratification'&gt;Delayed gratification&lt;/a&gt; doesn&amp;#8217;t apply to happiness.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>An island of Javascript</title>
   <link href="http://bnolan.github.com/2010/09/27/three.js.html"/>
   <updated>2010-09-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/27/three.js</id>
   <content type="html">&lt;p&gt;I ready about the sale of &lt;a href='http://www.dextrose.com/'&gt;Dextrose&lt;/a&gt; to Zynga by &lt;a href='http://twitter.com/pbakaus'&gt;Paul Baukaus&lt;/a&gt;, and it got me motivated to poke around with some html5 gaming again (a nice sunday morning thing to do). The outcome was an island generator using &lt;a href='http://github.com/mrdoob/three.js/'&gt;three.js&lt;/a&gt; and jquery ui.&lt;/p&gt;
&lt;img src='/images/island-zing.png' /&gt;&lt;cite&gt;Rudimentary but functional. 3d javascript for the future!&lt;/cite&gt;
&lt;p&gt;When you start the demo, you just get an empty sea, but move the cube around with the arrow keys and hold down space to raise some mountains out of the sea. The demo has a bad case of z-fighting, but I only spent an hour or so on this, so I&amp;#8217;ll look into those issues in the future sometime.&lt;/p&gt;

&lt;h1 id='threejs'&gt;Three.js&lt;/h1&gt;

&lt;p&gt;Three is a great library from one of the authors of papervision 3d (so they know what they&amp;#8217;re doing when it comes to browser-based graphics). It is surprisingly fast on modern browsers - the slowest thing seems to be the canvas drawing calls, which aren&amp;#8217;t hardware accelerated. The great thing about doing javascript work though, is that browsers are being updated so often at the moment (Safari, IE9, Firefox and Chrome) that what is slow but workable today, will be liquid smooth in 6 months time (assuming browser development keeps going like this).&lt;/p&gt;

&lt;p&gt;Three also has output support for canvas and webgl. I&amp;#8217;m using canvas in this demo.&lt;/p&gt;

&lt;h1 id='a_3d_game_engine'&gt;A 3d game engine&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;d like to play with this demo some more, and turn it into a mini game. I&amp;#8217;m currently thinking of using three to render to multiple canvases, and position the camera so that the terrain doesn&amp;#8217;t obscure itself, and I can use the browsers native z-order stacking for elements on top of the map. This should make a realtime 3d world doable without pegging the CPU (I have a strong aversion to pinning the CPU to draw a 400 face terrain when this macbook can play TF2 at native resolution).&lt;/p&gt;

&lt;p&gt;Then add multiplayer via websockets and node.js and you&amp;#8217;d have that multiplayer canvas game that Simon Willison &lt;a href='http://simonwillison.net/2010/Feb/8/pseudo/#comments'&gt;predicted&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>New Twitter Analyzed</title>
   <link href="http://bnolan.github.com/2010/09/24/new-twitter.html"/>
   <updated>2010-09-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/24/new-twitter</id>
   <content type="html">&lt;p&gt;I was interested to read the twitter engineering teams &lt;a href='http://engineering.twitter.com/2010/09/tech-behind-new-twittercom.html'&gt;overview&lt;/a&gt; of how the newtwitter works.&lt;/p&gt;

&lt;p&gt;This is the kind of app that is becoming more and more common, as it becomes viable to build apps in pure javascript, with just a json API as the backend. There are downsides to this kind of development, mostly in the inability for google to index the site - but for an app like twitter which are indexed by google using the pubsub interface (afaik), there&amp;#8217;s no reason not to provide a pure javascript / html5 interface for modern browsers.&lt;/p&gt;

&lt;p&gt;I haven&amp;#8217;t got new twitter yet - so I hit up a friend and got him to send me the URLs for the new twitter javascript. I guessed the pre-closure URLS, tidied them up using html tidy and textmate - and we have these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='/science/newtwitter/base.txt'&gt;base.js&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='/science/newtwitter/phoenix.txt'&gt;phoenix.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id='basejs'&gt;Base.js&lt;/h1&gt;

&lt;p&gt;Base.js seems to contain their extensions to jquery to create the twitter &amp;#8216;framework&amp;#8217;, eg:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logging&lt;/li&gt;

&lt;li&gt;Debugging&lt;/li&gt;

&lt;li&gt;Stack traces&lt;/li&gt;

&lt;li&gt;Browser detection&lt;/li&gt;

&lt;li&gt;Analytics&lt;/li&gt;

&lt;li&gt;Page state / history&lt;/li&gt;

&lt;li&gt;Load templates&lt;/li&gt;

&lt;li&gt;Form validation&lt;/li&gt;

&lt;li&gt;Help&lt;/li&gt;

&lt;li&gt;Autocomplete&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also has some code that uses the anywhere api (I think), to find a user by screenname. It has a bunch of code that has either been handrolled, or gathered together from different jquery plugins (eg timeAgo, numberWithDelimiter).&lt;/p&gt;

&lt;p&gt;The really interesting stuff is in phoenix.js though.&lt;/p&gt;

&lt;h1 id='phoenixjs'&gt;Phoenix.js&lt;/h1&gt;

&lt;p&gt;Newtwitter uses &lt;a href='http://mustache.github.com/'&gt;Mustache&lt;/a&gt; for their templates. Many of these templates are included in phoenix.js, as twttr.templates. The templates are internationalized and use classes liberally - eg &lt;code&gt;stream-tab-following&lt;/code&gt;, &lt;code&gt;stream-tab-pending&lt;/code&gt;, &lt;code&gt;delete-saved-search&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you search on any of these classnames - you&amp;#8217;ll find code later in phoenix.js that attaches the appropriate event handler to the html generated by mustache. For example - this fragment:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;div class=&amp;#39;delete-saved-search&amp;#39;&amp;gt;
  \n &amp;lt;a href=&amp;#39;#&amp;#39; class=&amp;#39;delete-saved-search-x&amp;#39;&amp;gt;&amp;lt;/a&amp;gt;\n &amp;lt;a href=&amp;#39;#&amp;#39;&amp;gt;Remove saved search&amp;lt;/a&amp;gt;\n
&amp;lt;/div&amp;gt;&amp;quot;,&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Has behaviour attached to it like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;click({
&amp;quot;.delete-saved-search&amp;quot;: function(B, A) {
    twttr.dialogs.deleteSavedSearch(twttr.bind(this,
    // ....
    B.stopPropagation();
    B.preventDefault();
    return false
})&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;ve munged the code up a bit here, but you get the basic idea. Phoenix.js includes jquery (the latest release, 1.4.2), Jquery UI (1.8.4), &lt;a href='http://www.modernizr.com/'&gt;Modernizer&lt;/a&gt; (a library for detecting browser support for various html5 functionality), &lt;a href='http://benalman.com/code/test/js-linkify/'&gt;Linkify&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This was just a quick analysis of the newtwitter codebase - but I found all the mentions of &lt;code&gt;twttr.view&lt;/code&gt; to be interesting - it seems like the twitter engineering team have built quite a strong framework for javascript apps - I wonder if they&amp;#8217;ll release their MVC framework for other developers to create similair apps?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Varnish and Rails</title>
   <link href="http://bnolan.github.com/2010/09/23/varnish-and-rails.html"/>
   <updated>2010-09-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/23/varnish-and-rails</id>
   <content type="html">&lt;p&gt;I got my R scripts running on production for &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt; - so if you browse to &lt;a href='http://twitterplaces.com/wlg'&gt;Wellington&lt;/a&gt; or &lt;a href='http://twitterplaces.com/lon'&gt;London&lt;/a&gt;, you can see twitter densities. That&amp;#8217;s all well and good and very rough, there&amp;#8217;s a lot of work to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The time slider looks rubbish&lt;/li&gt;

&lt;li&gt;The tweet frequency histogram isn&amp;#8217;t adjusted for the cities time offset&lt;/li&gt;

&lt;li&gt;The extents of the different cities are different, so you get elongated contours&lt;/li&gt;

&lt;li&gt;The contour needs to be subdivided for smoothness&lt;/li&gt;

&lt;li&gt;It would be good to weigh against multiple tweets from a user&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But the first problem, is that the contours are exceptionally expensive to convert to json, which is done on every page load by ruby. I wanted to have an easy way to cache a page for 60 seconds, so that if the page gets &amp;#8216;seagulled&amp;#8217; (a thousand people follow a link from techcrunch, look at the page for a second, then go back to techcrunch to comment &amp;#8216;it doesnt scale get nosql why not use php&amp;#8217;) the site doesn&amp;#8217;t go down.&lt;/p&gt;

&lt;h1 id='ask_koz'&gt;Ask Koz&lt;/h1&gt;

&lt;p&gt;I originally was going to do some apache rewriterule hax, but first I asked &lt;a href='http://twitter.com/nzkoz'&gt;@nzkoz&lt;/a&gt;, who told me to look into &lt;a href='http://www.varnish-cache.org/'&gt;Varnish&lt;/a&gt;. Varnish looked good so I gave it a go.&lt;/p&gt;

&lt;h1 id='varnish'&gt;Varnish&lt;/h1&gt;

&lt;p&gt;I followed the installation instructions &lt;a href='http://www.varnish-cache.org/installation/ubuntu'&gt;for Ubuntu&lt;/a&gt;, then edited &lt;code&gt;/etc/defaults/varnish&lt;/code&gt; to make varnish listen on port 80.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;DAEMON_OPTS=&amp;quot;-a :80\
             -T localhost:6082 \&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I edited &lt;code&gt;/etc/apache2/ports.conf&lt;/code&gt; to move apache over to port 8080:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NameVirtualHost *:8080
Listen 8080&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And edited the appropriate &lt;code&gt;sites-available&lt;/code&gt; scripts to move the virtual hosts over to the new port. Then I edited my &lt;code&gt;/etc/varnish/default.vcl&lt;/code&gt; (make sure you install Varnish 2.x, not the 1.x that comes with some old varieties of Ubuntu) like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sub vcl_recv {
        unset req.http.Cookie;
}
  
sub vcl_fetch {
        if (req.request == &amp;quot;GET&amp;quot;) {
                unset beresp.http.Set-Cookie;
                set beresp.cacheable = true;
                set beresp.ttl = 60s;
        }

        if (req.url ~ &amp;quot;^/images/&amp;quot; || req.url ~ &amp;quot;^/javascripts&amp;quot; || req.url ~ &amp;quot;^/stylesheets&amp;quot;){
                set beresp.ttl = 15m;
        }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All GETs are cached for 60 seconds. Javascripts, images and stylesheets are cached (on the client side) for 15 minutes.&lt;/p&gt;

&lt;p&gt;Note that this varnish config will annihilate any site that uses cookies - but twitterplaces (and weheartplaces) currently don&amp;#8217;t use cookies at all - so everyones looks at the same pages. I then restarted varnish and &lt;em&gt;voila&lt;/em&gt;, we have a fast cached site that can cope with some seagulling.&lt;/p&gt;

&lt;p&gt;To check that things are working - I tailed my rails log, hit the site up with &lt;code&gt;curl -I http://twitterplaces.com/wlg/&lt;/code&gt; and each request was served correctly, but didn&amp;#8217;t show up in the rails logs until 60 seconds had elapsed. Varnish is very clever and will serve the old version of the cached page until the new version has finished regenerating. Varnish really does seem like a neat bit of kit.&lt;/p&gt;

&lt;p&gt;Elapsed time, from learning of Varnish, to installing, configuring, testing and writing this blog post - 45 minutes.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Moving to production</title>
   <link href="http://bnolan.github.com/2010/09/22/r-on-ubuntu.html"/>
   <updated>2010-09-22T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/22/r-on-ubuntu</id>
   <content type="html">&lt;p&gt;I lied. I wasn&amp;#8217;t really building twitterplaces, I just got back from 5 days snowboarding, relaxing and reading books by the fire. Now i&amp;#8217;m back in the office and started the week with getting my production box set up so I can deploy the next release of &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='monit'&gt;Monit&lt;/h1&gt;

&lt;p&gt;I set up a monit task to run my tweet importer and restart the process if it dies. The monit task looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;check process importer
	with pidfile /tmp/importer.pid
    	start program = &amp;quot;/usr/bin/sudo -u ben /var/www/tp/script/runner -e production Tweet.import&amp;quot; with timeout 20 seconds
    	stop program  = &amp;quot;/bin/kill -TERM `cat /tmp/importer.pid`&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that this job requires monit 5 since it uses the &lt;code&gt;with timeout&lt;/code&gt; parameter. I also added this line to my importer script so that it spits out the process id.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;`echo #{Process.pid} &amp;gt; /tmp/importer.pid`&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='r_and_odbc'&gt;R and ODBC&lt;/h1&gt;

&lt;p&gt;For my R scripts, I&amp;#8217;ve been using the postgres adapter so that I can query directly from within R. It turns out the package I was using on the desktop wasn&amp;#8217;t available on ubuntu, so I followed the instructions &lt;a href='http://ubuntuforums.org/showthread.php?t=614715'&gt;here&lt;/a&gt; and &lt;a href='http://simon.bonners.ca/blog///blog5.php/2010/03/13/accessing-a-postgresql-database-from-r-using-rodbc'&gt;here&lt;/a&gt; to get &lt;code&gt;RODBC&lt;/code&gt; set up with postgres.&lt;/p&gt;

&lt;h1 id='future_tasks'&gt;Future tasks&lt;/h1&gt;

&lt;p&gt;I have a few things left to do before the new release is complete and ready for people to use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data massaging&lt;/strong&gt; - the production database needs massaging and normalization of the bounding boxes for cities - I&amp;#8217;ve been doing this adhoc, but it needs to be integrated into the twitter import process.&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Data analysis cronjobs&lt;/strong&gt; - some of the data analysis jobs are best run hourly (for example the contour map generation), so these need to be scheduled as a cronjob&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Postgres partitioning&lt;/strong&gt; - twitterplaces now imports over 2m tweets a day. To reduce the load on postgres, I&amp;#8217;m going to use &lt;a href='http://www.postgresql.org/docs/current/static/ddl-partitioning.html'&gt;partitioning&lt;/a&gt; to reduce the size of the indices and quicker data truncation (I can just drop week old tables, instead of a delete and vacuum).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hopefully i&amp;#8217;ll be able to get some of that out later this week.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A break in transmission</title>
   <link href="http://bnolan.github.com/2010/09/16/regular-transmissions.html"/>
   <updated>2010-09-16T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/16/regular-transmissions</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m taking a week off blogging so I can focus on &lt;b&gt;building&lt;/b&gt;. Please excuse my silence - and I look forward to resuming communications with you all sometime next week.&lt;/p&gt;
&lt;img src='http://farm5.static.flickr.com/4133/4990723483_c1a4f97d5b.jpg' /&gt;&lt;cite&gt;Manners mall redevelopment&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Twitterplaces Next Generation</title>
   <link href="http://bnolan.github.com/2010/09/15/twitterplaces-ng.html"/>
   <updated>2010-09-15T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/15/twitterplaces-ng</id>
   <content type="html">&lt;p&gt;Ever since I &lt;a href='http://bennolan.com/2010/09/13/a-world-of-tweets.html'&gt;discovered&lt;/a&gt; that you can index all of the worlds geotagged tweets with Twitter, I&amp;#8217;ve been working on the next generation of twitterplaces. It&amp;#8217;s a challenge. The app has to work on datasets the size of Wellington (around 110 tweets per day) to New York (around 15k tweets per day) and provide an intimate experience for every user.&lt;/p&gt;

&lt;p&gt;One of the biggest problems with displaying lots of data on a map is that you end up with massive clouds of google markers all over the map. These look okay when there&amp;#8217;s less than 5 markers, but above that, clicking on many markers is a bad user experience, it&amp;#8217;s hard to get an aggregate view of what&amp;#8217;s going on.&lt;/p&gt;
&lt;img src='/images/twng.png' /&gt;&lt;cite&gt;Viewing wellington tweets grouped by contour density maps&lt;/cite&gt;
&lt;p&gt;I&amp;#8217;ve already posted about using R to create contour maps of tweet density. I&amp;#8217;ve now taken that code and changed it from a manual job, into something automated. It&amp;#8217;s not production ready yet - but the idea is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Contour generator (R script) runs hourly on top 1000 cities&lt;/li&gt;

&lt;li&gt;R queries postgres for tweets in the last hour&lt;/li&gt;

&lt;li&gt;Generate the density matrix, and generate contour lines&lt;/li&gt;

&lt;li&gt;Convert contours into &lt;a href='http://postgis.refractions.net/docs/ch04.html#RefObject'&gt;WKT&lt;/a&gt; polygons and save to the database&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you display a city page - you export the contour polygons into a json array (indexed by hour) and then give the user some UI for changing what time window they are looking at.&lt;/p&gt;

&lt;h1 id='realtime_contour_generation'&gt;Realtime contour generation&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m not in a hurry to try and do this in realtime, but it has been at the back of my mind. My bookmarks tagged &lt;a href='http://www.delicious.com/benn/contour'&gt;contour&lt;/a&gt; have my notes on the basic algorithm. Any query that filters keyword, user_id, generate contour maps of an individual suburb, do language analysis, sentiment analysis, etc - would generate data suitable for converting into contour maps.&lt;/p&gt;

&lt;p&gt;If I wanted to be able to generate this data in realtime, there are two ways I can see of doing it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Farm the raw tweet data off to the browser and generate the contour lines in Javascript&lt;/li&gt;

&lt;li&gt;An optimized C++ app that uses sse / simd to generate the contour lines in a fraction of the time of R&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or - I could charge customers monthly, fire up another ec2 instance and keep using the existing queries in R.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Panasonic Lumix and the Optimal Prime</title>
   <link href="http://bnolan.github.com/2010/09/14/panasonic-lumix.html"/>
   <updated>2010-09-14T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/14/panasonic-lumix</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been waiting to make this post for a few weeks now. I bought a Pansonic Lumix GF1 with the 20mm prime (non-zoomable) lens. It&amp;#8217;s a real beauty! It takes lovely photos, is a joy to use (nice and fast) and fits in my coat pocket. I bought it as a present to myself for three months working for Lonely Planet in Melbourne.&lt;/p&gt;

&lt;h1 id='choosing_the_gf1'&gt;Choosing the GF1&lt;/h1&gt;

&lt;p&gt;I got interested in a camera with a nice prime lens after seeing all &lt;a href='http://www.flickr.com/photos/maddiontour'&gt;Maddis&lt;/a&gt; epic photos. He uses a sony Alpha and the minolta beercan lens. I started researching and quickly became interested in getting an &lt;a href='http://www.photographyblog.com/reviews/sony_a330_review/'&gt;a330&lt;/a&gt; and hunting down some 80s lenses - but as I read around the net about small form factor dslrs, I kept seeing micro four thirds being mentioned, in particular the GF1.&lt;/p&gt;

&lt;p&gt;This &lt;a href='http://www.dpreview.com/reviews/PanasonicGF1/'&gt;review&lt;/a&gt; at dpreview and &lt;a href='http://craigmod.com/journal/gf1-fieldtest/'&gt;craigmods&lt;/a&gt; gf1 review were the articles that really sold me on the GF1. It&amp;#8217;ll be fun to pack up our house into a big box and then go travel the world with this camera hanging off my neck.&lt;/p&gt;
&lt;img src='http://farm5.static.flickr.com/4145/4985753541_25ab2b35d9_z.jpg' /&gt;&lt;cite&gt;Sweet Mothers Kitchen. Taken with the 20mm pancake lens&lt;/cite&gt;
&lt;p&gt;See more photos from last night on this &lt;a href='http://www.flickr.com/photos/benn/sets/72157624946265944/with/4985753541/'&gt;flickr set&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A world of tweets</title>
   <link href="http://bnolan.github.com/2010/09/13/a-world-of-tweets.html"/>
   <updated>2010-09-13T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/13/a-world-of-tweets</id>
   <content type="html">&lt;p&gt;The Twitter streaming API now lets you recieve all geotagged tweets, not just geotagged tweets in specified areas. This means that with a command like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;curl -d &amp;quot;locations=-180,-90,180,90&amp;quot; http://stream.twitter.com/1/statuses/filter.json -uuser:pass&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can recieve all the geotagged tweets twitter has. I updated my crawler to run against this complete dataset, fixed a few lingering bugs, and then let my crawler run for a few hours:&lt;/p&gt;
&lt;img src='/images/ooo.png' /&gt;&lt;cite&gt;o's indicate exact location, .'s indicate neighbourhood&lt;/cite&gt;
&lt;p&gt;I then exported my tweets, and plotted x vs y in R:&lt;/p&gt;
&lt;img src='/images/worldtweets.png' /&gt;&lt;cite&gt;plot(tweets$x, tweets$y); world(add=TRUE)&lt;/cite&gt;
&lt;p&gt;You can clearly see a world map forming, with a great concentration of geotagged tweets in north america, europe, japan and indonesia, as well as the outlines of Australia and New Zealand.&lt;/p&gt;

&lt;p&gt;What if we cluster the points using &lt;code&gt;kmeans&lt;/code&gt;?&lt;/p&gt;
&lt;img src='/images/kmeans.png' /&gt;&lt;cite&gt;Clustered into 5 groups using kmeans squared&lt;/cite&gt;
&lt;p&gt;We get 5 clusters, western us, eastern us, europe, asia and south america. Looks like Texas is an eastern state then. It&amp;#8217;s kind of scary that Africa is so sparse that it gets gobbled up by Europe, South America and Asia.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m keen to see what a histogram of seconds from midnight (what I call epoch) and longitude will look like - but i&amp;#8217;ll have to wait til I have 24 hours of data. It looks like I&amp;#8217;ll end up with about 2 million tweets per 24 hour period, which should make a good dataset.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Contour maps of tweet density</title>
   <link href="http://bnolan.github.com/2010/09/10/contour-maps.html"/>
   <updated>2010-09-10T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/10/contour-maps</id>
   <content type="html">&lt;p&gt;I regenerated by tweet density graphs using contour lines, and got this nice looking animation of tweet density in london over the course of a day.&lt;/p&gt;
&lt;object height='400' width='400'&gt;&lt;param name='movie' value='http://www.youtube.com/v/XMNg1Hjd6qE?fs=1&amp;amp;hl=en_US' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;embed src='http://www.youtube.com/v/XMNg1Hjd6qE?fs=1&amp;amp;hl=en_US' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='400' width='400' /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;cite&gt;24 hours of tweets in London&lt;/cite&gt;&lt;br /&gt;
&lt;p&gt;The important improvements:&lt;/p&gt;

&lt;h2 id='use_a_sliding_time_window'&gt;Use a sliding time window&lt;/h2&gt;

&lt;p&gt;Before I was using hourly updates, which meant that the updates were quite abrupt, and I could have a maximum of 24 frames per movie. I used this subquery to pull out the number of seconds since midnight, so that I could use a sliding time window of one hour in R:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;extract(epoch from created_at::time)&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='use_contour_lines'&gt;Use contour lines&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;contour&lt;/code&gt; function in R generates really nice contours from heightmaps. They look nice, and are easily georeferenced.&lt;/p&gt;

&lt;h2 id='resample_the_density_matrix'&gt;Resample the density matrix&lt;/h2&gt;

&lt;p&gt;I sample the tweets in a 50x50 matrix. This works, but gives quite sharp contour lines. The &lt;code&gt;image.smooth&lt;/code&gt; function (from the image library) came in handy here, as it uses a gaussian smoothing kernel on each element in the matrix. The default settings gives a nice smooth heightfield which can be plotted by contour&lt;/p&gt;

&lt;h2 id='next_steps'&gt;Next steps&lt;/h2&gt;

&lt;p&gt;After this - I worked out that I could call &lt;code&gt;contourLines&lt;/code&gt; to get the line coordinates. Then by converting this to json using &lt;code&gt;rjson&lt;/code&gt;, I plotted the contourlines onto a google map using polygons. Finally, I made it so that you can click on the polygons, and see what tweets and neighbourhoods are causing weird spikes of activity.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m busy with client work at the moment, so hopefully sometime next week I can push an update to &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt; that features these contour maps.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Imperial March</title>
   <link href="http://bnolan.github.com/2010/09/08/imperial-march.html"/>
   <updated>2010-09-08T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/08/imperial-march</id>
   <content type="html">&lt;p&gt;One of the benefits from working at home is that I get to play trumpet and guitar as much as I want. Which means lots of time to practise.&lt;/p&gt;
&lt;object height='320' width='400'&gt;&lt;param name='movie' value='http://www.youtube.com/v/ZiXNUzFYvmw?hl=en&amp;fs=1' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;embed src='http://www.youtube.com/v/ZiXNUzFYvmw?hl=en&amp;fs=1' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='320' width='400' /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;For some reason, practising lots of the trumpet isn&amp;#8217;t helping me get better at all.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Tweet map in R</title>
   <link href="http://bnolan.github.com/2010/09/07/tweet-map-in-r.html"/>
   <updated>2010-09-07T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/07/tweet-map-in-r</id>
   <content type="html">&lt;p&gt;Just as a quick follow up to yesterdays post - this is the very rough visualization I came up with using R, openGL and ffmpeg.&lt;/p&gt;
&lt;object height='320' width='400'&gt;&lt;param name='movie' value='http://www.youtube.com/v/iqz6skQLkaQ?fs=1&amp;amp;hl=en_US' /&gt;&lt;param name='allowFullScreen' value='true' /&gt;&lt;param name='allowscriptaccess' value='always' /&gt;&lt;embed src='http://www.youtube.com/v/iqz6skQLkaQ?fs=1&amp;amp;hl=en_US' allowfullscreen='true' type='application/x-shockwave-flash' allowscriptaccess='always' height='320' width='400' /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;
&lt;p&gt;The r script used was something like this. The texture isn&amp;#8217;t correctly georeferenced, and needs to be flipped 180°, but this was as far as I got before having to move onto other work.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ourplot &amp;lt;- function (h) {
  north = 51.6
  south = 51.4
  east = 0.05
  west = -0.25

  df &amp;lt;- subset(tweets, x &amp;gt; west &amp;amp; x &amp;lt; east &amp;amp; y &amp;lt; north &amp;amp; y &amp;gt; south &amp;amp; hour == h)

  df &amp;lt;- rbind(df, data.frame(x=east, y=north, hour=-1))
  df &amp;lt;- rbind(df, data.frame(x=west, y=south, hour=-1))

  hdf &amp;lt;- hist2d(df$x, df$y, nbins=50, show=FALSE)

  persp3d( 
    hdf$x, 
    hdf$y, 
    hdf$counts, 
    ticktype=&amp;quot;detailed&amp;quot;,
    xlab=&amp;quot;Longitude&amp;quot;,
    ylab=&amp;quot;Latitude&amp;quot;,
    zlab=&amp;quot;# Tweets&amp;quot;,
    zlim=c(-30,50),
    expand=0.5, 
    shade=1.0, 
    specular=&amp;quot;white&amp;quot;,
    col=&amp;quot;white&amp;quot;,
    texture=&amp;quot;/tmp/london.png&amp;quot;,
    box=FALSE,
    axes=FALSE
  )

  rgl.snapshot(paste(&amp;quot;/tmp/london-3d-&amp;quot;,h,&amp;quot;.png&amp;quot;,sep=&amp;quot;&amp;quot;))
}

for (hour in seq(0,24,by=1)) ourplot(hour)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I have a vague plan of taking the histogram matrix, exporting it to json and using protovis to redraw the graphs, possibly as a &lt;a href='http://vis.stanford.edu/protovis/ex/stream.html'&gt;streamgraph&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Plotting Choropleths with r</title>
   <link href="http://bnolan.github.com/2010/09/06/plotting-choropleths-with-r.html"/>
   <updated>2010-09-06T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/06/plotting-choropleths-with-r</id>
   <content type="html">&lt;p&gt;Choropleths are those &lt;a href='http://flowingdata.com/2009/11/12/how-to-make-a-us-county-thematic-map-using-free-tools/'&gt;heatmap style&lt;/a&gt; maps you often see. I&amp;#8217;ve been keen to render some heatmaps out of the &lt;a href='http://twitterplaces.com'&gt;twitterplaces&lt;/a&gt; data I have, so I spent today learning R and using it to generate some graphs.&lt;/p&gt;

&lt;p&gt;First up - I installed R using the os x binaries, then went right on to install rgdal.&lt;/p&gt;

&lt;h2 id='installing_rgdal_on_snow_leopard'&gt;Installing rgdal on snow leopard&lt;/h2&gt;

&lt;p&gt;To load map data, you first need to install the PROJ and &lt;a href='http://www.kyngchaos.com/software:postgres'&gt;GDAL frameworks&lt;/a&gt;. Then you need to install the R bindings for GDAL. When you try and install RGDAL from source - you may get this error:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Error: gdal-config not found
The gdal-config script distributed with GDAL could not be found.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To let R know where gdal and proj are - try this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;install.packages(&amp;quot;rgdal&amp;quot;, configure.args = &amp;quot; \
  --with-gdal-config=/Library/Frameworks/GDAL.framework/unix/bin/gdal-config \
  --with-proj-include=/Library/Frameworks/PROJ.framework/unix/include \
  --with-proj-lib=/Library/Frameworks/PROJ.framework/unix/lib \
&amp;quot;,type=&amp;quot;source&amp;quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;R packages install super fast for me, rgdal took about 30 seconds to build and install. I&amp;#8217;m beginning to see why people like this package.&lt;/p&gt;

&lt;h2 id='plotting_california_state_boundies'&gt;Plotting california state boundies&lt;/h2&gt;

&lt;p&gt;Download the &lt;a href='http://www.census.gov/geo/www/cob/co2000.html'&gt;california shape files&lt;/a&gt; from the US census, then load the data and plot it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cali=readOGR(&amp;quot;/tmp&amp;quot;,&amp;quot;co06_d00&amp;quot;)
plot(cali)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should get a graph of californian country boundaries:&lt;/p&gt;
&lt;img src='/images/choropleth/cali.png' /&gt;&lt;cite&gt;Plot of US census geo data&lt;/cite&gt;
&lt;p&gt;Now to extract data from my twitter data.&lt;/p&gt;

&lt;h2 id='generating_neighbourhood_shapefiles'&gt;Generating neighbourhood shapefiles&lt;/h2&gt;

&lt;p&gt;As I import tweets from the twitter firehose, I create records in my place table that store the geometry data in a postgis &lt;code&gt;polygon&lt;/code&gt; field. This means I can use &lt;code&gt;pgsql2shp&lt;/code&gt; to extract the geometry data and create shape files that can be loaded into arcgis explorer, or imported into R using the readOGR command.&lt;/p&gt;

&lt;p&gt;To generate my shape file - I run something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pgsql2shp -f london -u postgres tp_dev &amp;quot;select \
  name, geom \
from \
  places \
where \
  kind=&amp;#39;neighborhood&amp;#39; and city_id=( \
    select id from cities where name=&amp;#39;London&amp;#39; \
  )&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which gives me 115 rows, all of the neighbourhoods in London that I have crawled so far. Plotting this data in R:&lt;/p&gt;
&lt;img src='/images/choropleth/london.png' /&gt;&lt;cite&gt;Plot of London twitter neighbourhoods&lt;/cite&gt;
&lt;p&gt;Twitter uses &lt;a href='http://www.maponics.com/products/gis-data/neighborhood-boundaries/overview/'&gt;third party data&lt;/a&gt; to geocode your tweets. Sadly, the neighbourhood data isn&amp;#8217;t free, so twitter can only share bounding boxes, which is why the map is all boxes.&lt;/p&gt;

&lt;p&gt;In the future I might try querying openstreetmap for &lt;a href='http://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative'&gt;boundary data&lt;/a&gt; of administration areas 9 and 10, but I&amp;#8217;m not sure how complete that data is.&lt;/p&gt;

&lt;h2 id='getting_tweet_frequency'&gt;Getting Tweet frequency&lt;/h2&gt;

&lt;p&gt;I re-ran the neighbourhood shape file dump, to include the number of users tweeting from each neighbourhood in london. The query ended up looking something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select \
  id, geom, name, ( \
    select count(distinct user_id) from tweets where place_id=places.id \
  ) as user_count \
from \
  places \
where \
  city_id=( \
    select id from cities where name=&amp;#39;London&amp;#39; \
  ) AND kind = &amp;#39;neighborhood&amp;#39; \
order by \
  user_count desc;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I can then load this data into R, create a blue palette and plot it in 3 lines:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pal &amp;lt;- brewer.pal(9,&amp;quot;Blues&amp;quot;)
plot(lon,col=pal[9 - (lon$USER_COUNT * 9 / max(lon$USER_COUNT))],border=&amp;quot;white&amp;quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The graph however - is kinda disappointing, since the overlapping bounding boxes - combined with some very large neighbourhood areas, makes the graph pretty much useless.&lt;/p&gt;
&lt;img src='/images/choropleth/london-heatmap.png' /&gt;&lt;cite&gt;Darker blue represents more tweets&lt;/cite&gt;
&lt;h2 id='two_dimensional_histogram'&gt;Two dimensional histogram&lt;/h2&gt;

&lt;p&gt;After failing at my first graphing experiment, I tried plotting a two dimensional histogram of tweets. First up - spit out all the lats and longs of tweets from postgres. I haven&amp;#8217;t installed the r&amp;lt;-&amp;gt;postgres bindings yet, so I have to export to CSV and then import to R.&lt;/p&gt;

&lt;p&gt;Enable CSV export from psql.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;\f &amp;#39;,&amp;#39; 
\a
\pset footer off
\o /tmp/tweets.csv&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then query&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;select 
  st_x(geom) as x, st_y(geom) as y, extract(hour from created_at) as hour 
from
  tweets 
where 
  geom is not null
and
  st_x(geom) &amp;lt; -100&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This also gives us the hour of the day that the tweet was made, which might come in handy later. I loaded this data into R, then I could plot a scatter graph:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tweets &amp;lt;- read.csv(&amp;quot;/tmp/tweets.csv&amp;quot;)
plot(tweets$x, tweets$y)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Gives a random looking graph with a concentration of points around the mission.&lt;/p&gt;
&lt;img src='/images/choropleth/scatter-sfo.png' /&gt;&lt;cite&gt;A scattergraph of 1600 geotagged tweets around San Francisco&lt;/cite&gt;
&lt;p&gt;Okay - what does this look like as a 2d histogram?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;hist2d(tweets$x,tweets$y)&lt;/code&gt;&lt;/pre&gt;
&lt;img src='/images/choropleth/heat-sfo.png' /&gt;&lt;cite&gt;A 2d histogram of tweets around San Francisco&lt;/cite&gt;
&lt;p&gt;Starting to get interesting - but still way too sparse. Let&amp;#8217;s trim the area down to only include San Francisco proper, from the Marina District in the north, to the mission in the south.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;city &amp;lt;- subset(tweets, y &amp;lt; 37.808 &amp;amp; y &amp;gt; 37.750 &amp;amp; x &amp;lt; -122.370 &amp;amp; x &amp;gt; -122.457)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then let&amp;#8217;s plot it in perspective 3d&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;h &amp;lt;- hist2d(city$x, city$y, nbins=25)
persp( 
  h$x, 
  h$y, 
  h$counts, 
  ticktype=&amp;quot;detailed&amp;quot;, 
  theta=30, 
  phi=30, 
  expand=0.5, 
  shade=0.5, 
  col=&amp;quot;cyan&amp;quot;, 
  ltheta=-30
)&lt;/code&gt;&lt;/pre&gt;
&lt;img src='/images/choropleth/sfo-persp.png' /&gt;&lt;cite&gt;User count in San Francisco rendered in a perspective view&lt;/cite&gt;
&lt;p&gt;The mission / cbd is in the top right of this graph, so you can see where most people are during the day.&lt;/p&gt;

&lt;h2 id='animating_the_graph_over_time'&gt;Animating the graph over time&lt;/h2&gt;

&lt;p&gt;This is rendering 5 hours of data on one graph, but I was interested to see how the activity looked on an hourly basis, so I wrote a little R script to re-render the graph for each hour of the day, which may be a topic for tomorrows blog post.&lt;/p&gt;

&lt;p&gt;nb: Note that I never actually created realistic looking choropleths in this post. ;D&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Specialization and Art</title>
   <link href="http://bnolan.github.com/2010/09/03/art-on-fridays.html"/>
   <updated>2010-09-03T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/03/art-on-fridays</id>
   <content type="html">&lt;p&gt;I like &lt;a href='http://elise.com/quotes/a/heinlein_-_specialization_is_for_insects.php'&gt;Heinleins quote&lt;/a&gt;, so instead of Follow Friday, I decided to try and post Art on Friday. So, an old charcoal drawing that&amp;#8217;s been hanging in my office, and 90 seconds of my acoustic guitar.&lt;/p&gt;
&lt;img src='/images/charcoal-drawing.jpg' /&gt;&lt;cite&gt;Drawn at &lt;a href='http://www.vincents.co.nz/'&gt;Vincents&lt;/a&gt; life drawing class in 2008&lt;/cite&gt;
&lt;p&gt;A warning - I made the guitar track up as I went along, so it&amp;#8217;s pretty rough eh.&lt;/p&gt;
&lt;audio controls='true' src='/tracks/friday-acoustic.mp3' autobuffer='true'&gt; &lt;/audio&gt;&lt;cite&gt;Something around Am and C, on my Tanglewood acoustic&lt;/cite&gt;
&lt;p&gt;The track was recorded by the imac&amp;#8217;s internal microphone (I need to get a 9 volt battery so I can use the pick-ups on the acoustic), so sounds a bit like it was recorded in a tin can.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>What to drink on Thursdays?</title>
   <link href="http://bnolan.github.com/2010/09/02/what-to-drink.html"/>
   <updated>2010-09-02T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/02/what-to-drink</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been making a real effort to avoid coffee in the afternoon. I&amp;#8217;ve made the discovery that although the first cup of coffee in the morning is awesome, afternoon coffees are just that &amp;#8216;cup of stress&amp;#8217; that my vegan friends talk about.&lt;/p&gt;

&lt;p&gt;So I made myself a handy guide to what I should drink, hour by hour, on Thurdays.&lt;/p&gt;
&lt;img src='/images/drinks.jpg' /&gt;&lt;cite&gt;Tea... Wins!&lt;/cite&gt;
&lt;p&gt;The beer is optional, although I was planning on catching up with &lt;a href='http://chillu.com/'&gt;Herr Schommer&lt;/a&gt; after work.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Polygons and postgis</title>
   <link href="http://bnolan.github.com/2010/09/01/polygons-and-postgis.html"/>
   <updated>2010-09-01T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/09/01/polygons-and-postgis</id>
   <content type="html">&lt;p&gt;I use &lt;a href='http://postgis.refractions.net/'&gt;postgis&lt;/a&gt; extensively in my geo-local development. If you&amp;#8217;re working on a project that involves geo data and you haven&amp;#8217;t seriously looked into postgis, you&amp;#8217;re doing yourself a disfavour.&lt;/p&gt;

&lt;p&gt;Postgres is really quite epic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Postgis&lt;/li&gt;

&lt;li&gt;&lt;a href='http://rpgsql.sourceforge.net/'&gt;R for Postgres&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.pygresql.org/'&gt;Python for Postgres&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;A nice stable API for creating C++ extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We used the C++ API to make a &lt;a href='http://xapian.org/'&gt;xapian&lt;/a&gt; plugin for &lt;a href='http://zoomin.co.nz/'&gt;zoomin&lt;/a&gt;, back in the day before &lt;a href='http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/'&gt;tsearch2&lt;/a&gt; became integrated into Postgresql.&lt;/p&gt;

&lt;h2 id='twitterplaces'&gt;Twitterplaces&lt;/h2&gt;

&lt;p&gt;&lt;a href='http://twitter.com/sminnee/'&gt;Sam&lt;/a&gt; asked that I add polygons onto my &lt;a href='http://twitterplaces.com/sfo/soma'&gt;twitterplaces maps&lt;/a&gt;, so that he could see where the boundaries of a neighbourhood are.&lt;/p&gt;
&lt;img src='/images/soma-tp.png' /&gt;&lt;cite&gt;South of Mission on Twitterplaces&lt;/cite&gt;
&lt;p&gt;The twitter places API gives you the bounding boxes of a place, so I already had the information, it was just a case of how to store the bounding boxes. I decided to do it properly and use &lt;a href='http://github.com/fragility/spatial_adapter'&gt;spatial_adapter&lt;/a&gt; and a :polygon column in my places table.&lt;/p&gt;

&lt;p&gt;This meant I could use a method like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def bounding_box=(params)
  points = []

  params[&amp;#39;coordinates&amp;#39;].first.each do |c|
    points.push GeoRuby::SimpleFeatures::Point.from_x_y(c.first, c.last)
  end

  self.latitude = points.collect(&amp;amp;:y).sum / points.length
  self.longitude = points.collect(&amp;amp;:x).sum / points.length

  c = params[&amp;#39;coordinates&amp;#39;].first.first
  points.push GeoRuby::SimpleFeatures::Point.from_x_y(c.first, c.last)
  self.geom = GeoRuby::SimpleFeatures::Polygon::from_points([points])
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To convert twitters json representation of a place into a WKRT geometry object in my database. This is cool, because then I can use some coffeescript like this to draw the polygon onto my maps.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if $place.geom.rings
  points = []
  bounds = new google.maps.LatLngBounds

  for point in $place.geom.rings[0].points
    coord = new google.maps.LatLng(point.y, point.x)
    bounds.extend coord
    points.push coord

  if bounds.toSpan().lat() == 0.0 or bounds.toSpan().lng() == 0.0
    marker = new google.maps.Marker {
      map : map
      position : bounds.getCenter()
    }
  else
    poly = new google.maps.Polygon {
      paths : [points]
      map : map
      strokeColor : &amp;#39;#ff0000&amp;#39;
      strokeOpacity: 0.5
      fillOpacity : 0.1
      fillColor : &amp;#39;#ff0000&amp;#39;
    }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That code also checks whether the polygon is degenerate (of zero size), and then plots a marker instead. Twitter always sends polygons, even if the polygon has zero area. Anyway. So this was all nice and took 15 minutes to code up. But it also let me do something super awesome:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def find_child_pois
  Place.find(:all, :conditions =&amp;gt; [&amp;#39;kind = ? AND st_contains(?, geom)&amp;#39;, &amp;#39;poi&amp;#39;, geom])
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I now have a method to find all places contained inside a place. So for example, &lt;a href='http://twitterplaces.com/sfo/soma'&gt;South of Mission&lt;/a&gt; in San Francisco, has &lt;a href='http://twitterplaces.com/sfo/adobe-systems-san-francisco'&gt;Adobe Systems&lt;/a&gt; inside of it. You can also find out which places contain this one - for example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt; Place.find_by_path(&amp;#39;sfo/soma&amp;#39;).find_parents.collect(&amp;amp;:name)
=&amp;gt; [&amp;quot;San Francisco&amp;quot;, &amp;quot;SoMa&amp;quot;, &amp;quot;California&amp;quot;]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I was pretty excited when all this came together so well. When I&amp;#8217;ve got more time, I&amp;#8217;d like to fix up the crawler that feeds twitterplaces, since at the moment it just dumps the database and recreates it every hour from a sampling of the twitter firehose.&lt;/p&gt;

&lt;p&gt;Ah - for more good hours in the day.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Agile board in html5</title>
   <link href="http://bnolan.github.com/2010/08/30/agile-board.html"/>
   <updated>2010-08-30T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/30/agile-board</id>
   <content type="html">&lt;p&gt;I put &lt;a href='/science/velocity/'&gt;this together&lt;/a&gt; as a quick prototype of what an agile board in HTML5 could look like. I&amp;#8217;m not a huge agile fan myself, but since I keep having to use pivotal tracker in projects - I&amp;#8217;m always tempted to do a little bit more work on it and get it to a usable state.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Batched save ruby module</title>
   <link href="http://bnolan.github.com/2010/08/29/batched-save.html"/>
   <updated>2010-08-29T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/29/batched-save</id>
   <content type="html">&lt;p&gt;In my work on &lt;a href='http://twitterplaces.com/'&gt;twitterplaces&lt;/a&gt; - I&amp;#8217;ve been commonly importing several thousand tweets at once from the streaming API. As I re-write my import process, I have to re-run this import job, so I&amp;#8217;ve been trying to get it as fast as possible. Currently what I do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use memcache&lt;/li&gt;

&lt;li&gt;Use &lt;a href='http://gist.github.com/555750'&gt;batched_save&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Batched save is my module I created to let you &lt;code&gt;include BatchedSave&lt;/code&gt; in a model, and then when you save a new record - it&amp;#8217;ll batch up 100 records and use COPY to insert them. It is for postgresql only, and obviously only works in situations like mine where the data isn&amp;#8217;t self-referential, but it&amp;#8217;s mega fast.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>My 10k submission was accepted</title>
   <link href="http://bnolan.github.com/2010/08/27/10k-submission-accepted.html"/>
   <updated>2010-08-27T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/27/10k-submission-accepted</id>
   <content type="html">&lt;p&gt;Woohoo! Please go &lt;a href='http://10k.aneventapart.com/Entry/394'&gt;vote now&lt;/a&gt;! It&amp;#8217;s a bit lame they&amp;#8217;ve got the unsexiest screenshot first, but&amp;#8230; yay!&lt;/p&gt;
&lt;img src='/images/10kgallery.png' /&gt;&lt;cite&gt;My entry in the official 10k gallery&lt;/cite&gt;
&lt;p&gt;There is a community prize that you win by getting the most votes - so if you like my submission, please spread the word.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>All done - in under 10240 bytes</title>
   <link href="http://bnolan.github.com/2010/08/26/under-10240-bytes.html"/>
   <updated>2010-08-26T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/26/under-10240-bytes</id>
   <content type="html">&lt;p&gt;Well, it&amp;#8217;s done. I just submitted my entry to the &lt;a href='http://10k.aneventapart.com/Entry/394'&gt;10k apart&lt;/a&gt; competition. It&amp;#8217;s been a pretty intense 24 hours, but I&amp;#8217;m glad I gave myself some extra time this morning to polish up my entry.&lt;/p&gt;
&lt;img src='/images/10kapart-preview.png' /&gt;&lt;cite&gt;Planning a trip to Paris, a screenshot from an earlier build&lt;/cite&gt;
&lt;p&gt;You can &lt;a href='http://10k.aneventapart.com/Entry/394'&gt;try it out here&lt;/a&gt; - all 9766 bytes of it.&lt;/p&gt;

&lt;h2 id='toolchain'&gt;Toolchain&lt;/h2&gt;

&lt;p&gt;I built the app using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://jashkenas.github.com/coffee-script/'&gt;Coffeescript&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://lesscss.org/'&gt;Less CSS&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://api.jquery.com/'&gt;jQuery&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://diveintohtml5.org/'&gt;HTML5&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://pdfcrowd.com/'&gt;PDFCrowd&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://code.google.com/apis/maps/documentation/staticmaps/'&gt;Google Static Maps&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://developer.yahoo.com/yui/compressor/'&gt;YUI Compressor&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://code.google.com/closure/'&gt;Google closure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have some extra code that is commented out, that does an autocomplete from Wikipedia when you add a new destination to your trip. So for example, you could type &amp;#8216;Montmar&amp;#8217; and get an autocomplete for Montmartre. It&amp;#8217;s nice because [a] I&amp;#8217;m not very good at french spelling and [b] you automatically get some description text of the place from Wikipedia.&lt;/p&gt;

&lt;p&gt;I also removed a column on the left that let you organise trips to different cities. I probably would&amp;#8217;ve been pushing the 10k limit had I kept adding features, but mainly I didn&amp;#8217;t have time to build and test the features properly. I enjoyed having time today to add some extra destinations to the trip, change the dates a little, and test the app thoroughly on each of the browsers.&lt;/p&gt;

&lt;h2 id='compression'&gt;Compression&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;d like to thank &lt;a href='http://blog.nihilogic.dk/2008/05/compression-using-canvas-and-png.html'&gt;Nihilogic&lt;/a&gt; for their awesome canvas compression technique. Because I could compress the javascript and css so effectively, I didn&amp;#8217;t have to muck around pruning bytes from my css and javascript, which meant I could spend more time polishing the app.&lt;/p&gt;

&lt;p&gt;For reference - here&amp;#8217;s the breakdown of the sizes of my CSS at different stages of my development pipeline. I used a simple bash script to compile, compress and package everything.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;|              | Source | Comp  | Opt  | PNG  |
| Less CSS     | 7143   | 7589  | 5961 | 1898 |
| Coffeescript | 11388  | 13742 | 9445 | 3879 |&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='internet_explorer_9'&gt;Internet Explorer 9&lt;/h2&gt;

&lt;p&gt;It&amp;#8217;s been an interesting experience using IE 9. It looks like it&amp;#8217;s going to be a good browser. I will still use Safari as my main browser and development tool (even if they did release IE9 for mac), but it looks like I&amp;#8217;ll be supporting Safari 5, Chrome, Firefox 3.5 and IE 9 in all my future web apps.&lt;/p&gt;

&lt;h2 id='thanks'&gt;Thanks&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;d like to thank @sminnee, @ristari, @nzkoz, @clarketus, @nikz, @agrath, @terrcin, @lancehodges, @youdoham, @nazdrug and @campbell for their support, feedback and bug checking while I put this thing together. I couldn&amp;#8217;t have got it done without you all, thanks.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Why not consult?</title>
   <link href="http://bnolan.github.com/2010/08/25/why-not-consult.html"/>
   <updated>2010-08-25T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/25/why-not-consult</id>
   <content type="html">&lt;p&gt;In the preparation for my leap back into the world of start-ups, I&amp;#8217;ve been wondering why I don&amp;#8217;t prefer to consult full-time. Consulting has a bunch of pros:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Excellent pay&lt;/li&gt;

&lt;li&gt;Challenging projects&lt;/li&gt;

&lt;li&gt;Turn your brain off at 5pm&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It struck me today - that the main reason I don&amp;#8217;t enjoy doing javascript / rails consulting is because I &lt;em&gt;can&amp;#8217;t do it all day long&lt;/em&gt;. I can do 4-5 hours of it and stay in flow, but after that it&amp;#8217;s a real struggle. Sure I can churn out more code and fix bugs, but I&amp;#8217;m not being creative, I&amp;#8217;m overexercising the part of my brain that writes code.&lt;/p&gt;

&lt;p&gt;And in a small business, that&amp;#8217;s the perfect time of day to put away your text editor, open up skype, imovie and mail.app, and start down some of that marketing work.&lt;/p&gt;

&lt;p&gt;I think this all comes back to Heinlein.&lt;/p&gt;
&lt;quote&gt;Specialization is for Insects&lt;/quote&gt;
&lt;p&gt;I want to be able to play the cello, climb a multipitch, fix a car, nurse a child, write a book, rally a crowd, run a marathon, pontificate on a beer, console a friend or any of a million more things.&lt;/p&gt;

&lt;p&gt;Small business takes away your safety net, but it lets you try out as every act in the circus.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>My 10k apart submission</title>
   <link href="http://bnolan.github.com/2010/08/24/10k-apart.html"/>
   <updated>2010-08-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/24/10k-apart</id>
   <content type="html">&lt;p&gt;I haven&amp;#8217;t had much time to look at the Facebook Places API, but I have been working on my &lt;a href='http://10k.aneventapart.com/'&gt;10k apart&lt;/a&gt; submission. This competition challenges you to build a functioning web app in only 10 kilobytes of javascript, html and css.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve decided to take an idea I&amp;#8217;ve had kicking around (a trip planner for &lt;a href='http://www.weheartplaces.com/'&gt;weheartplaces&lt;/a&gt;) and see if it can be polished up to fit into the 10k limit.&lt;/p&gt;
&lt;img src='/images/10kapart-preview.png' /&gt;&lt;cite&gt;Planning a trip to Paris, a screenshot from earlier this morning&lt;/cite&gt;
&lt;p&gt;Using the command &lt;code&gt;ls -l *.css *.js *.html | awk &amp;#39;{sum+=$5} END {print sum}&amp;#39;&lt;/code&gt; to sum up the bytes, I&amp;#8217;m already up to 12k of content for the unoptimized code.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m aiming to keep the entire project under 20k in unoptimized form, which will hopefully make the 10k limit achievable. &lt;a href='http://jashkenas.github.com/coffee-script/'&gt;Coffeescript&lt;/a&gt; and &lt;a href='http://lesscss.org/'&gt;less&lt;/a&gt; output is quite verbose - and will benefit from &lt;a href='http://code.google.com/closure/'&gt;closure&lt;/a&gt; and the &lt;a href='http://developer.yahoo.com/yui/compressor/'&gt;YUI compressor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Wish me luck. The deadline is lunchtime tomorrow (NZDT).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A varied gym schedule</title>
   <link href="http://bnolan.github.com/2010/08/23/a-varied-gym-schedule.html"/>
   <updated>2010-08-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/23/a-varied-gym-schedule</id>
   <content type="html">&lt;p&gt;Like some web developers, I&amp;#8217;m a bit ADD, so I find going to the gym a bit of a chore. Don&amp;#8217;t get me wrong. I love the exercise, the clear headedness afterwards, the more energy you have in every day, the rest for your mind - a blissful 45 minutes where your brain doesn&amp;#8217;t have to analyse pixels on a screen, or type strange patterns into the keyboard.&lt;/p&gt;

&lt;p&gt;But spending 45 minutes with no mental stimulation - how dull is that! Especially when you go to the gym at quiet times (I don&amp;#8217;t like noisy gyms), there&amp;#8217;s not even anyone to talk to.&lt;/p&gt;

&lt;p&gt;So my workout which is nice and varied is like so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;3km rowing ~12 minutes&lt;/li&gt;

&lt;li&gt;Situps, pushups and chins x3 sets ~15 minutes&lt;/li&gt;

&lt;li&gt;Treadmill on hilly mode ~15 minutes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I find the treadmill the hardest, since it&amp;#8217;s just so dull - but I take it as a nice time to be all Zen (after the half an hour of exercise I find my inner Zen-buddha is easier to access). I set the treadmill to &amp;#8216;randomly changing gradient&amp;#8217;, so that your heart rate is constantly moving up and down.&lt;/p&gt;

&lt;p&gt;Anyway - that works for me, and I&amp;#8217;ve found it an easy workout to do consistently 4 times per week&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Analyzing a places page</title>
   <link href="http://bnolan.github.com/2010/08/20/a-facebook-place.html"/>
   <updated>2010-08-20T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/20/a-facebook-place</id>
   <content type="html">&lt;p&gt;Since Facebook places isn&amp;#8217;t available outside of the US yet - I&amp;#8217;ve only had two options for exploring the places api.&lt;/p&gt;

&lt;p&gt;Firstly - my good friend &lt;a href='http://twitter.com/clarketus/'&gt;loliver&lt;/a&gt; moved to Palo Alto two months ago to work for &lt;a href='http://www.wildfireapp.com/'&gt;Wildfire&lt;/a&gt;, so I&amp;#8217;ve been following his &lt;a href='http://www.facebook.com/pages/Wildfire-HQ/119484554770490'&gt;checkins&lt;/a&gt;.&lt;/p&gt;
&lt;img src='/images/facebookplace-page.png' /&gt;&lt;cite&gt;Wildfire HQ Places page&lt;/cite&gt;
&lt;p&gt;I love the design, it&amp;#8217;s nice and simple, has a strong social component (with the facebook wall), had a piece of content in the middle of the page (the map), some stats on the left to get an idea of the popularity of this place - and then a list of people who have checked in there which gives some &amp;#8216;explorability&amp;#8217; to the places pages.&lt;/p&gt;

&lt;p&gt;They don&amp;#8217;t have &amp;#8216;nearby&amp;#8217; or &amp;#8216;similair&amp;#8217; places, but that might just be because it&amp;#8217;s new and not enough of my friends have checked into multiple places.&lt;/p&gt;

&lt;h2 id='proxies_and_geolocation_hacks'&gt;Proxies and geolocation hacks&lt;/h2&gt;

&lt;p&gt;The other way I&amp;#8217;ve been trying out the facebook is by proxying my requests through my US servers (which doesn&amp;#8217;t seem necessary now that they&amp;#8217;ve deployed the places functionality worldwide). The only downside is that when your browser tries to geolocate you, Facebook works out you&amp;#8217;re not in the US and gives up.&lt;/p&gt;

&lt;p&gt;The next trick for Monday will be to make a greasemonkey script that emulates the W3C geolocation API and let&amp;#8217;s you check &lt;a href='http://twitter.com/nzkoz/'&gt;friends&lt;/a&gt; into &lt;a href='http://www.tuscl.net/s.php?SID=27'&gt;Kentucky strip clubs&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Facebook Places</title>
   <link href="http://bnolan.github.com/2010/08/19/facebook-places.html"/>
   <updated>2010-08-19T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/19/facebook-places</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m really excited about the release of &lt;a href='http://developers.facebook.com/blog/post/403'&gt;Facebook Places&lt;/a&gt;. It&amp;#8217;s not widely available yet but it should be rolled out to American Facebook users over the next 24 hours.&lt;/p&gt;
&lt;img src='/images/facebookplaces.png' /&gt;&lt;cite&gt;Facebook places on the iPhone&lt;/cite&gt;
&lt;p&gt;The features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checking in to places, for where you are at the moment&lt;/li&gt;

&lt;li&gt;Tagging friends as being with you at a place&lt;/li&gt;

&lt;li&gt;Seeing where your friends are and have been&lt;/li&gt;

&lt;li&gt;An extensive API for accessing a users places data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It&amp;#8217;s number 4 that&amp;#8217;s exciting to me. Facebook gives a bunch of examples of ways the API could be used - including:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A travel application that gives people the ability to see which of their friends have already been to the place they are visiting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s kind of exactly what I&amp;#8217;ve been building. Starting next week, I&amp;#8217;ll be working on the re-release of &lt;a href='http://www.weheartplaces.com/'&gt;weheartplaces&lt;/a&gt;, integrated with the Facebook Places api.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>We Heart Nokia</title>
   <link href="http://bnolan.github.com/2010/08/18/we-heart-nokia.html"/>
   <updated>2010-08-18T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/18/we-heart-nokia</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m excited to announce that weheartplaces will be available for Nokia Series 60 phones, as well as the iPhone and Android.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll be using the Nokia Webruntime (WRT 1.0), a browser-based environment that effectively allows you to create web/javascript programs that masquerade as normal symbian applications. I&amp;#8217;ve just been testing out the functionality of my &lt;a href='http://www.nokia.com.au/find-products/all-phones/nokia-6220-classic?cid=ncomprod-fw-src-na-con-nokia_6220-google-au-20-nokia6220_117'&gt;Nokia 6220&lt;/a&gt;, which is a $150 phone with 3G, GPS, driving directions and a 5 megapixel camera.&lt;/p&gt;
&lt;img src='/images/weheartnokia.jpg' /&gt;&lt;cite&gt;I got the icon going! That's like 80% of the work right there.&lt;/cite&gt;
&lt;p&gt;I&amp;#8217;m not sure of the release date yet - but when it&amp;#8217;s ready it&amp;#8217;ll be available at my &lt;a href='http://store.ovi.com/publisher/Nolan+Consulting/'&gt;publishers page&lt;/a&gt; on the Ovi store.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>To Market!</title>
   <link href="http://bnolan.github.com/2010/08/17/to-market.html"/>
   <updated>2010-08-17T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/17/to-market</id>
   <content type="html">&lt;p&gt;Are you in Wellington and are serious about starting a tech business? I got an email from the &lt;a href='http://www.brightideaschallenge.co.nz/'&gt;bright ideas challenge&lt;/a&gt; with information about the following presentations, from various technical and business development peoples. I&amp;#8217;ll be attending these three&amp;#8230;&lt;/p&gt;

&lt;h2 id='strategy'&gt;Strategy&lt;/h2&gt;

&lt;p&gt;Value proposition, business model, pricing model, finances and sustainability - Monday, 30 August 2010.&lt;/p&gt;

&lt;h2 id='technical'&gt;Technical&lt;/h2&gt;

&lt;p&gt;Intellectual property strategy, legal and governance, prototyping and funding options - Monday, 6 September 2010.&lt;/p&gt;

&lt;h2 id='gotomarket'&gt;Go-to-Market&lt;/h2&gt;

&lt;p&gt;Go-to-market strategy, branding, exporting and distribution - Wednesday, 8 September 2010.&lt;/p&gt;

&lt;p&gt;All events are held 4.30-6.30pm in the Memorial Theatre, Victoria University of Wellington. That marketing one sounds especially interesting.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Weird bug of the day</title>
   <link href="http://bnolan.github.com/2010/08/16/weird-bug-of-the-day.html"/>
   <updated>2010-08-16T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/16/weird-bug-of-the-day</id>
   <content type="html">&lt;p&gt;On Safari, it&amp;#8217;s nice to use ellipsis to limit the length of text. However, a warning to young players - &lt;code&gt;text-overflow: ellipsis&lt;/code&gt; doesn&amp;#8217;t work with webfonts.&lt;/p&gt;
&lt;img src='/images/overflow-1.png' /&gt;&lt;cite&gt;Correctly functioning ellipsis styling&lt;/cite&gt;&lt;img src='/images/overflow-2.png' /&gt;&lt;cite&gt;When using a webfont, Safari gives up, it's all too hard&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Hey what does this button do?</title>
   <link href="http://bnolan.github.com/2010/08/15/hey-what-does.html"/>
   <updated>2010-08-15T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/15/hey-what-does</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve used photoshop for years and consider myself an intermediate user. You end up using photoshop a lot in webdesign to slice stuff up, or create decent logos - and prior to CSS3 it was my number one gradients tool. However - there&amp;#8217;s a bunch of stuff photoshop doesn&amp;#8217;t do.&lt;/p&gt;

&lt;p&gt;With the advent of resolution-independent interfaces (retina display, next version of os x, landscape and portrait views of a site) and the need to create business cards, flyers, stickers and pixel art for websites - I&amp;#8217;ve been learning Adobe Illustrator.&lt;/p&gt;

&lt;p&gt;While playing with the &lt;a href='http://www.weheartplaces.com/'&gt;weheartplaces&lt;/a&gt; logo - I discovered this menu item:&lt;/p&gt;
&lt;img src='/images/logos/menu.png' /&gt;&lt;cite&gt;Hey - what does this effect do?&lt;/cite&gt;&lt;img src='/images/logos/cut6.png' /&gt;&lt;cite&gt;Houston. We have a logo.&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Logo Design</title>
   <link href="http://bnolan.github.com/2010/08/14/weheartplaces.html"/>
   <updated>2010-08-14T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/14/weheartplaces</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working on logos and design rules for &lt;a href='http://www.weheartplaces.com/'&gt;Weheartplaces&lt;/a&gt;, creating dozens of Artboards in illustrator. I&amp;#8217;m not a designer by trade, so some of my design is a bit stilted, but bear with me and eventually there might be a nice logo and style for the site.&lt;/p&gt;
&lt;img src='/images/logos/cut1.png' /&gt;&lt;cite&gt;Dax, probably too strong a shadow.&lt;/cite&gt;&lt;img src='/images/logos/cut2.png' /&gt;&lt;cite&gt;Eurostile, going cold on this one.&lt;/cite&gt;&lt;img src='/images/logos/cut3.png' /&gt;&lt;cite&gt;Oh, hai Steve.&lt;/cite&gt;&lt;img src='/images/logos/cut4.png' /&gt;&lt;cite&gt;The Scott Pilgrim special, plus Illustrator gradients.&lt;/cite&gt;&lt;img src='/images/logos/cut5.png' /&gt;&lt;cite&gt;For legal correspondence only.&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Push state and Node.js</title>
   <link href="http://bnolan.github.com/2010/08/13/pushstate-and-nodejs.html"/>
   <updated>2010-08-13T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/13/pushstate-and-nodejs</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve talked with &lt;a href='http://twitter.com/sminnee'&gt;Sam Minnee&lt;/a&gt; (CTO at &lt;a href='http://silverstripe.com/'&gt;Silverstripe&lt;/a&gt;) a bunch of times about running jquery on the server side. It was only a hunch, I never knew exactly what the benefits would be - but with the availability of &lt;a href='https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history'&gt;pushState&lt;/a&gt; on Firefox, Safari and Chrome - it suddenly makes a lot of sense.&lt;/p&gt;

&lt;p&gt;What pushState and jquery on the server lets you do - is to have a pure javascript application that doesnt require page reloads to go to different urls. For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;http://yourapp.com/&lt;/li&gt;

&lt;li&gt;http://yourapp.com/search&lt;/li&gt;

&lt;li&gt;http://yourapp.com/search/myterms&lt;/li&gt;

&lt;li&gt;http://yourapp.com/tweet/12345&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Can all be generated client side by your jquery and coffeescript code. This is an awesome way to write an app, you get a good responsive app and it&amp;#8217;s easy to persist state between pages (eg your google map won&amp;#8217;t spring back to the default location everytime you click &amp;#8216;back&amp;#8217;).&lt;/p&gt;

&lt;p&gt;The number one downfall of javascript apps, is that there are now pages in your app that can&amp;#8217;t be linked to - nor can they be crawled by google, or scraped by any other site that uses the http protocol. Building exciting new apps that &amp;#8216;break the internet&amp;#8217; isn&amp;#8217;t cool.&lt;/p&gt;

&lt;p&gt;But if you can run your entire app on the server side - then if someone goes to &lt;code&gt;http://yourapp.com/search/myterms&lt;/code&gt; - node.js can load your page on the server, recognize the url, run the correct javascript code to update the state as the browser would - then send it down the wire. So that non-javascript clients can access the same content that a desktop browser can.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a whole new way to do accessibility.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Facebook places</title>
   <link href="http://bnolan.github.com/2010/08/12/facebook-places.html"/>
   <updated>2010-08-12T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/12/facebook-places</id>
   <content type="html">&lt;p&gt;This &lt;a href='http://gigaom.com/2010/08/10/facebook-places-will-be-about-more-than-just-a-check-in/'&gt;analysis by Gigaom&lt;/a&gt; is interesting to me. I&amp;#8217;m really keen to see what Facebook does with places. What they&amp;#8217;ve done so far has been underwhelming technically, but has seen impressive takeup.&lt;/p&gt;

&lt;p&gt;For example - try searching for &lt;a href='http://apps.facebook.com/weheartplaces/places/935148524-hashigo_zake'&gt;Hashigo Zake&lt;/a&gt; (a Wellington beer bar popular with early adopters / geeks) on various services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://www.facebook.com/pages/Wellington-New-Zealand/Hashigo-Zake/144268315585'&gt;Facebook page&lt;/a&gt; - 413 people, 100s of posts&lt;/li&gt;

&lt;li&gt;&lt;a href='http://foursquare.com/venue/306746'&gt;Foursquare&lt;/a&gt; - 65 people, 3 tips&lt;/li&gt;

&lt;li&gt;&lt;a href='http://gowalla.com/spots/571126'&gt;Gowalla&lt;/a&gt; - 10 people, 4 comments&lt;/li&gt;

&lt;li&gt;&lt;a href='http://maps.google.com/maps/place?cid=11598129844502475571&amp;amp;q=hashigo+zake&amp;amp;hl=en&amp;amp;cd=1&amp;amp;ei=BSBiTLDxDYOEvgPfzKSqDg&amp;amp;sig2=RxTDHaj8pywo70MGfMzcSg&amp;amp;dtab=2&amp;amp;pcsi=11598129844502475571,1&amp;amp;geocode=FX7wif0douxqCg&amp;amp;sll=-41.291693,174.779499&amp;amp;sspn=0.004184,0.003358&amp;amp;ie=UTF8&amp;amp;ll=-41.289126,174.777267&amp;amp;spn=0,0&amp;amp;z=17&amp;amp;iwloc=A'&gt;Google places&lt;/a&gt; - 5 maps - 2 reviews&lt;/li&gt;

&lt;li&gt;&lt;a href='http://search.twitter.com/search?q=hashigo+zake'&gt;Twitter&lt;/a&gt; - 4 tweets in the past week&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Facebook has such massive uptake, that whatever it does has an impact. The understanding, technology and devices behind &amp;#8216;location based&amp;#8217; services are so widespread that it&amp;#8217;s really a case of Facebook just providing the tools and they&amp;#8217;ll probably dominate existing location based services.&lt;/p&gt;

&lt;p&gt;Also - note that all of the sites have reasonably terse (or even descriptive) URLs. All except Google. They really don&amp;#8217;t get clean URLs.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Make LESS less painful</title>
   <link href="http://bnolan.github.com/2010/08/11/less-painful.html"/>
   <updated>2010-08-11T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/11/less-painful</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been using &lt;a href='http://lesscss.org/'&gt;LESS&lt;/a&gt; to make writing css for a &lt;a href='http://jqtouch.com/'&gt;jqtouch&lt;/a&gt; app less painful. However - the less compiler is a bit awkward to use by default - if you run:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;lessc -g -w *.less&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It recompiles your scripts everytime you make a change, which is perfect, and it notifies you by growl if you have a syntax error - wonderful.&lt;/p&gt;

&lt;p&gt;However - every time you get a syntax error, it also blocks the terminal that you launched less from, and you have to go to that terminal and &amp;#8216;Press [return] to continue&amp;#8230;&amp;#8217;. It&amp;#8217;s pretty annoying. The solution is to load up &lt;code&gt;/Library/Ruby/Gems/1.8/gems/less-1.2.21/&lt;/code&gt; in your text editor, search for command.rb, and change the &lt;code&gt;run!&lt;/code&gt; method, to disable the &lt;code&gt;$stdin.gets&lt;/code&gt; and replace it as so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# File has changed
if (not File.exists?( @destination )) or File.stat( @source ).mtime &amp;gt; File.stat( @destination ).mtime
  print Time.now.strftime(&amp;quot;%H:%M:%S -- &amp;quot;) if @options[:timestamps]
  print &amp;quot;Change detected... &amp;quot;

  if parse
    # ...
  else 
    `touch #{@destination}`
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I also set the growl.priority to 1 in &lt;code&gt;err(...)&lt;/code&gt; to make my notifications show up in red.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;growl.priority = 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You then get growl notifications on error, but simply correct the error and hit save again to recompile. No more hunting to find the right terminal.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>CoffeeScript 0.9</title>
   <link href="http://bnolan.github.com/2010/08/09/coffeescript-0.9.html"/>
   <updated>2010-08-09T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/09/coffeescript-0.9</id>
   <content type="html">&lt;p&gt;&lt;a href='http://jashkenas.github.com/coffee-script/'&gt;CoffeeScript 0.9&lt;/a&gt; was released over the weekend. CoffeeScript is a compiler that turns .coffee files into .js files. CoffeeScript is a significant whitespace, rubyish language that makes large (and small) javascript projects much more manageable and fun.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been using CoffeeScript since 0.5, first with a multiplayer javascript game experiment, then more recently as part of my consulting with &lt;a href='http://lplabs.com/'&gt;Lonely Planet Labs&lt;/a&gt;. It&amp;#8217;s been interesting working with multiple developers on CoffeeScript - and seeing how it works in a production environment. I can heartily recommend it to teams that are looking to ease their javascript development.&lt;/p&gt;

&lt;p&gt;CS 0.9 is a big change from 0.7.2, read &lt;a href='http://github.com/jashkenas/coffee-script/issues/closed#issue/541'&gt;this ticket&lt;/a&gt; for some of the background on the change. My own reaction to the change is interesting - I was against the change at first, and only changed my mind after 0.9 was released. I was impressed by how &lt;a href='http://github.com/jashkenas/'&gt;Jeremy&lt;/a&gt; got opininions and analysis from all the existing users, then quickly made such a fundamental change to the language, let people try it out in a branch - and finally decided to merge it back into stable.&lt;/p&gt;

&lt;p&gt;All this - despite the fact that upgrading most coffeescript apps to 0.9 is non-trivial. Changing the symbol used for assignment will probably break most existing code. The assignment change was required to bring in yamlish object assignment which is awesome. The new release also has a host of other, non contentious improvements, around superclasses.&lt;/p&gt;

&lt;p&gt;I think it&amp;#8217;s a good reminder, that no matter how substantial a change - if you manage is right, and the benefits outweigh the costs, your community will adapt and embrace the new version.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Safari Extension</title>
   <link href="http://bnolan.github.com/2010/08/08/safari-extension.html"/>
   <updated>2010-08-08T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/08/safari-extension</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working through the extension authoring documentation for each of the browsers. I was excited when I got my little icon showing up in the Safari toolbar for the first time:&lt;/p&gt;
&lt;img src='/images/safari-preview.png' /&gt;&lt;cite&gt;Weheartplaces toolbar button&lt;/cite&gt;</content>
 </entry>
 
 <entry>
   <title>Design features</title>
   <link href="http://bnolan.github.com/2010/08/05/design.html"/>
   <updated>2010-08-05T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/05/design</id>
   <content type="html">&lt;p&gt;While redesigning this blog (I love being able to edit css and template as easily as blog posts, &lt;a href='http://pages.github.com/'&gt;go github pages&lt;/a&gt;!), I found myself turning this:&lt;/p&gt;
&lt;img src='/images/design-staccato.png' /&gt;&lt;cite&gt;Ordered chronologically&lt;/cite&gt;
&lt;p&gt;Into this:&lt;/p&gt;
&lt;img src='/images/design-wave.png' /&gt;&lt;cite&gt;Ordered by aesthetic&lt;/cite&gt;
&lt;p&gt;I find the wave a lot more pleasing to the eye, and I still kept the primary order mostly intact. This is one of my design tenets - lay out the page by weight and balance, then work out what text you can fit into each of the boxes.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s almost the opposite of how &lt;a href='http://37signals.com/papers/introtopatterns//index'&gt;the signals&lt;/a&gt; do design, but I love it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Brewdog Punk IPA</title>
   <link href="http://bnolan.github.com/2010/08/04/brewdog.html"/>
   <updated>2010-08-04T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/08/04/brewdog</id>
   <content type="html">&lt;p&gt;I just discovered the awe inspiring &lt;a href='http://apps.facebook.com/weheartplaces/cities/1004679663-wellington/places/935148610-flagstaff_cellars'&gt;flagstaff cellars&lt;/a&gt;, which is a tucked away little beershop in an unassuming corner of Melbourne.&lt;/p&gt;

&lt;p&gt;The thing about this place though, is that is a stocker of Brewdog, Rogue, Epic and a number of good Australian beers - such as Matilda Alpha, Little Creatures and Moo Brew.&lt;/p&gt;

&lt;p&gt;Anyway - they had this beer on special - &lt;a href='http://www.brewdog.com/punk_ipa.php'&gt;Punk IPA&lt;/a&gt; by &lt;a href='http://www.brewdog.com/'&gt;Brewdog&lt;/a&gt;, so I bought two and came home and tried them.&lt;/p&gt;
&lt;img src='/images/brewdogpunk.jpg' /&gt;&lt;cite&gt;A very good beer.&lt;/cite&gt;
&lt;p&gt;The internet website &lt;a href='http://www.ratebeer.com/beer/brewdog-punk-ipa/72423/'&gt;rate beer&lt;/a&gt; said good things about the Punk IPA, although the haters at &lt;a href='http://beeradvocate.com/beer/profile/16315/39435'&gt;beer advocate&lt;/a&gt; weren&amp;#8217;t so enamoured. The guy who drunk a Punk IPA that was 12 months past it&amp;#8217;s best date - in particular - has a bad time with the beer.&lt;/p&gt;

&lt;h1 id='my_review_of_punk_ipa'&gt;My review of Punk IPA&lt;/h1&gt;

&lt;p&gt;This beer is awesome. It cost $5. I will drink it again. Probably in a few minutes when I get the other one out of the fridge. &lt;b&gt;5 stars.&lt;/b&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Cities in the world..</title>
   <link href="http://bnolan.github.com/2010/07/29/number-of-cities-in-the-world.html"/>
   <updated>2010-07-29T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/07/29/number-of-cities-in-the-world</id>
   <content type="html">&lt;p&gt;When you&amp;#8217;re building an application for travellers, you come up against the problem of how do you get enough data in the system so that it&amp;#8217;s useful for 455 cities with a population of more than one million people, 1054 with more than 500,000 and 2851 with more than 150,000 people.&lt;/p&gt;

&lt;p&gt;Or to look at the problem a different way - the most visited cities in the world&amp;#8230;&lt;/p&gt;

&lt;h1 id='most_visited_cities'&gt;Most visited cities&lt;/h1&gt;

&lt;p&gt;This &lt;a href='http://en.wikipedia.org/wiki/Tourism#Most_visited_cities'&gt;table&lt;/a&gt; at Wikipedia shows the top &lt;b&gt;10 most visited&lt;/b&gt; cities to be &lt;i&gt;Paris, London, Bangkok, Singapore, Kuala Lumpur, New York City, Dubai, Istanbul, Hong Kong, Shanghai&lt;/i&gt;.&lt;/p&gt;

&lt;h1 id='crawling_data_for_these_cities'&gt;Crawling data for these cities&lt;/h1&gt;

&lt;p&gt;I&amp;#8217;m not sure what the take away from this data is. Seeding 2851 cities with data seems very doable in a week of crawling, seeding the top 10 visited cities with deep data is also achievable - it&amp;#8217;d be interesting to compare the list of top 2851 cities with the hometowns of the users of &lt;a href='http://www.weheartplaces.com/'&gt;weheartplaces&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id='the_real_take_away'&gt;The real take away&lt;/h1&gt;

&lt;p&gt;Is that it&amp;#8217;s better to encourage users to add content to &amp;#8216;empty&amp;#8217; cities, than to expect to have every city to have a persuasive dataset when you launch your travel site.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Haversine in Coffeescript</title>
   <link href="http://bnolan.github.com/2010/07/28/haversine-in-coffeescript.html"/>
   <updated>2010-07-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/07/28/haversine-in-coffeescript</id>
   <content type="html">&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Haversine_formula'&gt;Haversine formula&lt;/a&gt; is a equation that can be used to calculate the straight line distance between two coordinates on a sphere. It is commonly used by geohackers to work out how far in &lt;em&gt;kilometres&lt;/em&gt; it is between two latitude/latitude coordinates.&lt;/p&gt;

&lt;p&gt;Remember that lat/longs are actually spherical coordinates expressed in degrees.&lt;/p&gt;

&lt;p&gt;This &lt;a href='http://kapelica.hr/kw/latlong.html'&gt;page&lt;/a&gt; at kapelica.hr contained a great implementation of the haversine formula in javascript, I tidied it up and ported it to coffeescript to measure distances to the nearest places in my iphone app.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Radians: (degrees) -&amp;gt;
  degrees /  57.2957795

Haversine: (lat1, lon1, lat2, lon2) -&amp;gt;
  R = 6371 # km
  dLat: Radians(lat2-lat1)
  dLon: Radians(lon2-lon1)
  a: Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(Radians(lat1)) * Math.cos(Radians(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2)
  c: 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
  R * c&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the degrees-&amp;gt;radians conversion isn&amp;#8217;t exact, but the results should be within the margin of error for most GPS positioning systems.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Displaying only the first paragraph</title>
   <link href="http://bnolan.github.com/2010/07/28/display-only-the-first-paragraph.html"/>
   <updated>2010-07-28T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/07/28/display-only-the-first-paragraph</id>
   <content type="html">&lt;p&gt;In redesigning my blog and publishing it on github pages, I wanted a simple way to show only the first paragraph of each post on the front page. The way I did it isn&amp;#8217;t something I&amp;#8217;m proud of - but it does show the power of css.&lt;/p&gt;

&lt;p&gt;The following rule hides everything apart from the first child of a div.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;div &amp;gt; * + *{
  display: none;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It works on safari, firefox and will work on ie9.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Offline manifests</title>
   <link href="http://bnolan.github.com/2010/07/23/offline-manifests.html"/>
   <updated>2010-07-23T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/07/23/offline-manifests</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been working on an html5 app for Lonely Planet, and part of the task is to make the app work offline on the iPhone. Getting it to work isn&amp;#8217;t too hard - you need to create a &lt;a href='http://diveintohtml5.org/offline.html'&gt;cache.manifest&lt;/a&gt; file and make sure it is served with the correct mime type.&lt;/p&gt;

&lt;h2 id='the_problem_is_online'&gt;The problem is online&lt;/h2&gt;

&lt;p&gt;When you have the phone offline and load the app, it loads in 2 seconds. When you turn the phone online again, it takes about 30 seconds to load all the javascript and so on.&lt;/p&gt;

&lt;h2 id='its_the_caching_rules'&gt;It&amp;#8217;s the caching rules&lt;/h2&gt;

&lt;p&gt;We have been deploying to google app engine, and by default - app engine sets all files to expire after 10 minutes. So even though the iphone has a local copy of the files, every 10 minutes, it&amp;#8217;ll expire the local cache and redownload everything that the manifest refers too.&lt;/p&gt;

&lt;h2 id='a_checklist_for_fast_online_iphone_apps'&gt;A checklist for fast online iphone apps&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Use a manifest&lt;/li&gt;

&lt;li&gt;Ensure the manifest is served with the mimetype text/cache-manifest&lt;/li&gt;

&lt;li&gt;Ensure the manifest has no 404 errors in it&lt;/li&gt;

&lt;li&gt;Ensure the manifest and all the content in it has an expiry date in the distant future&lt;/li&gt;

&lt;li&gt;White-list your network resources explicitly in the manifest&lt;/li&gt;

&lt;li&gt;Use jqt.offline.js to help debug the browser behaviour&lt;/li&gt;

&lt;li&gt;Tail your webserver logs and keep an eagle eye for unnecessary requests&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All going well, your html5 app will load instantly, and still be able to access network resources.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Coffeescript</title>
   <link href="http://bnolan.github.com/2010/07/05/coffeescript.html"/>
   <updated>2010-07-05T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/07/05/coffeescript</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been doing a lot of coffeescript lately and can recommend it wholeheartedly.&lt;/p&gt;

&lt;p&gt;That is all.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Skating in Melbourne</title>
   <link href="http://bnolan.github.com/2010/06/20/skating-melbourne.html"/>
   <updated>2010-06-20T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/06/20/skating-melbourne</id>
   <content type="html">&lt;p&gt;I just went on a big skate of melbourne CBD.&lt;/p&gt;

&lt;p&gt;I started at home (nähe Southern Cross Station), then skated out to Prudence in West Melbourne. Prudence is a highly recommended bar. The beer is expensive, but the cocktails apparently are affordable. From Souther Cross to Prudence is mostly uphill, which meant that after a few beers, a few conversations and a good laugh - it was all downhill to Section 8.&lt;/p&gt;

&lt;p&gt;Section 8 is a very cool bar. During the day. I went there in the evening and wasn&amp;#8217;t so impressed. The skate was good though - it&amp;#8217;s mostly downhill from Prudence along Victoria Street - then turn right, drop down into town (it&amp;#8217;s a pretty steep skate through traffic down to little collins street) - and a hard left into Section 8.&lt;/p&gt;

&lt;p&gt;S8 only had one beer I wanted - and it was in what australians call a &amp;#8220;tallie&amp;#8221; (800ml beer). I took a few drinks - decided S8 wasn&amp;#8217;t for me, then stashed the beer in my back pocket and headed through town. There were people everywhere (and you can&amp;#8217;t drink in public anywhere in Australia) so it took 5/10 minutes before I got out of the city (skating past the Melbourne Cricket Ground by now) and could drink the rest of my beer. It was a lovely long skate past the MCG - down a shallow smooth slope on a path surrounded in trees and grass. Had some good tunes on - nice times.&lt;/p&gt;

&lt;p&gt;Then I bombed from the MCG down to Richmond - eyeballed out the gig I was going to go see at the corner bar, decided it wasn&amp;#8217;t worth $50 to go see - then caught a tram back to Southern Cross and mellowed along Spencer street to home.&lt;/p&gt;

&lt;p&gt;Melbourne. Good for skating.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Merging identities</title>
   <link href="http://bnolan.github.com/2010/05/24/merging-identities.html"/>
   <updated>2010-05-24T00:00:00-07:00</updated>
   <id>http://bnolan.github.com/2010/05/24/merging-identities</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve set this blog up on Github pages using Jekyll. My old posts may find their way here&amp;#8230;.&lt;/p&gt;</content>
 </entry>
 
 
</feed>
