<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>paul.annesley.cc</title>
  <link href="http://paul.annesley.cc/atom.xml" rel="self"/>
  <link href="http://paul.annesley.cc/"/>
  <updated>2012-03-29T12:01:21+11:00</updated>
  <id>http://paul.annesley.cc/</id>
  <author>
    <name>Paul Annesley</name>
    
  </author>

  
  <entry>
    <title>Simple Dependency Injection and MiniTest::Mock</title>
    <link href="http://paul.annesley.cc/2012/03/simple-dependency-injection-and-minitest-mock/"/>
    <updated>2012-03-28T19:53:00+11:00</updated>
    <id>http://paul.annesley.cc/2012/03/simple-dependency-injection-and-minitest-mock</id>
    <content type="html">&lt;p&gt;I recently wrote a &lt;a href=&quot;https://github.com/flippa/ralexa&quot;&gt;Ruby client for Amazon Alexa&amp;#8217;s APIs&lt;/a&gt;, and thought I&amp;#8217;d
pull out an example of nice, simple dependency injection to facilitate unit
testing. Nothing revolutionary or complicated, just good practice.&lt;/p&gt;

&lt;p&gt;The example is based around a &lt;code&gt;UriSigner&lt;/code&gt; class, normally used by the calling
code like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;UriSigner.new(*credentials).sign_uri(uri)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The calling code doesn&amp;#8217;t know or care that &lt;code&gt;UriSigner&lt;/code&gt; depends on &lt;a href=&quot;http://ruby-doc.org/stdlib-1.9.3/libdoc/base64/rdoc/Base64.html&quot;&gt;Base64&lt;/a&gt;,
&lt;a href=&quot;http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Digest.html&quot;&gt;OpenSSL::Digest::SHA256&lt;/a&gt; and &lt;a href=&quot;http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/HMAC.html&quot;&gt;OpenSSL::HMAC&lt;/a&gt;. The unit test for
&lt;code&gt;UriSigner&lt;/code&gt;, however, cares for two reasons.&lt;/p&gt;

&lt;p&gt;Firstly, they&amp;#8217;re external dependencies, and only need to be tested for correct
usage, not correct implementation.&lt;/p&gt;

&lt;p&gt;Secondly, these dependencies represent an encoder and a cryptographic hash
function; they&amp;#8217;re deterministic, but they return very opaque data which can
make tests and their failure messages difficult to understand.&lt;/p&gt;

&lt;p&gt;So instead of testing against magical (computed in advance) Base64 strings and
HMAC hashes, I&amp;#8217;ve used simple &lt;code&gt;attr_writer&lt;/code&gt; dependency injectors:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2224862.js?file=uri_signer.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require &amp;quot;base64&amp;quot;
require &amp;quot;digest/sha2&amp;quot;
require &amp;quot;openssl&amp;quot;

module Ralexa
  class UriSigner

    # Hacked to simplify example. Full version at:
    # https://github.com/flippa/ralexa/blob/master/lib/ralexa/uri_signer.rb

    def initialize(*credentials)
      # &#8230;
    end

    # dependency injectors
    attr_writer :digest
    attr_writer :hmac_signer
    attr_writer :base64_encoder
    attr_writer :time_utc

    def sign_uri(original_uri)
      # there&#8217;s more to it than this, but to illustrate dependency injection:
      original_uri.dup.tap do |uri|
        uri.query_values = uri.query_values.merge(
          &amp;quot;Timestamp&amp;quot; =&amp;gt; time_utc.strftime(&amp;quot;%Y-%m-%dT%H:%M:%S.000Z&amp;quot;),
          &amp;quot;Signature&amp;quot; =&amp;gt; base64_encoder.encode64(hmac_signer.digest(digest, @key, uri.to_s))
        )
      end
    end

    private

    ##
    # Injectable dependencies.

    def digest
      @digest ||= OpenSSL::Digest::SHA256.new
    end

    def hmac_signer
      @hmac_signer || OpenSSL::HMAC
    end

    def base64_encoder
      @base64_encoder || Base64
    end

    def time_utc
      @time_utc || Time.now.utc
    end

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


&lt;p&gt;The unit test can then inject &lt;a href=&quot;http://ruby-doc.org/stdlib-1.9.3/libdoc/minitest/mock/rdoc/MiniTest/Mock.html&quot;&gt;MiniTest::Mock&lt;/a&gt; instances in place of the
real Base64 and HMAC implementations, setting expected method calls and their
return values:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2224862.js?file=uri_signer_spec.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require_relative &amp;quot;spec_helper&amp;quot;

require &amp;quot;addressable/uri&amp;quot;

module Ralexa
  describe UriSigner do

    # Hacked to simplify example. Full version at:
    # https://github.com/flippa/ralexa/blob/master/spec/uri_signer_spec.rb

    # UriSigner with dependencies injected.
    def signer
      UriSigner.new(&amp;quot;id&amp;quot;, &amp;quot;secret&amp;quot;).tap do |rs|
        rs.digest = digest
        rs.hmac_signer = hmac_signer
        rs.base64_encoder = base64_encoder
        rs.time_utc = time_utc
      end
    end

    # Mocked dependencies.
    let(:digest) { MiniTest::Mock.new }
    let(:hmac_signer) { MiniTest::Mock.new }
    let(:base64_encoder) { MiniTest::Mock.new }
    let(:time_utc) { Time.now.utc }

    # Mock expectations and return values.
    before do
      hmac_signer.expect :digest, &amp;quot;the_hmac&amp;quot;, [ digest, &amp;quot;secret&amp;quot;, String ]
      base64_encoder.expect :encode64, &amp;quot;base64_encoded\n&amp;quot;, [ &amp;quot;the_hmac&amp;quot; ]
    end

    describe &amp;quot;for http://example.org/path?a=b&amp;quot; do
      it &amp;quot;returns a signed URL&amp;quot; do
        original_uri = Addressable::URI.parse(&amp;quot;http://example.org/path?a=b&amp;quot;)
        signer.signed_uri(original_uri).query_values.must_equal(
          &amp;quot;a&amp;quot; =&amp;gt; &amp;quot;b&amp;quot;,
          &amp;quot;Signature&amp;quot; =&amp;gt; &amp;quot;base64_encoded&amp;quot;,
          &amp;quot;Timestamp&amp;quot; =&amp;gt; time_utc.strftime(&amp;quot;%Y-%m-%dT%H:%M:%S.000Z&amp;quot;),
        )
      end
    end

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


&lt;p&gt;As simple as that.&lt;/p&gt;

&lt;p&gt;The same approach is used by the HTTP Client class to stub out actual HTTP
calls via Net::HTTP. There&amp;#8217;s great libraries like &lt;a href=&quot;https://github.com/myronmarston/vcr&quot;&gt;VCR&lt;/a&gt;, &lt;a href=&quot;https://github.com/bblimke/webmock&quot;&gt;WebMock&lt;/a&gt; and
&lt;a href=&quot;https://github.com/chrisk/fakeweb&quot;&gt;FakeWeb&lt;/a&gt; for handling this, but sometimes it&amp;#8217;s easier to keep it lo-fi:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2224862.js?file=client.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head prefix=&amp;quot;og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog: http://ogp.me/ns/fb/githubog#&amp;quot;&amp;gt;
    &amp;lt;meta charset=&#8217;utf-8&#8217;&amp;gt;
    &amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot;&amp;gt;
        &amp;lt;title&amp;gt;404 · GitHub&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;search&amp;quot; type=&amp;quot;application/opensearchdescription+xml&amp;quot; href=&amp;quot;/opensearch.xml&amp;quot; title=&amp;quot;GitHub&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;fluid-icon&amp;quot; href=&amp;quot;https://github.com/fluidicon.png&amp;quot; title=&amp;quot;GitHub&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;/favicon.ico&amp;quot; type=&amp;quot;image/x-icon&amp;quot; /&amp;gt;

    
    

    

    &amp;lt;link href=&amp;quot;https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github-e2fb92c4dcb5e5b1ce2ffd0e84d6bf80937d9197.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
    &amp;lt;link href=&amp;quot;https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github2-a6e03f3438e57a85fea8f7cc4939ed556a5c96e4.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
    

    &amp;lt;script src=&amp;quot;https://a248.e.akamai.net/assets.github.com/javascripts/bundles/jquery-225576cef50ef2097c9f9fbcd8953c1572544611.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&amp;quot;https://a248.e.akamai.net/assets.github.com/javascripts/bundles/github-353ded132c604f1bdf010516392d71052f37ffcf.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    

    
  &amp;lt;/head&amp;gt;


  &amp;lt;body class=&amp;quot;logged_out    env-production &amp;quot; data-blob-contribs-enabled=&amp;quot;yes&amp;quot;&amp;gt;
    &amp;lt;div id=&amp;quot;wrapper&amp;quot;&amp;gt;

    
    
    

      &amp;lt;div id=&amp;quot;header&amp;quot; class=&amp;quot;true clearfix&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;
          &amp;lt;a class=&amp;quot;site-logo&amp;quot; href=&amp;quot;https://github.com&amp;quot;&amp;gt;
            &amp;lt;!&#8211;[if IE]&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7.png?1323882778&amp;quot; /&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-hover&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7-hover.png?1324325424&amp;quot; /&amp;gt;
            &amp;lt;![endif]&#8211;&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-4x&amp;quot; height=&amp;quot;30&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x.png?1323882778&amp;quot; /&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-4x-hover&amp;quot; height=&amp;quot;30&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x-hover.png?1324325424&amp;quot; /&amp;gt;
          &amp;lt;/a&amp;gt;

                  &amp;lt;!&#8211;
      make sure to use fully qualified URLs here since this nav
      is used on error pages on other domains
    &#8211;&amp;gt;
    &amp;lt;ul class=&amp;quot;top-nav logged_out&amp;quot;&amp;gt;
        &amp;lt;li class=&amp;quot;pricing&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/plans&amp;quot;&amp;gt;Signup and Pricing&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&amp;quot;explore&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/explore&amp;quot;&amp;gt;Explore GitHub&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;features&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/features&amp;quot;&amp;gt;Features&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&amp;quot;blog&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/blog&amp;quot;&amp;gt;Blog&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;login&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/login?return_to=%2Fgist%2F2224862%2Fclient.rb&amp;quot;&amp;gt;Login&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;



          
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

      

        &amp;lt;div class=&amp;quot;site clearfix&amp;quot;&amp;gt;
          &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
            

&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
    #header{
        border-bottom: 0;
    }
    .site{
        padding: 0;
        margin-top: -20px;
    }
    * {
        margin: 0px;
        padding: 0px;
    }
    #parallax_field{
        overflow: hidden;
        position: absolute;
        left: 0;
        top: 0;
        height: 370px;
        width: 100%;
    }
    #parallax_field #parallax_bg {
        position: absolute;
        top: -20px;
        left: -20px;
        width: 110%;
        height: 425px;
        z-index: 1;
    }
    #parallax_illustration {
        display:block;
        width: 940px;
        height: 370px;
        position: relative;
        overflow: hidden;
        clear: both;
    }
    #parallax_illustration #parallax_error_text {
        position: absolute;
        top: 72px;
        left: 72px;
        z-index: 10;
    }
    #parallax_illustration #parallax_octocat {
        position: absolute;
        top: 94px;
        left: 356px;
        z-index: 9;
    }
    #parallax_illustration #parallax_speeder {
        position: absolute;
        top: 150px;
        left: 432px;
        z-index: 8;
    }
    #parallax_illustration #parallax_octocatshadow {
        position: absolute;
        top: 297px;
        left: 371px;
        z-index: 7;
    }
    #parallax_illustration #parallax_speedershadow {
        position: absolute;
        top: 263px;
        left: 442px;
        z-index: 6;
    }
    #parallax_illustration #parallax_building_1 {
        position: absolute;
        top: 73px;
        left: 467px;
        z-index: 5;
    }
    #parallax_illustration #parallax_building_2 {
        position: absolute;
        top: 113px;
        left: 762px;
        z-index: 4;
    }
    #footer {
        margin-top: 0px;
        z-index: 12;
    }
&amp;lt;/style&amp;gt;


&amp;lt;div id=&amp;quot;parallax_field&amp;quot;&amp;gt;
    &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;0&amp;quot; data-yrange=&amp;quot;20&amp;quot; height=&amp;quot;415&amp;quot; id=&amp;quot;parallax_bg&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_bg.jpg?1293753715&amp;quot; width=&amp;quot;940&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;parallax_illustration&amp;quot;&amp;gt;
  &amp;lt;img alt=&amp;quot;404 | &amp;amp;ldquo;This is not the web page you are looking for&amp;amp;rdquo;&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;20&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;249&amp;quot; id=&amp;quot;parallax_error_text&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_errortext.png?1293753715&amp;quot; width=&amp;quot;271&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;Octobi Wan Catnobi&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;230&amp;quot; id=&amp;quot;parallax_octocat&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_octocat.png?1293753715&amp;quot; width=&amp;quot;188&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;land speeder&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;156&amp;quot; id=&amp;quot;parallax_speeder&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_speeder.png?1293753715&amp;quot; width=&amp;quot;440&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;Octobi Wan Catnobi&#8217;s shadow&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;49&amp;quot; id=&amp;quot;parallax_octocatshadow&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_octocatshadow.png?1293753715&amp;quot; width=&amp;quot;166&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;land speeder&#8217;s shadow&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;75&amp;quot; id=&amp;quot;parallax_speedershadow&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_speedershadow.png?1293753715&amp;quot; width=&amp;quot;430&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;50&amp;quot; data-yrange=&amp;quot;20&amp;quot; height=&amp;quot;123&amp;quot; id=&amp;quot;parallax_building_1&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_building_1.png?1293753715&amp;quot; width=&amp;quot;304&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;75&amp;quot; data-yrange=&amp;quot;30&amp;quot; height=&amp;quot;50&amp;quot; id=&amp;quot;parallax_building_2&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_building_2.png?1293753715&amp;quot; width=&amp;quot;116&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;

          &amp;lt;/div&amp;gt;
          &amp;lt;div class=&amp;quot;context-overlay&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;div id=&amp;quot;footer-push&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;!&#8211; hack for sticky footer &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; end of wrapper - hack for sticky footer &#8211;&amp;gt;

      &amp;lt;!&#8211; footer &#8211;&amp;gt;
      &amp;lt;div id=&amp;quot;footer&amp;quot; &amp;gt;
        
  &amp;lt;div class=&amp;quot;upper_footer&amp;quot;&amp;gt;
     &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;

       &amp;lt;!&#8211;[if IE]&amp;gt;&amp;lt;h4 id=&amp;quot;blacktocat_ie&amp;quot;&amp;gt;GitHub Links&amp;lt;/h4&amp;gt;&amp;lt;![endif]&#8211;&amp;gt;
       &amp;lt;![if !IE]&amp;gt;&amp;lt;h4 id=&amp;quot;blacktocat&amp;quot;&amp;gt;GitHub Links&amp;lt;/h4&amp;gt;&amp;lt;![endif]&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;GitHub&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/about&amp;quot;&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/blog&amp;quot;&amp;gt;Blog&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/features&amp;quot;&amp;gt;Features&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/contact&amp;quot;&amp;gt;Contact &amp;amp;amp; Support&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/training&amp;quot;&amp;gt;Training&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://enterprise.github.com/&amp;quot;&amp;gt;GitHub Enterprise&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://status.github.com/&amp;quot;&amp;gt;Site Status&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Tools&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://get.gaug.es/&amp;quot;&amp;gt;Gauges: Analyze web traffic&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://speakerdeck.com&amp;quot;&amp;gt;Speaker Deck: Presentations&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://gist.github.com&amp;quot;&amp;gt;Gist: Code snippets&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://mac.github.com/&amp;quot;&amp;gt;GitHub for Mac&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://mobile.github.com/&amp;quot;&amp;gt;Issues for iPhone&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://jobs.github.com/&amp;quot;&amp;gt;Job Board&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Extras&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://shop.github.com/&amp;quot;&amp;gt;GitHub Shop&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://octodex.github.com/&amp;quot;&amp;gt;The Octodex&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Documentation&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://help.github.com/&amp;quot;&amp;gt;GitHub Help&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://developer.github.com/&amp;quot;&amp;gt;Developer API&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://github.github.com/github-flavored-markdown/&amp;quot;&amp;gt;GitHub Flavored Markdown&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://pages.github.com/&amp;quot;&amp;gt;GitHub Pages&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

     &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.site &#8211;&amp;gt;
  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.upper_footer &#8211;&amp;gt;

&amp;lt;div class=&amp;quot;lower_footer&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;
    &amp;lt;!&#8211;[if IE]&amp;gt;&amp;lt;div id=&amp;quot;legal_ie&amp;quot;&amp;gt;&amp;lt;![endif]&#8211;&amp;gt;
    &amp;lt;![if !IE]&amp;gt;&amp;lt;div id=&amp;quot;legal&amp;quot;&amp;gt;&amp;lt;![endif]&amp;gt;
      &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/site/terms&amp;quot;&amp;gt;Terms of Service&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/site/privacy&amp;quot;&amp;gt;Privacy&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/security&amp;quot;&amp;gt;Security&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;p&amp;gt;&amp;amp;copy; 2012 &amp;lt;span title=&amp;quot;0.02171s from fe6.rs.github.com&amp;quot;&amp;gt;GitHub&amp;lt;/span&amp;gt; Inc. All rights reserved.&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /#legal or /#legal_ie&#8211;&amp;gt;

      &amp;lt;div class=&amp;quot;sponsor&amp;quot;&amp;gt;
        &amp;lt;a href=&amp;quot;http://www.rackspace.com&amp;quot; class=&amp;quot;logo&amp;quot;&amp;gt;
          &amp;lt;img alt=&amp;quot;Dedicated Server&amp;quot; height=&amp;quot;36&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/footer/rackspaces_logo.png?1329521041&amp;quot; width=&amp;quot;38&amp;quot; /&amp;gt;
        &amp;lt;/a&amp;gt;
        Powered by the &amp;lt;a href=&amp;quot;http://www.rackspace.com &amp;quot;&amp;gt;Dedicated
        Servers&amp;lt;/a&amp;gt; and&amp;lt;br/&amp;gt; &amp;lt;a href=&amp;quot;http://www.rackspacecloud.com&amp;quot;&amp;gt;Cloud
        Computing&amp;lt;/a&amp;gt; of Rackspace Hosting&amp;lt;span&amp;gt;&amp;amp;reg;&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.site &#8211;&amp;gt;
&amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.lower_footer &#8211;&amp;gt;

      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /#footer &#8211;&amp;gt;

    

&amp;lt;div id=&amp;quot;keyboard_shortcuts_pane&amp;quot; class=&amp;quot;instapaper_ignore readability-extra&amp;quot; style=&amp;quot;display:none&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Keyboard Shortcuts &amp;lt;small&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;js-see-all-keyboard-shortcuts&amp;quot;&amp;gt;(see all)&amp;lt;/a&amp;gt;&amp;lt;/small&amp;gt;&amp;lt;/h2&amp;gt;

  &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Site wide shortcuts&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;s&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Focus site search&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;?&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Bring up this help dialog&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;

    &amp;lt;div class=&amp;quot;column middle&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
      &amp;lt;h3&amp;gt;Commit list&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;c &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Open commit&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Expand URL to its canonical form&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;

    &amp;lt;div class=&amp;quot;column last&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
      &amp;lt;h3&amp;gt;Pull request list&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.columns.last &#8211;&amp;gt;

  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.columns.equacols &#8211;&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Issues&amp;lt;/h3&amp;gt;

    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;x&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Toggle selection&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column middle&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;I&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Mark selection as read&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;U&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Mark selection as unread&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Remove selection from view&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.middle &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column last&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;c&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Create issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Create label&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;i&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Back to inbox&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;u&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Back to issues&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;/&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Focus issues search&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Issues Dashboard&amp;lt;/h3&amp;gt;

    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Network Graph&amp;lt;/h3&amp;gt;
    &amp;lt;div class=&amp;quot;columns equacols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;←&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; h&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll left&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;→&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll right&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↑&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↓&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;t&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Toggle visibility of head labels&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column last&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;←&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift h&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way left&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;→&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way right&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↑&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↓&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.last &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
        &amp;lt;h3&amp;gt;Source Code Browsing&amp;lt;/h3&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;t&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Activates the file finder&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Jump to line&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;w&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Switch branch/tag&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Expand URL to its canonical form&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

    &amp;lt;div id=&amp;quot;markdown-help&amp;quot; class=&amp;quot;instapaper_ignore readability-extra&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Markdown Cheat Sheet&amp;lt;/h2&amp;gt;

  &amp;lt;div class=&amp;quot;cheatsheet-content&amp;quot;&amp;gt;

  &amp;lt;div class=&amp;quot;mod&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Format Text&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Headers&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
# This is an &amp;amp;lt;h1&amp;amp;gt; tag
## This is an &amp;amp;lt;h2&amp;amp;gt; tag
###### This is an &amp;amp;lt;h6&amp;amp;gt; tag&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Text styles&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__

*You **can** combine them*
&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Lists&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Unordered&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
* Item 1
* Item 2
  * Item 2a
  * Item 2b&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Ordered&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
1. Item 1
2. Item 2
3. Item 3
   * Item 3a
   * Item 3b&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Miscellaneous&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Images&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
![GitHub Logo](/images/logo.png)
Format: ![Alt Text](url)
&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Links&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
http://github.com - automatic!
[GitHub](http://github.com)&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;Blockquotes&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
As Kanye West said:

&amp;gt; We&#8217;re living the future so
&amp;gt; the present is our past.
&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

  &amp;lt;h3&amp;gt;Code Examples in Markdown&amp;lt;/h3&amp;gt;
  &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Syntax highlighting with &amp;lt;a href=&amp;quot;http://github.github.com/github-flavored-markdown/&amp;quot; title=&amp;quot;GitHub Flavored Markdown&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;GFM&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
&#8220;`javascript
function fancyAlert(arg) {
  if(arg) {
    $.facebox({div:&#8217;#foo&#8217;})
  }
}
&#8220;`&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Or, indent your code 4 spaces&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
Here is a Python code example
without syntax highlighting:

    def foo:
      if not bar:
        return true&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Inline code for comments&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
I think you should use an
`&amp;amp;lt;addr&amp;amp;gt;` element here instead.&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;


    &amp;lt;div class=&amp;quot;ajax-error-message&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; Something went wrong with that request. Please try again. &amp;lt;a href=&amp;quot;javascript:;&amp;quot; class=&amp;quot;ajax-error-dismiss&amp;quot;&amp;gt;Dismiss&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div id=&amp;quot;logo-popup&amp;quot;&amp;gt;
      &amp;lt;h2&amp;gt;Looking for the GitHub logo?&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;
          &amp;lt;h4&amp;gt;GitHub Logo&amp;lt;/h4&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip&amp;quot;&amp;gt;&amp;lt;img alt=&amp;quot;Github_logo&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/about_page/github_logo.png?1306884371&amp;quot; /&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip&amp;quot; class=&amp;quot;minibutton btn-download download&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Download&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;
          &amp;lt;h4&amp;gt;The Octocat&amp;lt;/h4&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/Octocats.zip&amp;quot;&amp;gt;&amp;lt;img alt=&amp;quot;Octocat&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/about_page/octocat.png?1306884371&amp;quot; /&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/Octocats.zip&amp;quot; class=&amp;quot;minibutton btn-download download&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Download&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;

    
    
    
    &amp;lt;span id=&#8217;server_response_time&#8217; data-time=&#8217;0.02880&#8217; data-host=&#8217;fe6&#8217;&amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;




&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2224862.js?file=client_spec.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
  &amp;lt;head prefix=&amp;quot;og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog: http://ogp.me/ns/fb/githubog#&amp;quot;&amp;gt;
    &amp;lt;meta charset=&#8217;utf-8&#8217;&amp;gt;
    &amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot;&amp;gt;
        &amp;lt;title&amp;gt;404 · GitHub&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&amp;quot;search&amp;quot; type=&amp;quot;application/opensearchdescription+xml&amp;quot; href=&amp;quot;/opensearch.xml&amp;quot; title=&amp;quot;GitHub&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;fluid-icon&amp;quot; href=&amp;quot;https://github.com/fluidicon.png&amp;quot; title=&amp;quot;GitHub&amp;quot; /&amp;gt;
    &amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;/favicon.ico&amp;quot; type=&amp;quot;image/x-icon&amp;quot; /&amp;gt;

    
    

    

    &amp;lt;link href=&amp;quot;https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github-e2fb92c4dcb5e5b1ce2ffd0e84d6bf80937d9197.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
    &amp;lt;link href=&amp;quot;https://a248.e.akamai.net/assets.github.com/stylesheets/bundles/github2-a6e03f3438e57a85fea8f7cc4939ed556a5c96e4.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
    

    &amp;lt;script src=&amp;quot;https://a248.e.akamai.net/assets.github.com/javascripts/bundles/jquery-225576cef50ef2097c9f9fbcd8953c1572544611.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&amp;quot;https://a248.e.akamai.net/assets.github.com/javascripts/bundles/github-353ded132c604f1bdf010516392d71052f37ffcf.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
    

    
  &amp;lt;/head&amp;gt;


  &amp;lt;body class=&amp;quot;logged_out    env-production &amp;quot; data-blob-contribs-enabled=&amp;quot;yes&amp;quot;&amp;gt;
    &amp;lt;div id=&amp;quot;wrapper&amp;quot;&amp;gt;

    
    
    

      &amp;lt;div id=&amp;quot;header&amp;quot; class=&amp;quot;true clearfix&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;
          &amp;lt;a class=&amp;quot;site-logo&amp;quot; href=&amp;quot;https://github.com&amp;quot;&amp;gt;
            &amp;lt;!&#8211;[if IE]&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7.png?1323882717&amp;quot; /&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-hover&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7-hover.png?1324325358&amp;quot; /&amp;gt;
            &amp;lt;![endif]&#8211;&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-4x&amp;quot; height=&amp;quot;30&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x.png?1323882717&amp;quot; /&amp;gt;
            &amp;lt;img alt=&amp;quot;GitHub&amp;quot; class=&amp;quot;github-logo-4x-hover&amp;quot; height=&amp;quot;30&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/header/logov7@4x-hover.png?1324325358&amp;quot; /&amp;gt;
          &amp;lt;/a&amp;gt;

                  &amp;lt;!&#8211;
      make sure to use fully qualified URLs here since this nav
      is used on error pages on other domains
    &#8211;&amp;gt;
    &amp;lt;ul class=&amp;quot;top-nav logged_out&amp;quot;&amp;gt;
        &amp;lt;li class=&amp;quot;pricing&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/plans&amp;quot;&amp;gt;Signup and Pricing&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&amp;quot;explore&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/explore&amp;quot;&amp;gt;Explore GitHub&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;features&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/features&amp;quot;&amp;gt;Features&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li class=&amp;quot;blog&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/blog&amp;quot;&amp;gt;Blog&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;li class=&amp;quot;login&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/login?return_to=%2Fgist%2F2224862%2Fclient_spec.rb&amp;quot;&amp;gt;Login&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;



          
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;

      

        &amp;lt;div class=&amp;quot;site clearfix&amp;quot;&amp;gt;
          &amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;
            

&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
    #header{
        border-bottom: 0;
    }
    .site{
        padding: 0;
        margin-top: -20px;
    }
    * {
        margin: 0px;
        padding: 0px;
    }
    #parallax_field{
        overflow: hidden;
        position: absolute;
        left: 0;
        top: 0;
        height: 370px;
        width: 100%;
    }
    #parallax_field #parallax_bg {
        position: absolute;
        top: -20px;
        left: -20px;
        width: 110%;
        height: 425px;
        z-index: 1;
    }
    #parallax_illustration {
        display:block;
        width: 940px;
        height: 370px;
        position: relative;
        overflow: hidden;
        clear: both;
    }
    #parallax_illustration #parallax_error_text {
        position: absolute;
        top: 72px;
        left: 72px;
        z-index: 10;
    }
    #parallax_illustration #parallax_octocat {
        position: absolute;
        top: 94px;
        left: 356px;
        z-index: 9;
    }
    #parallax_illustration #parallax_speeder {
        position: absolute;
        top: 150px;
        left: 432px;
        z-index: 8;
    }
    #parallax_illustration #parallax_octocatshadow {
        position: absolute;
        top: 297px;
        left: 371px;
        z-index: 7;
    }
    #parallax_illustration #parallax_speedershadow {
        position: absolute;
        top: 263px;
        left: 442px;
        z-index: 6;
    }
    #parallax_illustration #parallax_building_1 {
        position: absolute;
        top: 73px;
        left: 467px;
        z-index: 5;
    }
    #parallax_illustration #parallax_building_2 {
        position: absolute;
        top: 113px;
        left: 762px;
        z-index: 4;
    }
    #footer {
        margin-top: 0px;
        z-index: 12;
    }
&amp;lt;/style&amp;gt;


&amp;lt;div id=&amp;quot;parallax_field&amp;quot;&amp;gt;
    &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;0&amp;quot; data-yrange=&amp;quot;20&amp;quot; height=&amp;quot;415&amp;quot; id=&amp;quot;parallax_bg&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_bg.jpg?1315937721&amp;quot; width=&amp;quot;940&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;parallax_illustration&amp;quot;&amp;gt;
  &amp;lt;img alt=&amp;quot;404 | &amp;amp;ldquo;This is not the web page you are looking for&amp;amp;rdquo;&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;20&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;249&amp;quot; id=&amp;quot;parallax_error_text&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_errortext.png?1315937721&amp;quot; width=&amp;quot;271&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;Octobi Wan Catnobi&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;230&amp;quot; id=&amp;quot;parallax_octocat&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_octocat.png?1315937721&amp;quot; width=&amp;quot;188&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;land speeder&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;156&amp;quot; id=&amp;quot;parallax_speeder&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_speeder.png?1315937721&amp;quot; width=&amp;quot;440&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;Octobi Wan Catnobi&#8217;s shadow&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;49&amp;quot; id=&amp;quot;parallax_octocatshadow&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_octocatshadow.png?1315937721&amp;quot; width=&amp;quot;166&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;land speeder&#8217;s shadow&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-xrange=&amp;quot;10&amp;quot; data-yrange=&amp;quot;10&amp;quot; height=&amp;quot;75&amp;quot; id=&amp;quot;parallax_speedershadow&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_speedershadow.png?1315937721&amp;quot; width=&amp;quot;430&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;50&amp;quot; data-yrange=&amp;quot;20&amp;quot; height=&amp;quot;123&amp;quot; id=&amp;quot;parallax_building_1&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_building_1.png?1315937721&amp;quot; width=&amp;quot;304&amp;quot; /&amp;gt;
  &amp;lt;img alt=&amp;quot;building&amp;quot; class=&amp;quot;js-plaxify&amp;quot; data-invert=&amp;quot;true&amp;quot; data-xrange=&amp;quot;75&amp;quot; data-yrange=&amp;quot;30&amp;quot; height=&amp;quot;50&amp;quot; id=&amp;quot;parallax_building_2&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/404/parallax_building_2.png?1315937721&amp;quot; width=&amp;quot;116&amp;quot; /&amp;gt;
&amp;lt;/div&amp;gt;

          &amp;lt;/div&amp;gt;
          &amp;lt;div class=&amp;quot;context-overlay&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;div id=&amp;quot;footer-push&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;!&#8211; hack for sticky footer &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; end of wrapper - hack for sticky footer &#8211;&amp;gt;

      &amp;lt;!&#8211; footer &#8211;&amp;gt;
      &amp;lt;div id=&amp;quot;footer&amp;quot; &amp;gt;
        
  &amp;lt;div class=&amp;quot;upper_footer&amp;quot;&amp;gt;
     &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;

       &amp;lt;!&#8211;[if IE]&amp;gt;&amp;lt;h4 id=&amp;quot;blacktocat_ie&amp;quot;&amp;gt;GitHub Links&amp;lt;/h4&amp;gt;&amp;lt;![endif]&#8211;&amp;gt;
       &amp;lt;![if !IE]&amp;gt;&amp;lt;h4 id=&amp;quot;blacktocat&amp;quot;&amp;gt;GitHub Links&amp;lt;/h4&amp;gt;&amp;lt;![endif]&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;GitHub&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/about&amp;quot;&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/blog&amp;quot;&amp;gt;Blog&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/features&amp;quot;&amp;gt;Features&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/contact&amp;quot;&amp;gt;Contact &amp;amp;amp; Support&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/training&amp;quot;&amp;gt;Training&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://enterprise.github.com/&amp;quot;&amp;gt;GitHub Enterprise&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://status.github.com/&amp;quot;&amp;gt;Site Status&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Tools&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://get.gaug.es/&amp;quot;&amp;gt;Gauges: Analyze web traffic&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://speakerdeck.com&amp;quot;&amp;gt;Speaker Deck: Presentations&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://gist.github.com&amp;quot;&amp;gt;Gist: Code snippets&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://mac.github.com/&amp;quot;&amp;gt;GitHub for Mac&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://mobile.github.com/&amp;quot;&amp;gt;Issues for iPhone&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://jobs.github.com/&amp;quot;&amp;gt;Job Board&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Extras&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://shop.github.com/&amp;quot;&amp;gt;GitHub Shop&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://octodex.github.com/&amp;quot;&amp;gt;The Octodex&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

       &amp;lt;ul class=&amp;quot;footer_nav&amp;quot;&amp;gt;
         &amp;lt;h4&amp;gt;Documentation&amp;lt;/h4&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://help.github.com/&amp;quot;&amp;gt;GitHub Help&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://developer.github.com/&amp;quot;&amp;gt;Developer API&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://github.github.com/github-flavored-markdown/&amp;quot;&amp;gt;GitHub Flavored Markdown&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
         &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://pages.github.com/&amp;quot;&amp;gt;GitHub Pages&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
       &amp;lt;/ul&amp;gt;

     &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.site &#8211;&amp;gt;
  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.upper_footer &#8211;&amp;gt;

&amp;lt;div class=&amp;quot;lower_footer&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;container clearfix&amp;quot;&amp;gt;
    &amp;lt;!&#8211;[if IE]&amp;gt;&amp;lt;div id=&amp;quot;legal_ie&amp;quot;&amp;gt;&amp;lt;![endif]&#8211;&amp;gt;
    &amp;lt;![if !IE]&amp;gt;&amp;lt;div id=&amp;quot;legal&amp;quot;&amp;gt;&amp;lt;![endif]&amp;gt;
      &amp;lt;ul&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/site/terms&amp;quot;&amp;gt;Terms of Service&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/site/privacy&amp;quot;&amp;gt;Privacy&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/security&amp;quot;&amp;gt;Security&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;

      &amp;lt;p&amp;gt;&amp;amp;copy; 2012 &amp;lt;span title=&amp;quot;0.01817s from fe12.rs.github.com&amp;quot;&amp;gt;GitHub&amp;lt;/span&amp;gt; Inc. All rights reserved.&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /#legal or /#legal_ie&#8211;&amp;gt;

      &amp;lt;div class=&amp;quot;sponsor&amp;quot;&amp;gt;
        &amp;lt;a href=&amp;quot;http://www.rackspace.com&amp;quot; class=&amp;quot;logo&amp;quot;&amp;gt;
          &amp;lt;img alt=&amp;quot;Dedicated Server&amp;quot; height=&amp;quot;36&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/footer/rackspaces_logo.png?1329521040&amp;quot; width=&amp;quot;38&amp;quot; /&amp;gt;
        &amp;lt;/a&amp;gt;
        Powered by the &amp;lt;a href=&amp;quot;http://www.rackspace.com &amp;quot;&amp;gt;Dedicated
        Servers&amp;lt;/a&amp;gt; and&amp;lt;br/&amp;gt; &amp;lt;a href=&amp;quot;http://www.rackspacecloud.com&amp;quot;&amp;gt;Cloud
        Computing&amp;lt;/a&amp;gt; of Rackspace Hosting&amp;lt;span&amp;gt;&amp;amp;reg;&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.site &#8211;&amp;gt;
&amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.lower_footer &#8211;&amp;gt;

      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /#footer &#8211;&amp;gt;

    

&amp;lt;div id=&amp;quot;keyboard_shortcuts_pane&amp;quot; class=&amp;quot;instapaper_ignore readability-extra&amp;quot; style=&amp;quot;display:none&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Keyboard Shortcuts &amp;lt;small&amp;gt;&amp;lt;a href=&amp;quot;#&amp;quot; class=&amp;quot;js-see-all-keyboard-shortcuts&amp;quot;&amp;gt;(see all)&amp;lt;/a&amp;gt;&amp;lt;/small&amp;gt;&amp;lt;/h2&amp;gt;

  &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Site wide shortcuts&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;s&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Focus site search&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;?&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Bring up this help dialog&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;

    &amp;lt;div class=&amp;quot;column middle&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
      &amp;lt;h3&amp;gt;Commit list&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;c &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Open commit&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Expand URL to its canonical form&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;

    &amp;lt;div class=&amp;quot;column last&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
      &amp;lt;h3&amp;gt;Pull request list&amp;lt;/h3&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
      &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
        &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
        &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
      &amp;lt;/dl&amp;gt;
    &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.columns.last &#8211;&amp;gt;

  &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.columns.equacols &#8211;&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Issues&amp;lt;/h3&amp;gt;

    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;x&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Toggle selection&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column middle&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;I&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Mark selection as read&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;U&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Mark selection as unread&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Remove selection from view&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.middle &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column last&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;c&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Create issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Create label&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;i&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Back to inbox&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;u&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Back to issues&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;/&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Focus issues search&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Issues Dashboard&amp;lt;/h3&amp;gt;

    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Move selection up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;o &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; enter&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Open issue&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h3&amp;gt;Network Graph&amp;lt;/h3&amp;gt;
    &amp;lt;div class=&amp;quot;columns equacols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;←&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; h&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll left&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;→&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll right&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↑&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;&amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↓&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;t&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Toggle visibility of head labels&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.first &#8211;&amp;gt;
      &amp;lt;div class=&amp;quot;column last&amp;quot;&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;←&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift h&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way left&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;→&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way right&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↑&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift k&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way up&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;shift &amp;lt;span class=&amp;quot;badmono&amp;quot;&amp;gt;↓&amp;lt;/span&amp;gt; &amp;lt;em&amp;gt;or&amp;lt;/em&amp;gt; shift j&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Scroll all the way down&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;&amp;lt;!&#8211; /.column.last &#8211;&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;div style=&#8217;display:none&#8217;&amp;gt;
    &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;columns threecols&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column first&amp;quot; style=&#8217;display:none&#8217;&amp;gt;
        &amp;lt;h3&amp;gt;Source Code Browsing&amp;lt;/h3&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;t&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Activates the file finder&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;l&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Jump to line&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;w&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Switch branch/tag&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
        &amp;lt;dl class=&amp;quot;keyboard-mappings&amp;quot;&amp;gt;
          &amp;lt;dt&amp;gt;y&amp;lt;/dt&amp;gt;
          &amp;lt;dd&amp;gt;Expand URL to its canonical form&amp;lt;/dd&amp;gt;
        &amp;lt;/dl&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

    &amp;lt;div id=&amp;quot;markdown-help&amp;quot; class=&amp;quot;instapaper_ignore readability-extra&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;Markdown Cheat Sheet&amp;lt;/h2&amp;gt;

  &amp;lt;div class=&amp;quot;cheatsheet-content&amp;quot;&amp;gt;

  &amp;lt;div class=&amp;quot;mod&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Format Text&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Headers&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
# This is an &amp;amp;lt;h1&amp;amp;gt; tag
## This is an &amp;amp;lt;h2&amp;amp;gt; tag
###### This is an &amp;amp;lt;h6&amp;amp;gt; tag&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Text styles&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
*This text will be italic*
_This will also be italic_
**This text will be bold**
__This will also be bold__

*You **can** combine them*
&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Lists&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Unordered&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
* Item 1
* Item 2
  * Item 2a
  * Item 2b&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Ordered&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
1. Item 1
2. Item 2
3. Item 3
   * Item 3a
   * Item 3b&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;h3&amp;gt;Miscellaneous&amp;lt;/h3&amp;gt;
      &amp;lt;p&amp;gt;Images&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
![GitHub Logo](/images/logo.png)
Format: ![Alt Text](url)
&amp;lt;/pre&amp;gt;
     &amp;lt;p&amp;gt;Links&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
http://github.com - automatic!
[GitHub](http://github.com)&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;Blockquotes&amp;lt;/p&amp;gt;
     &amp;lt;pre&amp;gt;
As Kanye West said:

&amp;gt; We&#8217;re living the future so
&amp;gt; the present is our past.
&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;rule&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

  &amp;lt;h3&amp;gt;Code Examples in Markdown&amp;lt;/h3&amp;gt;
  &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Syntax highlighting with &amp;lt;a href=&amp;quot;http://github.github.com/github-flavored-markdown/&amp;quot; title=&amp;quot;GitHub Flavored Markdown&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;GFM&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
&#8220;`javascript
function fancyAlert(arg) {
  if(arg) {
    $.facebox({div:&#8217;#foo&#8217;})
  }
}
&#8220;`&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Or, indent your code 4 spaces&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
Here is a Python code example
without syntax highlighting:

    def foo:
      if not bar:
        return true&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;Inline code for comments&amp;lt;/p&amp;gt;
      &amp;lt;pre&amp;gt;
I think you should use an
`&amp;amp;lt;addr&amp;amp;gt;` element here instead.&amp;lt;/pre&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;

  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;


    &amp;lt;div class=&amp;quot;ajax-error-message&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; Something went wrong with that request. Please try again. &amp;lt;a href=&amp;quot;javascript:;&amp;quot; class=&amp;quot;ajax-error-dismiss&amp;quot;&amp;gt;Dismiss&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;div id=&amp;quot;logo-popup&amp;quot;&amp;gt;
      &amp;lt;h2&amp;gt;Looking for the GitHub logo?&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;
          &amp;lt;h4&amp;gt;GitHub Logo&amp;lt;/h4&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip&amp;quot;&amp;gt;&amp;lt;img alt=&amp;quot;Github_logo&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/about_page/github_logo.png?1315937721&amp;quot; /&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/GitHub_Logos.zip&amp;quot; class=&amp;quot;minibutton btn-download download&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Download&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;
          &amp;lt;h4&amp;gt;The Octocat&amp;lt;/h4&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/Octocats.zip&amp;quot;&amp;gt;&amp;lt;img alt=&amp;quot;Octocat&amp;quot; src=&amp;quot;https://a248.e.akamai.net/assets.github.com/images/modules/about_page/octocat.png?1315937721&amp;quot; /&amp;gt;&amp;lt;/a&amp;gt;
          &amp;lt;a href=&amp;quot;http://github-media-downloads.s3.amazonaws.com/Octocats.zip&amp;quot; class=&amp;quot;minibutton btn-download download&amp;quot;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;Download&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;

    
    
    
    &amp;lt;span id=&#8217;server_response_time&#8217; data-time=&#8217;0.02467&#8217; data-host=&#8217;fe12&#8217;&amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;This kind of dependency injection is one of many basic techniques which aren&amp;#8217;t
fancy enough to get a lot of press, but go a long way to keeping your objects
and tests in order.&lt;/p&gt;

&lt;p&gt;Got any thoughts? Hit me up, I&amp;#8217;m &lt;a href=&quot;https://twitter.com/pda&quot;&gt;@pda on Twitter&lt;/a&gt;,
where I generally write about this kind of thing.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Fast RSpec/Rails: tiered spec_helper.rb</title>
    <link href="http://paul.annesley.cc/2012/03/fast-rspec-slash-rails-tiered-spec-helper-dot-rb/"/>
    <updated>2012-03-14T20:41:00+11:00</updated>
    <id>http://paul.annesley.cc/2012/03/fast-rspec-slash-rails-tiered-spec-helper-dot-rb</id>
    <content type="html">&lt;p&gt;Slow Rails startup time is the TDD killer.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;paul@paulbookpro ~/project ⸩ time rspec spec/lib/method_hunting_delegator_spec.rb
..
Finished in 0.00078 seconds
2 examples, 0 failures
rspec spec/lib/method_hunting_delegator_spec.rb -f d  6.76s user 1.64s system 91% cpu 9.225 total
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Holy crap, that&amp;#8217;s 9 seconds of Rails startup, for 0.00078 seconds worth of
RSpec. And &lt;a href=&quot;http://paul.annesley.cc/2012/01/methodhuntingdelegator/&quot;&gt;this class/test&lt;/a&gt; doesn&amp;#8217;t even use Rails! We can do better.&lt;/p&gt;

&lt;p&gt;The culprit? That &lt;code&gt;require &quot;spec_helper&quot;&lt;/code&gt; at the top of every spec file which
loads the entire of Rails:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# This file is copied to spec/ when you run &#8216;rails generate rspec:install&#8217;
ENV[&quot;RAILS_ENV&quot;] ||= &#8216;test&#8217;
require File.expand_path(&quot;../../config/environment&quot;, __FILE__)
require &#8216;rspec/rails&#8217;
require &#8216;rspec/autorun&#8217;
# etc &#8230;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;#8217;s a few ways to deal with this, each with their own &lt;a href=&quot;https://github.com/rspec/rspec-rails/issues/371&quot;&gt;pitfalls&lt;/a&gt;. After
trying many approaches, I&amp;#8217;ve settled on a tiered RSpec initializer
(spec_helper.rb and friends) which I can choose when invoking RSpec.&lt;/p&gt;

&lt;p&gt;All the spec files still &lt;code&gt;require &quot;spec_helper&quot;&lt;/code&gt;, but it looks more like this:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2034589.js?file=spec_helper.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;if ENV[&amp;quot;COVERAGE&amp;quot;]
  require &amp;quot;simplecov&amp;quot;
  SimpleCov.start &amp;quot;rails&amp;quot;
end

mode = ENV[&amp;quot;SPEC&amp;quot;] || &amp;quot;full&amp;quot;
require_relative &amp;quot;spec_helper_#{mode}&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;Which means we can select different initializers using the SPEC environment
variable. The following &lt;code&gt;spec_helper_unit.rb&lt;/code&gt; is perfect for the
method_hunting_delegator_spec which took 9 seconds earlier, because there&amp;#8217;s no
dependencies on Rails.&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2034589.js?file=spec_helper_unit.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require &amp;quot;pathname&amp;quot;
RAILS_ROOT = Pathname.new(File.expand_path(&amp;quot;../..&amp;quot;, __FILE__))

# ActiveSupport
require &amp;quot;active_support&amp;quot;
require &amp;quot;active_support/dependencies&amp;quot;
%w{ extensions forms helpers mailers models presenters scripts }.each do |dir|
  ActiveSupport::Dependencies.autoload_paths &amp;lt;&amp;lt;
    File.expand_path(&amp;quot;../../app/#{dir}&amp;quot;, __FILE__)
end&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;The result?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;paul@paulbookpro ~/project ⸩ time SPEC=unit rspec spec/lib/method_hunting_delegator_spec.rb
..
Finished in 0.00079 seconds
2 examples, 0 failures
SPEC=unit rspec spec/lib/method_hunting_delegator_spec.rb  0.81s user 0.08s system 99% cpu 0.890 total
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Under a second (0.890) is much more like it, and we still get class autoloading
provided by ActiveSupport. I use this mode for just about everything except
subclasses of Rails components, and those I keep a slim as possible. Moving
logic into &lt;a href=&quot;http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)&quot;&gt;SOLID&lt;/a&gt; classes is something you&amp;#8217;ll benefit from anyway, and
these faster tests provide extra incentive. This example was a spec for a
standalone class living in &lt;code&gt;RAILS_ROOT/lib/&lt;/code&gt; but I use it for all sorts of
classes under &lt;code&gt;app/models/&lt;/code&gt;, &lt;code&gt;app/presenters/&lt;/code&gt;, &lt;code&gt;app/forms/&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;But this zero-Rails initializer doesn&amp;#8217;t help with testing your ORM-subclasses
(we&amp;#8217;ll begrudgingly call them &amp;#8220;models&amp;#8221;) which depend on ActiveRecord:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;paul@paulbookpro ~/project ⸩ SPEC=unit rspec spec/models/book_spec.rb
/Users/paul/project/app/models/book.rb:4:in `&amp;lt;top (required)&amp;gt;&#8217;: uninitialized constant ActiveRecord (NameError)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And having tasted sub-second tests, 12 seconds is clearly unacceptable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;paul@paulbookpro ~/project ⸩ time rspec spec/models/book_spec.rb
&#8230;&#8230;&#8230;&#8230;&#8230;..
Finished in 0.67016 seconds
17 examples, 0 failures
rspec spec/models/book_spec.rb  8.08s user 1.85s system 78% cpu 12.698 total
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But if you write your classes carefully, they don&amp;#8217;t need to depend on much
from Rails except ActiveRecord. So let&amp;#8217;s write a spec_helper which loads &amp;amp;
configures ActiveRecord, plus a few other bits and pieces useful for testing
database-persisted models.&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2034589.js?file=spec_helper_model.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require_relative &amp;quot;spec_helper_unit&amp;quot;

ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;quot;test&amp;quot;

# ActiveRecord
require &amp;quot;yaml&amp;quot;
require &amp;quot;active_record&amp;quot;
ActiveRecord::Base.establish_connection(
  YAML.load(File.read(RAILS_ROOT + &amp;quot;config/database.yml&amp;quot;))[&amp;quot;test&amp;quot;]
)

# factory_girl
require_relative &amp;quot;factories&amp;quot;
require_relative &amp;quot;support/factory_girl&amp;quot;

# DatabaseCleaner
require &amp;quot;database_cleaner&amp;quot;
RSpec.configure do |config|
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end
  config.before(:each) do
    DatabaseCleaner.start
  end
  config.after(:each) do
    DatabaseCleaner.clean
  end
end

# Todo, autoload observers?
ActiveRecord::Base.observers = [PaypalIpnObserver]
ActiveRecord::Base.instantiate_observers

# Enter database configurations into ActiveRecord
ActiveRecord::Base.send(:configurations=, YAML::load(ERB.new(IO.read(RAILS_ROOT + &amp;quot;config/database.yml&amp;quot;)).result))

# We hates Devise :(
class ActiveRecord::Base
  def self.devise *parameters; end; def self.define_index *parameters; end#; def configurations; configs; end
end
module Devise; module Models; module Recoverable; end end end
class User &amp;lt; ActiveRecord::Base; attr_writer :password; def self.has_own_preferences *parameters; end end
require_relative &amp;quot;../app/models/user&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;&lt;em&gt;You&amp;#8217;ll have to excuse the Devise hackery; it was the one component tightly
coupled into a model (&lt;code&gt;User&lt;/code&gt;), and like most Rails app, that particular model
is at the center of the whole relationship graph. Perhaps there&amp;#8217;s a better
solution, but this got me fast model tests for all but the user_spec itself.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Lets run that model spec again, this time boosted by &lt;code&gt;SPEC=model&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;paul@paulbookpro ~/project ⸩ time SPEC=model rspec spec/models/book_spec.rb
&#8230;&#8230;&#8230;&#8230;&#8230;..
Finished in 0.58512 seconds
17 examples, 0 failures
SPEC=model rspec spec/models/book_spec.rb  6.50s user 0.21s system 98% cpu 6.844 total
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that your model classes can still depend on external gems, but they&amp;#8217;ll
need to e.g. &lt;code&gt;require &quot;money&quot;&lt;/code&gt; at the top. I suspect this explicit declaration
of dependency isn&amp;#8217;t a bad idea anyway.&lt;/p&gt;

&lt;p&gt;Of course, there&amp;#8217;s always going to be specs which depend on the whole stack,
such as acceptance tests.  For those, here&amp;#8217;s the default spec_helper_full.rb;
basically like the original spec_helper.rb:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/2034589.js?file=spec_helper_full.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;# This file is copied to spec/ when you run &#8216;rails generate rspec:install&#8217;
ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &#8216;test&#8217;
require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
require &#8216;rspec/rails&#8217;

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)].each {|f| require f}&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;God speed.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>MethodHuntingDelegator</title>
    <link href="http://paul.annesley.cc/2012/01/methodhuntingdelegator/"/>
    <updated>2012-01-09T17:51:00+11:00</updated>
    <id>http://paul.annesley.cc/2012/01/methodhuntingdelegator</id>
    <content type="html">&lt;p&gt;I was implementing search in a Ruby app where the results objects were instances
of a mix of model classes. Each one had what could be considered a title and a
description, but the method names were inconsistent.&lt;/p&gt;

&lt;p&gt;Wrapping each result in a &lt;code&gt;SearchResult&lt;/code&gt; decorator to normalize the interface
seemed like a good idea. Ruby provides an abstract &lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/delegate/rdoc/Delegator.html&quot;&gt;Delegator&lt;/a&gt; and a concrete
&lt;a href=&quot;http://www.ruby-doc.org/stdlib-1.9.3/libdoc/delegate/rdoc/SimpleDelegator.html&quot;&gt;SimpleDelegator&lt;/a&gt; which gets most of the way there.&lt;/p&gt;

&lt;p&gt;To normalize the method interface, I wrote an extension of &lt;code&gt;SimpleDelegator&lt;/code&gt;
with a &lt;code&gt;#hunt_and_call(*candidates)&lt;/code&gt; method, which finds and calls the first
method of the candidate list which the delegate responds to.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the example calling code:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/1581535.js?file=example.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;class Book &amp;lt; SomeModelThing
  attr_reader :title, :blurb
end

class Course &amp;lt; SomeModelThing
  attr_reader :name, :description
end

class SearchResult &amp;lt; MethodHuntingDelegator

  def description
    hunt_and_call :description, :blurb
  end

  def title
    hunt_and_call :title, :name
  end

end

# simulate the results of a search with mixed result types
results = [ Book.first, Course.first ].map(&amp;amp;SearchResult.method(:new))

results.each { |r| puts &amp;quot;#{r.title}: #{r.description}&amp;quot; }&lt;/code&gt;&lt;/pre&gt;&lt;/noscript&gt;&lt;/div&gt;


&lt;p&gt;And the MethodHuntingDelegator implementation:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/1581535.js?file=method_hunting_delegator.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require &amp;quot;delegate&amp;quot;

class MethodHuntingDelegator &amp;lt; SimpleDelegator

  def hunt_and_call *candidates
    hunt_method(*candidates).call
  end

  private

  def hunt_method *candidates
    __getobj__.method candidates.detect(
      -&amp;gt;{ raise Error.new(candidates, __getobj__) },
      &amp;amp;__getobj__.method(:respond_to?)
    )
  end

  class Error &amp;lt; StandardError
    def initialize candidates, object
      super &amp;quot;#{candidates.inspect} not implemented by #{object.inspect}&amp;quot;
    end
  end

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


&lt;p&gt;And of course:&lt;/p&gt;

&lt;div&gt;&lt;script src=&#8217;https://gist.github.com/1581535.js?file=method_hunting_delegator_spec.rb&#8217;&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;pre&gt;&lt;code&gt;require &amp;quot;spec_helper&amp;quot;
require &amp;quot;method_hunting_delegator&amp;quot;

describe MethodHuntingDelegator do

  context &amp;quot;decorating a string&amp;quot; do

    let(:delegate) { &amp;quot;abcd&amp;quot; }
    let(:delegator) { MethodHuntingDelegator.new(delegate) }

    describe &amp;quot;#hunt_and_call&amp;quot; do

      it &amp;quot;delegates [ :not_a_method, :length, :upcase ] to String#length&amp;quot; do
        delegator.hunt_and_call(:not_a_method, :length, :upcase).should == 4
      end

      it &amp;quot;raises MethodHuntingDelegator::Error for [ :nope_A, :nope_B ]&amp;quot; do
        expect do
          delegator.hunt_and_call(:nope_A, :nope_B)
        end.to raise_error(MethodHuntingDelegator::Error)
      end

    end

  end

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


&lt;p&gt;Completely insane? Useful enough for a gem? Better way of going about it? Give
me hell in &lt;a href=&quot;https://gist.github.com/1581535&quot;&gt;the gist comments&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Camera Buyers Guide — The Verge</title>
    <link href="http://paul.annesley.cc/2012/01/camera-buyers-guide-the-verge/"/>
    <updated>2012-01-09T10:50:00+11:00</updated>
    <id>http://www.theverge.com/2012/1/2/2663464/camera-buyers-guide</id>
    <content type="html">&lt;p&gt;Ridiculously good article on digital cameras at &lt;a href=&quot;http://www.theverge.com/about-the-verge&quot;&gt;The Verge&lt;/a&gt;, worth reading
even if you&amp;#8217;re not in the market for one.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;What we’re seeking to do here is help you make an informed decision by
separating the meaningful data from the meaningless. This is a guide to
discerning the things that will make a recognizable difference in your
photographic experience and results. We’ve selected a few of our favorite
cameras in the categories below, but those will change over time, whereas the
rest of this advice will (hopefully) remain relevant for a long time to come.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Why can&amp;#8217;t there be more content of this quality on the Internet?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Todokyo</title>
    <link href="http://paul.annesley.cc/2011/02/11-todokyo/"/>
    <updated>2011-02-11T11:24:53+11:00</updated>
    <id>http://todokyo.com/</id>
    <content type="html">&lt;p&gt;Interesting looking todo client-side web app..&lt;/p&gt;

&lt;blockquote&gt;
It works like you’d expect, with a couple restrictions: First, every morning it starts over fresh. Your list from the day before is thrown in the trash. This, hopefully, will encourage the completion of all tasks each day and discourage the addition of frivolous items. Second, there’s no reordering. I want to trust my subconscious; if I add a task before another, then it’s because my mind has determined it’s priority by remembering it sooner.
&lt;/blockquote&gt;


&lt;p&gt;via &lt;a href=&quot;http://twitter.com/toolmantim/status/35851627713798144&quot;&gt;@toolmantim&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Email with Amazon SES and Rails 3</title>
    <link href="http://paul.annesley.cc/2011/02/06-email-with-amazon-ses-and-rails-3/"/>
    <updated>2011-02-06T19:48:31+11:00</updated>
    <id>http://robots.thoughtbot.com/post/3105121049/delivering-email-with-amazon-ses-in-a-rails-3-app</id>
    <content type="html">&lt;p&gt;The always excellent GIANT ROBOTS describes using Amazon&amp;#8217;s new Simple Email Service for sending mail from Rails 3, using the aws-ses gem.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>An intro to modern OpenGL</title>
    <link href="http://paul.annesley.cc/2010/05/12-opengl-es-20-tutorial/"/>
    <updated>2010-05-12T21:29:00+10:00</updated>
    <id>http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html</id>
    <content type="html">&lt;p&gt;An excellent OpenGL tutorial; beware other documentation and tutorials which endorse deprecated APIs and practices.&lt;/p&gt;

&lt;p&gt;Modern enough to be applicable to OpenGL ES 2.0 (and therefore &lt;a href=&quot;http://en.wikipedia.org/wiki/WebGL&quot;&gt;WebGL&lt;/a&gt;), which requires vertex and fragment shaders to be written in &lt;a href=&quot;http://en.wikipedia.org/wiki/WebGL&quot;&gt;OpenGL Shader Language&lt;/a&gt; to take advantage of the programmable rendering pipeline, and which removes much of the procedural (glBegin/glEnd) API.&lt;/p&gt;

&lt;p&gt;Adapting this tutorial to Cocoa Touch for iPhone/iPad OpenGL ES 2.0 development was relatively easy, and beat any iPhone OS specific documentation for ES 2.0 that I&amp;#8217;ve found.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>git-ff for git 1.7+</title>
    <link href="http://paul.annesley.cc/2010/05/12-git-ff/"/>
    <updated>2010-05-12T20:07:00+10:00</updated>
    <id>http://gist.github.com/398090</id>
    <content type="html">&lt;p&gt;Provides &amp;#8216;git ff&amp;#8217; to quickly fast-forward your current branch to the tracked remote when possible.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s &amp;#8216;git pull &amp;#8211;ff-only&amp;#8217; for those who do their own fetching, and besides, &amp;#8216;git ff&amp;#8217; is quicker :)&lt;/p&gt;

&lt;p&gt;Drop it in your path somewhere; depends on Git 1.7+ for the new &amp;#8211;ff-only parameter.&lt;/p&gt;

&lt;script src=&quot;http://gist.github.com/398090.js?file=git-ff&quot;&gt;&lt;/script&gt;

</content>
  </entry>
  
  <entry>
    <title>mustache: logic-less templates</title>
    <link href="http://paul.annesley.cc/2010/03/30-mustache-templates/"/>
    <updated>2010-03-30T21:18:00+11:00</updated>
    <id>http://defunkt.github.com/mustache/</id>
    <content type="html">&lt;p&gt;Nice simple template format, implementations in Ruby, Python, JavaScript, PHP and more.
Similar to Django templates in simplicity, syntax and sensible constraint of logic.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>toto</title>
    <link href="http://paul.annesley.cc/2010/02/toto/"/>
    <updated>2010-02-10T00:46:19+11:00</updated>
    <id>http://github.com/cloudhead/toto</id>
    <content type="html">&lt;p&gt;Tiny blog engine in Ruby and Rack, uses flat git-managed content files containing YAML &amp;amp; ERB/Markdown, handles comments via disqus, leaves caching to HTTP.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Machinarium</title>
    <link href="http://paul.annesley.cc/2010/01/machinarium/"/>
    <updated>2010-01-22T14:03:56+11:00</updated>
    <id>http://machinarium.net/demo/</id>
    <content type="html">&lt;p&gt;A puzzle point-and-click adventure game with a nice ambient soundtrack and a Oddworld: Abe&amp;#8217;s Oddysee feel about it. Implemented in flash, free demo.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Semantic Versioning</title>
    <link href="http://paul.annesley.cc/2009/12/semantic-versioning/"/>
    <updated>2009-12-16T14:13:37+11:00</updated>
    <id>http://semver.org/</id>
    <content type="html">&lt;p&gt;Simple version number specification for systems which expose a public API.  The format is major.minor.patch (e.g. 3.0.12); major indicates backwards incompatible, minor indicates backwards compatible, and 0.x.x indicates rapid development.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>The Go Programming Language</title>
    <link href="http://paul.annesley.cc/2009/11/the-go-programming-language/"/>
    <updated>2009-11-11T16:05:50+11:00</updated>
    <id>http://golang.org/</id>
    <content type="html">&lt;p&gt;New programming language from Google: performance like C, dynamic like Python, concurrent like Erlang.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>node.js</title>
    <link href="http://paul.annesley.cc/2009/11/node-js/"/>
    <updated>2009-11-10T10:18:13+11:00</updated>
    <id>http://nodejs.org/</id>
    <content type="html">&lt;p&gt;Event driven network IO for V8 JavaScript.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>v8 JavaScript Engine</title>
    <link href="http://paul.annesley.cc/2009/11/v8-javascript-engine/"/>
    <updated>2009-11-10T10:17:01+11:00</updated>
    <id>http://code.google.com/p/v8/</id>
    <content type="html">&lt;p&gt;Google&amp;#8217;s JavaScript engine as seen in Chrome, runs standalone or embedded in C++&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>jaml - GitHub</title>
    <link href="http://paul.annesley.cc/2009/11/jaml-github/"/>
    <updated>2009-11-09T09:04:33+11:00</updated>
    <id>http://github.com/edspencer/jaml</id>
    <content type="html">&lt;p&gt;Jaml tries to emulate Ruby’s Haml library, making it easy to generate HTML in your JavaScript projects.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Conflict free DNS and routes with multiple DHCP interfaces</title>
    <link href="http://paul.annesley.cc/2009/10/conflict-free-dns-routes-multiple-dhcp-interfaces/"/>
    <updated>2009-10-27T11:57:00+11:00</updated>
    <id>http://paul.annesley.cc/2009/10/conflict-free-dns-routes-multiple-dhcp-interfaces</id>
    <content type="html">&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;Running DHCP on two or more network interfaces inevitably leads to 
conflicting or unpredictable DNS and default route settings.&lt;/p&gt;

&lt;p&gt;For development at home and work, I use an Ubuntu virtual machine running 
on Mac OS.  To ensure I have a predictable IP address regardless of what 
network I&amp;#8217;m on, the VM primary network interface is &lt;strong&gt;NATed&lt;/strong&gt;, so 
it gets an IP address from VMware&amp;#8217;s DHCP server.  To let my co-workers access 
HTTP on my virtual machine, I have a second network interface which is 
&lt;strong&gt;bridged&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The biggest symptom of the problem is complete loss of connectivity when 
I switch between home and office, and the default route from the previous 
location is retained.&lt;/p&gt;

&lt;h2&gt;The Solution That Should Work&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://linux.die.net/man/5/dhclient.conf&quot;&gt;DHCP client configuration&lt;/a&gt;
lets you specify which details you want to request from the DHCP server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;request&lt;/strong&gt; statement&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;request [ option ] [, &amp;#8230; option ];&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The request statement causes the client to request that any server 
responding to the client send the client its values for the specified 
options. Only the option names should be specified in the request statement 
- not option parameters. By default, the DHCP server requests the subnet-mask, 
broadcast-address, time-offset, routers, domain-name, domain-name-servers, 
host-name, nis-domain, nis-servers, and ntp-servers options.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So it should be possible to omit &amp;#8216;routers&amp;#8217; and &amp;#8216;domain-name-servers&amp;#8217; from 
the &amp;#8216;request&amp;#8217; statement of the bridged interface, and all should be good.
However, it seems that some DHCP servers (like in my Linksys router at home) 
send a &amp;#8216;router&amp;#8217; anyway, and the DHCP client respects it despite not having 
requested it.&lt;/p&gt;

&lt;h2&gt;The Solution That Does Work&lt;/h2&gt;

&lt;p&gt;The solution that seems to work reliably is to write a simple 
dhclient-enter-hook to unset any unwanted details before they are 
processed.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
# /etc/dhcp3/dhclient-enter-hooks.d/bridged-eth1

if [ &quot;$interface&quot; = eth1 -a -n &quot;$new_routers&quot; ]; then
        echo Discarding eth1 routers: $new_routers
        unset new_routers
fi
if [ &quot;$interface&quot; = eth1 -a -n &quot;$new_domain_name_servers&quot; ]; then
        echo Discarding eth1 dns servers: $new_domain_name_servers
        unset new_domain_name_servers
fi
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  <entry>
    <title>proxymachine - GitHub</title>
    <link href="http://paul.annesley.cc/2009/10/proxymachine-github/"/>
    <updated>2009-10-22T11:46:43+11:00</updated>
    <id>http://github.com/mojombo/proxymachine</id>
    <content type="html">&lt;p&gt;Awesome looking Ruby/EventMachine TCP proxy from GitHub that does content-based routing to a backend. Opens a proxy to a backend once the read buffer contains enough information for a ruby block to return the desired backend address.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>sstrudeau&#8217;s jquery-dropper at master - GitHub</title>
    <link href="http://paul.annesley.cc/2009/10/sstrudeau-jquery-dropper-at-master-github/"/>
    <updated>2009-10-15T18:27:01+11:00</updated>
    <id>http://github.com/sstrudeau/jquery-dropper</id>
    <content type="html">&lt;p&gt;jQuery plugin, uses Canvas to provide an &amp;#8220;eye dropper&amp;#8221; color picker for same-domain images based on their pixel data.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Cloudvox - API-driven phone calls</title>
    <link href="http://paul.annesley.cc/2009/10/cloudvox-api-driven-phone-calls/"/>
    <updated>2009-10-12T21:37:01+11:00</updated>
    <id>http://cloudvox.com/</id>
    <content type="html">&lt;p&gt;Make and receive calls with JSON over RESTful HTTP, with flexible pricing.&lt;/p&gt;
</content>
  </entry>
  
</feed>

