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

<channel>
	<title>iknuth</title>
	<atom:link href="http://iknuth.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://iknuth.com</link>
	<description>gis - database - systems - web programming</description>
	<lastBuildDate>Fri, 20 Jan 2012 03:55:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>using socket.io to connect sencha to node and postgis</title>
		<link>http://iknuth.com/2012/01/using-socket-io-to-connect-sencha-to-node-and-postgis/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-socket-io-to-connect-sencha-to-node-and-postgis</link>
		<comments>http://iknuth.com/2012/01/using-socket-io-to-connect-sencha-to-node-and-postgis/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 00:00:28 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[postgis]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[sencha]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=539</guid>
		<description><![CDATA[Now that we&#8217;ve got node connected to our postgis database, we need to pull the route information into our sencha mobile web app. I&#8217;ve pushed this version to the github repo, but I haven&#8217;t deployed it to nodejitsu, just yet. &#8230; <a href="http://iknuth.com/2012/01/using-socket-io-to-connect-sencha-to-node-and-postgis/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p><a href="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-15-at-3.24.11-PM.png"><img class="alignright size-medium wp-image-541" title="Screen shot 2012-01-15 at 3.24.11 PM" src="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-15-at-3.24.11-PM-250x300.png" alt="working sencha trimet route view" width="250" height="300" /></a>Now that we&#8217;ve got node connected to our postgis database, we need to pull the route information into our sencha mobile web app.</p>
<p>I&#8217;ve pushed this version to the github repo, but I haven&#8217;t deployed it to nodejitsu, just yet.  <a title="postgis hosting service" href="https://www.ganeshdb.com" target="_blank">My postgis hosting service</a> requires that ssl be enabled, which is supported by the native version of the postgres module.  Unfortunately I can only get the pure js api to work on nodejitsu.</p>
<p>Rather than using jQuery or even Ext to make ajax requests, I&#8217;m going to be using <a href="http://socket.io" target="_blank">socket.io</a>, which is a websocket like implementation for node.</p>
<h3>passing around data with socket.io</h3>
<p>We are triggering the &#8216;get-routes&#8217; socket.io event on the backend, which takes a lat/lon and returns a list of routes to the callback.  This allows the view to be updated asynchronously by adding the new routes to the store and refreshing the display.</p>
<p><div id="gist-1617988" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">var</span> <span class="nx">refreshRoutes</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">lat</span><span class="p">,</span> <span class="nx">lon</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">socket</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;get-routes&#39;</span><span class="p">,</span> <span class="nx">lat</span><span class="p">,</span> <span class="nx">lon</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">routes</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">Ext</span><span class="p">.</span><span class="nx">each</span><span class="p">(</span><span class="nx">routes</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">route</span><span class="p">,</span> <span class="nx">index</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">App</span><span class="p">.</span><span class="nx">routeStore</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">route</span><span class="p">);</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">App</span><span class="p">.</span><span class="nx">routeList</span><span class="p">.</span><span class="nx">refresh</span><span class="p">();</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">};</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1617988/ebebd77e2d8f39e4e0965af88936af070f7df209/refreshroutes.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1617988#file_refreshroutes.js" style="float:right;margin-right:10px;color:#666">refreshroutes.js</a>
            <a href="https://gist.github.com/1617988">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
<br />
socket.io uses a variety of means of communication to send and receive events and objects between the web app and the server.  If web sockets aren&#8217;t available it falls back to flash sockets, commit style long polling and a variety of other mechanisms.</p>
<h3>sencha geolocation and data request</h3>
<p>I&#8217;ve added in the geolocation api that is part of sencha.  The app is refreshing the routes when it has a lock on the gps.  Sencha&#8217;s geolocation api makes this sort of thing easy.  Note that I&#8217;m not really handling any errors here, and they definitely could crop up. The following goes into the app&#8217;s onReady method.<br />
<div id="gist-1617988" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">var</span> <span class="nx">geo</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Ext</span><span class="p">.</span><span class="nx">util</span><span class="p">.</span><span class="nx">GeoLocation</span><span class="p">({</span></div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">autoUpdate</span><span class="o">:</span> <span class="kc">false</span><span class="p">,</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">listeners</span><span class="o">:</span> <span class="p">{</span></div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">locationupdate</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">geo</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">refreshRoutes</span><span class="p">(</span><span class="nx">geo</span><span class="p">.</span><span class="nx">latitude</span><span class="p">,</span> <span class="nx">geo</span><span class="p">.</span><span class="nx">longitude</span><span class="p">);</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">},</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">locationerror</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">geo</span><span class="p">,</span> <span class="nx">bTimeout</span><span class="p">,</span> <span class="nx">bPermissionDenied</span><span class="p">,</span> <span class="nx">bLocationUnavailable</span><span class="p">,</span> <span class="nx">message</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nx">bTimeout</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;Timeout occurred.&#39;</span><span class="p">);</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span> <span class="k">else</span> <span class="p">{</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;Error occurred.&#39;</span><span class="p">);</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">geo</span><span class="p">.</span><span class="nx">updateLocation</span><span class="p">();</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1617988/9b1cca44683324db3809db5e97b10859913c88db/geolocation.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1617988#file_geolocation.js" style="float:right;margin-right:10px;color:#666">geolocation.js</a>
            <a href="https://gist.github.com/1617988">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<h2>project status and next steps</h2>
<p>I&#8217;ve got the routes view rendering and I&#8217;ve added disclosure icons that switch the focus to the comments view.  I gave up on putting the map on the start screen because I had some trouble getting those components to share a card.  The next arrival bar on the bottom is mocked up for now and will require additional backend work.</p>
<p>I&#8217;m also thinking of scrapping comments and just focusing on the other two components.  That would free up some space on the toolbar and reduce the scope of the project.  My next step is to split the chat channels based on trimet routes and wire up that view.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/using-socket-io-to-connect-sencha-to-node-and-postgis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>using postgis with node.js</title>
		<link>http://iknuth.com/2012/01/using-postgis-with-node-js/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=using-postgis-with-node-js</link>
		<comments>http://iknuth.com/2012/01/using-postgis-with-node-js/#comments</comments>
		<pubDate>Sun, 15 Jan 2012 20:57:53 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[postgis]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=533</guid>
		<description><![CDATA[I&#8217;ve written my spatial query and it returns a an array of the 10 route lines that are closest to a point. My query retrieves the route number, description and distance in decimal degrees. I&#8217;ve projected the trimet data to &#8230; <a href="http://iknuth.com/2012/01/using-postgis-with-node-js/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>I&#8217;ve written my spatial query and it returns a an array of the 10 route lines that are closest to a point. My query retrieves the route number, description and distance in decimal degrees. I&#8217;ve projected the trimet data to the WGS84 projection, which is what we usually get from a GPS.</p>
<h3>a note about projections and web mapping</h3>
<p>I&#8217;m sure that the GIS people are nervous about my cavalier treatment of projections. I didn&#8217;t mention anything about spheres vs spheroids or anything like that.  If we were doing serious analysis it would be unacceptable to pay so little attention to the underlying data. However we are building a web app where speed and ease of use trumps accuracy. There are compromises that have to be made for this sort of thing. It is good to be aware of the tradeoffs, but I&#8217;m not too concerned.</p>
<h2>a trimet node module and git branches</h2>
<p>I&#8217;ve added a some node module to the repo to hold the server side application code for interacting with postgis and the trimet data. I haven&#8217;t worried too much about organizing my code, yet, but it seems like a good time to impose some structure. I&#8217;ve also added a test directory and an integration test that actually runs the query against our database and verifies that we get the expected results. This will come in handy as things get more complicated.</p>
<h3>git flow and development branches</h3>
<p>You may also notice that the <a href="https://github.com/eknuth/seatMate/" target="_blank">git repo</a> contains a <a href="https://github.com/eknuth/seatMate/tree/develop" target="_blank">develop branch</a> in addition to our master. The master branch holds our current stable deployed code, and new code gets added to develop.</p>
<p>When I am ready to release I merge the develop branch into master to be deployed.  Git makes it easy to branch and merge.  I&#8217;m also using the <a href="http://nvie.com/posts/a-successful-git-branching-model/" target="_blank">flow extension to git</a> to make it easy to manage the branches.  I highly recommend this approach.</p>
<h3>trimet node.js module</h3>
<p>In the development branch, I&#8217;ve added a new javascript file called <a href="https://github.com/eknuth/seatMate/blob/develop/lib/trimet.js" target="_blank">lib/trimet.js</a>.  It exports one function to our server that takes a latitude and longitude and returns a list of routes from the postgis database.  It is using the <a href="https://github.com/brianc/node-postgres" target="_blank">node-postgres module</a> by Brian Carlson and used in production at places like <a href="https://www.yammer.com/" target="_blank">yammer</a>.</p>
<p>This integration test demonstrates the use of trimet.getRoutesByPoint, our first module function.  It uses <a href="https://github.com/visionmedia/mocha" target="_blank">mocha</a>, an excellent node test framework that I wrote about in article on <a href="http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/" title="exploring redis in node.js using the mocha testing framework" target="_blank">asynchronous tests with node and redis</a>.</p>
<h3>preventing sql injection attacks</h3>
<p>Note that I am creating the query string by concatenating the coordinates.  This opens us up to sql injection attacks and should raise a <a href="http://xkcd.com/327/" target="_blank">red flag for security</a>.  The node postgres module supports parameter replacement, but I was running into trouble with that.  </p>
<p>In order to prevent random sql from being executed on our database, I&#8217;m testing to make sure our latitude and longitude are actually numbers before passing them to the module.  Really this method should fail if we pass it anything but numbers.  We&#8217;ll address that later.</p>
<div id="gist-1617156" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">var</span> <span class="nx">trimet</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;../lib/trimet.js&#39;</span><span class="p">),</span></div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">should</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;should&#39;</span><span class="p">);</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;trimet: get nearest routes from coordinate&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;getRoutesByPoint&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should return some points&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">lat</span> <span class="o">=</span> <span class="mf">45.499541</span><span class="p">,</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">lon</span> <span class="o">=</span> <span class="o">-</span><span class="mf">122.613639</span><span class="p">,</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">expectedRoutes</span> <span class="o">=</span> <span class="p">[{</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">route</span><span class="o">:</span> <span class="mi">9</span><span class="p">,</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">description</span><span class="o">:</span> <span class="s1">&#39;Powell/Broadway&#39;</span><span class="p">,</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">distance</span><span class="o">:</span> <span class="mf">0.00200889736828729</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">},</span> <span class="p">{</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">route</span><span class="o">:</span> <span class="mi">14</span><span class="p">,</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">description</span><span class="o">:</span> <span class="s1">&#39;Hawthorne&#39;</span><span class="p">,</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">distance</span><span class="o">:</span> <span class="mf">0.00229043846550735</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}];</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">trimet</span><span class="p">.</span><span class="nx">getRouteByPoint</span><span class="p">(</span><span class="nx">lat</span><span class="p">,</span> <span class="nx">lon</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">should</span><span class="p">.</span><span class="nx">not</span><span class="p">.</span><span class="nx">exist</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">should</span><span class="p">.</span><span class="nx">exist</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">data</span><span class="p">.</span><span class="nx">should</span><span class="p">.</span><span class="nx">eql</span><span class="p">(</span><span class="nx">expectedRoutes</span><span class="p">);</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">done</span><span class="p">();</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1617156/0590f792471fc259ebcc7415a5e9071a2639a001/test_trimet.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1617156#file_test_trimet.js" style="float:right;margin-right:10px;color:#666">test_trimet.js</a>
            <a href="https://gist.github.com/1617156">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/using-postgis-with-node-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>making seatmate aware of locations with postgis</title>
		<link>http://iknuth.com/2012/01/making-seatmate-aware-of-locations-with-postgis/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=making-seatmate-aware-of-locations-with-postgis</link>
		<comments>http://iknuth.com/2012/01/making-seatmate-aware-of-locations-with-postgis/#comments</comments>
		<pubDate>Sat, 14 Jan 2012 17:49:00 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[location based service]]></category>
		<category><![CDATA[mockup]]></category>
		<category><![CDATA[postgis]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=515</guid>
		<description><![CDATA[Now that I&#8217;ve got the comment view more or less working, it&#8217;s time to link it up with actual trimet routes.  I think we need an initial screen to show to users when they first bring up the app.  I &#8230; <a href="http://iknuth.com/2012/01/making-seatmate-aware-of-locations-with-postgis/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>Now that I&#8217;ve got the comment view more or less working, it&#8217;s time to link it up with actual trimet routes.  I think we need an initial screen to show to users when they first bring up the app.  I imagine that people will be either riding the bus/max, or they will be waiting at the stop.  Seems like we need to start by showing routes that are closest the user&#8217;s current location.</p>
<p><a href="http://iknuth.com/wp-content/uploads/2012/01/start-screen.png"><img class="aligncenter size-medium wp-image-516" title="start-screen" src="http://iknuth.com/wp-content/uploads/2012/01/start-screen-300x258.png" alt="start screen for seatmate app" width="300" height="258" /></a></p>
<h2>performing spatial queries in postgis</h2>
<p>Our backend needs to support a method that takes a latitude and longitude in the commonly used WGS84 projection and return the routes that are closest to that point.  Just getting the nearest stops isn&#8217;t useful because the rider may be actually travelling the route and not anywhere near a stop.  Luckily postgis makes it easy to select lines based on proximity to a point.  Please see the note from Regina in the comments for updated postgis functions.</p>
<div id="gist-1612154" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">SELECT</span> <span class="ss">&quot;RTE&quot;</span> <span class="k">as</span> <span class="n">route</span><span class="p">,</span><span class="ss">&quot;RTE_DESC&quot;</span> <span class="k">as</span> <span class="n">description</span><span class="p">,</span><span class="ss">&quot;DIR_DESC&quot;</span> <span class="k">as</span> <span class="n">direction</span><span class="p">,</span></div><div class='line' id='LC2'>	<span class="n">distance</span><span class="p">(</span><span class="n">PointFromText</span><span class="p">(</span><span class="s1">&#39;POINT(-122.613639 45.499541)&#39;</span><span class="p">,</span> <span class="mi">4326</span><span class="p">),</span> <span class="n">the_geom</span><span class="p">)</span> <span class="k">as</span> <span class="n">distance</span></div><div class='line' id='LC3'><span class="k">from</span> <span class="n">tm_routes</span> <span class="k">order</span> <span class="k">by</span> <span class="n">distance</span> <span class="k">limit</span> <span class="mi">10</span><span class="p">;</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1612154/c3c7211ae353a4240ad8789ce01c10c38f80a97c/spatial.sql" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1612154#file_spatial.sql" style="float:right;margin-right:10px;color:#666">spatial.sql</a>
            <a href="https://gist.github.com/1612154">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>This query returns the following results when applied against the postgis table I created from the trimet shapefile projected to WGS84. Note that postgres requires that we double quote the column names because they are capitalized.</p>
<div id="gist-1612154" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>&nbsp;route |      description       |           direction            |      distance       </div><div class='line' id='LC2'>-------+------------------------+--------------------------------+---------------------</div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9 | Powell/Broadway        | To Powell &amp; 98th or Gresham TC | 0.00200889736828729</div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9 | Powell/Broadway        | To Saratoga &amp; 27th             | 0.00200890251737265</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;14 | Hawthorne              | To Foster &amp; 94th               | 0.00229043846550735</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;14 | Hawthorne              | To Portland City Center        | 0.00229044244641688</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;71 | 60th Ave/122nd Ave     | To Foster &amp; 94th               | 0.00460586966268184</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;71 | 60th Ave/122nd Ave     | To Clackamas Town Center       | 0.00460588437600594</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 | Division/Fessenden     | To Gresham TC                  | 0.00575370636240205</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 | Division/Fessenden     | To St Johns                    | 0.00575370636240205</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;75 | Cesar E Chavez/Lombard | To St. Johns                   | 0.00898150226029743</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;75 | Cesar E Chavez/Lombard | To Milwaukie                   | 0.00898150543661629</div><div class='line' id='LC13'>(10 rows)</div><div class='line' id='LC14'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1612154/21f8c8d7568fcc110e4ac8a390d93d6343f4e056/results.txt" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1612154#file_results.txt" style="float:right;margin-right:10px;color:#666">results.txt</a>
            <a href="https://gist.github.com/1612154">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<h2>grouping results in sql</h2>
<p>The routes returned look great for my current location. The data is accurate enough to differentiate between routes that run on the same street in different directions. If I were waiting at a bus stop, it would be a safe bet to assume that the bus I want is on the same side of the street as me. I still want to return other routes, but at this point I don&#8217;t really care what direction they are going. I want to group the results and just return a single row for each route. We can achieve that goal by tweaking the sql. We just need to apply an aggregate to the distance and group the results by route. We could filter the results by distance, but there isn&#8217;t really a need at this point.</p>
<p><div id="gist-1612154" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">SELECT</span> <span class="ss">&quot;RTE&quot;</span> <span class="k">as</span> <span class="n">route</span><span class="p">,</span> <span class="ss">&quot;RTE_DESC&quot;</span> <span class="k">as</span> <span class="n">description</span><span class="p">,</span></div><div class='line' id='LC2'>	<span class="k">min</span><span class="p">(</span><span class="n">distance</span><span class="p">(</span><span class="n">PointFromText</span><span class="p">(</span><span class="s1">&#39;POINT(-122.613639 45.499541)&#39;</span><span class="p">,</span> <span class="mi">4326</span><span class="p">),</span> <span class="n">the_geom</span><span class="p">))</span> <span class="k">as</span> <span class="n">distance</span></div><div class='line' id='LC3'><span class="k">from</span> <span class="n">tm_routes</span> <span class="k">group</span> <span class="k">by</span> <span class="n">route</span><span class="p">,</span> <span class="n">description</span></div><div class='line' id='LC4'><span class="k">order</span> <span class="k">by</span> <span class="n">distance</span> <span class="k">limit</span> <span class="mi">10</span><span class="p">;</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1612154/c2102181c0c79cd267b35a948ac45f6f3aa710c9/improved.sql" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1612154#file_improved.sql" style="float:right;margin-right:10px;color:#666">improved.sql</a>
            <a href="https://gist.github.com/1612154">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
<br />
<div id="gist-1612154" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'>route |      description       |      distance       </div><div class='line' id='LC2'>-------+------------------------+---------------------</div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;9 | Powell/Broadway        | 0.00200889736828729</div><div class='line' id='LC4'>&nbsp;&nbsp;&nbsp;&nbsp;14 | Hawthorne              | 0.00229043846550735</div><div class='line' id='LC5'>&nbsp;&nbsp;&nbsp;&nbsp;71 | 60th Ave/122nd Ave     | 0.00460586966268184</div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4 | Division/Fessenden     | 0.00575370636240205</div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;75 | Cesar E Chavez/Lombard | 0.00898150226029743</div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;66 | Marquam Hill/Hollywood | 0.00898150861891694</div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;17 | Holgate/NW 21st        | 0.00924074516961275</div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;10 | Harold St              |  0.0148568363291083</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;15 | Belmont/NW 23rd        |  0.0170180326549672</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;19 | Woodstock/Glisan       |   0.020370095002805</div><div class='line' id='LC13'>(10 rows)</div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1612154/54366ad6ed0c9e58c8709bea65d064d585bb3321/improved_results.txt" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1612154#file_improved_results.txt" style="float:right;margin-right:10px;color:#666">improved_results.txt</a>
            <a href="https://gist.github.com/1612154">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
</p>
<h2>putting it all together</h2>
<p>I&#8217;m happy with these results. The next step is to wrap it in a method and expose it on our backend. Then I&#8217;ll write a new Sencha touch view to request the data based on the coordinate returned from the geolocation api in the browser. Should be a snap.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/making-seatmate-aware-of-locations-with-postgis/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>the node.js and postgis backend for seatmate</title>
		<link>http://iknuth.com/2012/01/the-node-js-and-postgis-backend-for-seatmate/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=the-node-js-and-postgis-backend-for-seatmate</link>
		<comments>http://iknuth.com/2012/01/the-node-js-and-postgis-backend-for-seatmate/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 05:20:01 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[geolocation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[location based service]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[postgis]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=495</guid>
		<description><![CDATA[So far I haven&#8217;t spent much development time working on the backend for seatMate.  I mentioned that I was using node.js to serve up the static files on my development server and nodejitsu.  The backend also saves and retrieves comments &#8230; <a href="http://iknuth.com/2012/01/the-node-js-and-postgis-backend-for-seatmate/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>So far I haven&#8217;t spent much development time working on the backend for seatMate.  I mentioned that I was using <a href="http://nodejs.org" target="_blank">node.js</a> to serve up the static files on my development server and <a href="http://nodejitsu.com" target="_blank">nodejitsu</a>.  The backend also saves and retrieves comments from a list stored in <a href="http://redis.io" target="_blank">redis</a>.</p>
<h2>backend architecture choices, async events with node.js</h2>
<p>The great thing about node and redis is that they support asynchronous operations in the same way that javascript handles events in the browser.  To make things even more responsive, I&#8217;m using <a href="http://socket.io" target="_blank">socket.io</a> to pass an object to a method on the server, rather than using an http post when the client submits a comment .  socket.io acts like a websocket, but degrades to flash sockets, long polling and other less fancy methods to support all browsers including IE6.</p>
<p>In a previous post, I wrote more about <a href="http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/">node and redis</a>.</p>
<h2>pushing events back to the browser with socket.io</h2>
<p>The benefit to using socket.io and node  is that I can trigger events in the browser from the server without doing any polling from the client.  This will be handy when it comes to the chat and instant messaging components, which update in real time.  When a user sends a message, the backend can immediately relay it to any other device connected to the channel causing it to appear in their browser.</p>
<h2>using redis to store and relay information</h2>
<p>redis is the other technology I added to the project.  It is one of the new nosql datastores, but it also supports other features that will make it useful here.  redis is a data structure storage engine and can handle strings, hashes, sets and sorted sets.  It also has a publisher/subscriber functionality that makes it a snap to implement a messaging queue.</p>
<p>For the comment view, I&#8217;m pushing incoming messages into a redis list and retrieving the last 15 messages when rendering the comment view.  All these operations are extremely fast, even if the list gets huge.  No need to talk about the big o, but it will stay fast at scale.</p>
<h2>performing spatial queries on a geodatabase with postgis</h2>
<p>The next step is to actually tie the comments to specific bus routes and busses.  For the contest I have to use TriMet data.  The stops, routes, and possibly the real time transit feeds are exactly what I need.  To start matching up users with routes, I need to be able to select the route that is closest to the location of the the rider.</p>
<p>It would be trivial to perform this sort of operation with points, although scaling might get difficult.  Calculating the distance to a line from a point is an easy to do with postgis, the geodatabase extension to postgresql.  My next step is to create a method that queries postgis for routes that are closest to the location of the device as reported by the geolocation api.</p>
<p>In cases where the user is on a bus that travels the same path as our routes this operation will return multiple rows and, I will have to use other data to disambiguate the results.  Just grabbing the closest route is good enough for now, though.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/the-node-js-and-postgis-backend-for-seatmate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>working comment front end with sencha touch</title>
		<link>http://iknuth.com/2012/01/working-comment-front-end-with-sencha-touch/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=working-comment-front-end-with-sencha-touch</link>
		<comments>http://iknuth.com/2012/01/working-comment-front-end-with-sencha-touch/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 02:53:54 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[extjs]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[sencha]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=483</guid>
		<description><![CDATA[After spending a day watching Sencha Touch screencast videos, I&#8217;ve got my comment view cleaned working and deployed to nodejitsu at http://seatmate.nodejitsu.com.  Basically the same code should make the chat and instant messaging views function as well.  Feel free to &#8230; <a href="http://iknuth.com/2012/01/working-comment-front-end-with-sencha-touch/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><p>After spending a day watching <a href="http://www.sencha.com/learn/touch/#Xx/screencast/date/desc" target="_blank">Sencha Touch screencast videos</a>, I&#8217;ve got my comment view cleaned working and deployed to nodejitsu at <a href="http://seatmate.nodejitsu.com" target="_blank">http://seatmate.nodejitsu.com</a>.  Basically the same code should make the chat and instant messaging views function as well.  Feel free to file bug reports on the <a href="https://github.com/eknuth/seatMate/issues" target="_blank">seatMate github issue tracker</a>.</p>
<p><a href="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-12-at-1.38.01-PM.png"><img class="alignleft size-medium wp-image-484" title="comment view mockup" src="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-12-at-1.38.01-PM-246x300.png" alt="comment view mockup" width="246" height="300" /></a>I&#8217;ve got a Sencha list view with an xtemplate bound to a json store.  There is a form panel that dispatches to a controller for posting messages to a single comment channel on the backend.  When the page loads, the datastore is prepopulated with the last 10 or so  comments on the channel.  The list view scrolls independently of the rest of the page.</p>
<p>New comments entered through the form are added to the view immediately, but comments posted on other devices are not displayed automatically.  That would be what makes the feature that differentiates the comment view from the chat view.  I also need to tweak the css to make the comments smaller and have more of them on the screen at once.</p>
<p>The app works on Android and iOS browsers, as well as desktop webkit browsers like Chrome, but has some trouble with Firefox.  Unfortunately that is a problem for all Sencha Touch apps.</p>
<p>Development was good considering I also had to learn Sencha/ExtJS.  Unfortunately I don&#8217;t have any javascript unit tests.  I have a hard time doing TDD when I&#8217;m using a new framework, but I&#8217;d be able to do it next time.</p>
<p>I&#8217;m going to finish the app in Sencha, but I feel like it isn&#8217;t the best approach for mobile web app development.  I&#8217;m writing a lot of code for what I&#8217;m getting and I prefer to build my interfaces in html rather than javascript.  The framework does provide a slick product and handles a lot of the mobile pain, though.</p>
<p>I&#8217;d also prefer a solution that allowed the same app to run on mobile, tablets and desktops with responsive design.  Unfortunately sencha touch apps are relegated to the mobile ghetto.  But I feel like I&#8217;m making good progress overall.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/working-comment-front-end-with-sencha-touch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>first draft of seatMate interface using sencha touch</title>
		<link>http://iknuth.com/2012/01/first-draft-of-seatmate-interface-using-sencha-touch/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=first-draft-of-seatmate-interface-using-sencha-touch</link>
		<comments>http://iknuth.com/2012/01/first-draft-of-seatmate-interface-using-sencha-touch/#comments</comments>
		<pubDate>Mon, 09 Jan 2012 02:01:23 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[extjs]]></category>
		<category><![CDATA[geoext]]></category>
		<category><![CDATA[seatMate]]></category>
		<category><![CDATA[sencha]]></category>
		<category><![CDATA[trimet]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=463</guid>
		<description><![CDATA[creating a mobile web app from a mockup I&#8217;ve started on the interface using sencha touch, a mobile web framework.  Sencha Touch is part of the ExtJS family of javascript libraries.  I&#8217;ve hard good things about sencha and GeoExt, so &#8230; <a href="http://iknuth.com/2012/01/first-draft-of-seatmate-interface-using-sencha-touch/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><h2>creating a mobile web app from a mockup</h2>
<p style="text-align: center;"><a href="http://iknuth.com/wp-content/uploads/2012/01/flirt-tab.png"><img class=" wp-image-466 aligncenter" title="flirt-tab" src="http://iknuth.com/wp-content/uploads/2012/01/flirt-tab.png" alt="" width="407" height="240" /></a></p>
<p>I&#8217;ve started on the interface using sencha touch, a mobile web framework.  <a href="http://www.sencha.com/products/touch/" target="_blank">Sencha Touch</a> is part of the <a href="http://www.sencha.com/products/extjs" target="_blank">ExtJS</a> family of javascript libraries.  I&#8217;ve hard good things about sencha and<a href="http://geoext.org/" target="_blank"> GeoExt</a>, so I&#8217;m excited to give it a shot.  The style is similar to how we used to develop web apps at the company I work for, but we&#8217;ve since moved on to using <a href="http://knockoutjs.com/" target="_blank">knockout.js</a>.</p>
<h2>the sencha touch approach</h2>
<p>Sencha lets you build up a mobile web frontend programmatically rather than starting from existing html.  You create objects that represent forms, tabs, carousels and everything else you need to develop a smartphone or tablet app.  Sencha produces html5 and supports many of the animations and transitions that are used in native iOS and android apps.</p>
<p>I&#8217;ve made good progress and sencha seems robust and flexible.  My main concern is that the workflow is clumsy.  Rather than writing html to create the interface, you describe it in javascript.  I would rather create the page freely and then add behavior.</p>
<p>Using code inspired by several of the online demos, I&#8217;ve put together a sencha app with an initial stab at a chat/comment view.  I have a comment entry field and a submit button as well as a table of comments.  The other tabs will follow the same general pattern, but aren&#8217;t built yet.</p>
<h2> serving the static html, css and js files</h2>
<p>Since the files are static html I can view them directly in a browser without spending time setting up a webserver.  However, I&#8217;m using a snippet of javascript for node.js that serves up the contents of the static directory on port 8000.  I&#8217;ve pushed this version to the repo and deployed it to nodejitsu.</p>
<h2>deployed to hosting provider</h2>
<p>You can check it out at <a href="http://seatmate.nodejitsu.com/" target="_blank">http://seatmate.nodejitsu.com/</a></p>
<p><a href="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-08-at-5.37.36-PM.png"><img class="alignleft  wp-image-464" title="first  sencha touch mockup" src="http://iknuth.com/wp-content/uploads/2012/01/Screen-shot-2012-01-08-at-5.37.36-PM.png" alt="first sencha touch mockup" width="277" height="430" /></a><a href="http://iknuth.com/wp-content/uploads/2012/01/chat-tab1.png"><img class=" wp-image-465 alignright" title="chat-tab" src="http://iknuth.com/wp-content/uploads/2012/01/chat-tab1.png" alt="" width="236" height="375" /></a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>I&#8217;ve also attached a few more mockups of the other screens.  They are in landscape and portrait mode.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/first-draft-of-seatmate-interface-using-sencha-touch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>initial mockup for seatMate mobile app</title>
		<link>http://iknuth.com/2012/01/initial-mockup-for-seatmate-mobile-app/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=initial-mockup-for-seatmate-mobile-app</link>
		<comments>http://iknuth.com/2012/01/initial-mockup-for-seatmate-mobile-app/#comments</comments>
		<pubDate>Sat, 07 Jan 2012 23:53:27 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[mockup]]></category>
		<category><![CDATA[seatMate]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=453</guid>
		<description><![CDATA[first mockup for comment tab For usability&#8217;s sake, web apps tend to use familiar components.  There are a number of design templates that make it easy to get a an application up and running without spending a lot of time &#8230; <a href="http://iknuth.com/2012/01/initial-mockup-for-seatmate-mobile-app/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><h1>first mockup for comment tab</h1>
<p>For usability&#8217;s sake, web apps tend to use familiar components.  There are a number of design templates that make it easy to get a an application up and running without spending a lot of time wrestling with html and css.</p>
<p>One of the problems with using these templates, is that your application will end up looking like every app that uses the same template.  At some point I will make the application look more unique, so I&#8217;ve added &#8220;not cookie cutter&#8221; to the requirements.</p>
<p>Here is my first drawing for the comment component of seatMate.  It is basic, but should provide enough to get started.  Please pardon my messy drawing!</p>
<p><a href="http://iknuth.com/wp-content/uploads/2012/01/chat-tab.png"><img class="aligncenter size-full wp-image-454" title="chat-tab" src="http://iknuth.com/wp-content/uploads/2012/01/chat-tab.png" alt="mock up for chat tab" width="306" height="526" /></a></p>
<h2>repo</h2>
<p>I&#8217;ve added this mockup and an initial skeleton for the app to the <a href="https://github.com/eknuth/seatMate" target="_blank">seatMate github repo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/initial-mockup-for-seatmate-mobile-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>trimet app contest entry: seatMate</title>
		<link>http://iknuth.com/2012/01/trimet-app-contest-entry-seatmate/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=trimet-app-contest-entry-seatmate</link>
		<comments>http://iknuth.com/2012/01/trimet-app-contest-entry-seatmate/#comments</comments>
		<pubDate>Sat, 07 Jan 2012 21:53:16 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[seatMate]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=451</guid>
		<description><![CDATA[2012 TriMet App Contest I&#8217;ve decided to compete in the TriMet App Contest.  The deadline is February 1st, 2012, and I am starting this weekend.  The app must use TriMet and CivicApps open datasets and be released as an open &#8230; <a href="http://iknuth.com/2012/01/trimet-app-contest-entry-seatmate/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><h1>2012 TriMet App Contest</h1>
<p>I&#8217;ve decided to compete in the <a href="http://www.trimet.org/contest/visitor-app.htm" target="_blank">TriMet App Contest</a>.  The deadline is February 1st, 2012, and I am starting this weekend.  The app must use TriMet and <a href="https://civicapps.org" target="_blank">CivicApps</a> open datasets and be released as an open source project.</p>
<p>Rather than keeping my app under wraps until the end date, I&#8217;ve decided to do all the design and development in public.  I hope the other entrants will use my code and methods to develop their own cool apps.</p>
<h1>My App: seatMate</h1>
<p>For this contest I will build a chat and messaging app for TriMet passengers who are riding the same bus or route.  It will be targeted at riders with tablets and smartphones and use the TriMet route and arrival data to enable social interactions between passengers.</p>
<h2>Leave a message/comments</h2>
<p>Passengers will be able to leave message or comments that will be visible to other people riding the same bus or route.  They could be used for lost and found or &#8220;missed connection&#8221; type communication.  They will be public, archived and searchable.</p>
<h2>Chat</h2>
<p>There will also be the option of partaking in a chatroom or private instant messaging with other people riding the same bus or route.  There should be some expectation of privacy/anonymity for users.</p>
<h2>Flirting</h2>
<p>The third element of the app will be to facilitate romantic interaction between riders that <strong><em>opt in</em></strong>.  People that are interested in meeting other passengers can activate a &#8220;flirt&#8221; mode, that will enable private messaging between interested parties.  Users will only be identified by age/gender/sexual preference.</p>
<h2>Requirements</h2>
<p>seatMate will  be a mobile html5/javascript web application and also available as a native Android/iOS app from the app stores.  It should:</p>
<ul>
<li>be fast and interactive</li>
<li>use geolocation to determine route information</li>
<li>have push notifications or sms</li>
<li>allow image uploading/sharing</li>
<li>deployable to cloud hosting (ideally at the freemium level)</li>
</ul>
<h2>Links</h2>
<h3>repo</h3>
<p>The contest specifies that the app must be available as a public repository.  I&#8217;ll be using git and host the code on github.  This will allow for public issue tracking and enable anyone to fork the repo and submit code through github pull requests.</p>
<p><a href="https://github.com/eknuth/seatMate" target="_blank">https://github.com/eknuth/seatMate</a></p>
<h3>trello</h3>
<p>For project management, I&#8217;ll be keeping big picture task information in Fog Creek&#8217;s trello app.  It&#8217;ll be public and allow voting and comments.</p>
<p><a href="https://trello.com/board/seatmate/4f081075ffd434f16d04b1bc" target="_blank">https://trello.com/board/seatmate/4f081075ffd434f16d04b1bc</a></p>
<h3>blog</h3>
<p>I will be blogging about the process on this site using the seatMate tag.</p>
<p><a href="http://iknuth.com/tag/seatMate/" target="_blank">http://iknuth.com/tag/seatMate/</a></p>
<p>Feel free to follow along and participate as much as you like.  I&#8217;m hoping that this will be a fun month!</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2012/01/trimet-app-contest-entry-seatmate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>exploring redis in node.js using the mocha testing framework</title>
		<link>http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2</link>
		<comments>http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/#comments</comments>
		<pubDate>Sat, 17 Dec 2011 19:58:49 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[mocha]]></category>
		<category><![CDATA[node.js]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=443</guid>
		<description><![CDATA[overview node.js Node is currently the cool kid of the web dev scene and is starting to take over.  Node is the project that lets you run javascript on the server side in a super fast v8 based vm.  Out &#8230; <a href="http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><h1>overview</h1>
<h2>node.js</h2>
<p><a href="http://nodejs.org/">Node</a> is currently the cool kid of the web dev scene and is starting to take over.  Node is the project that lets you run javascript on the server side in a super fast v8 based vm.  Out of the gate, it is evented/async, non blocking and ridiculously fast.  Javascript has a lot of haters, but it is undeniably an interesting and powerful language.   The node community is thriving and mature.  The tools are awesome and it is a blast to use.</p>
<h2>redis</h2>
<p><a href="http://redis.io/">redis</a> is amazing. It is one of the stars of the nosql movement. It is a server that stores strings, lists, sets and hashes. If that isn&#8217;t even it also lets you do publisher/subscriber to trigger events. It is a natural fit for node and if you try it, you&#8217;ll like it.</p>
<h2>mocha</h2>
<p><a href="http://visionmedia.github.com/mocha/">Mocha</a> is the latest generation of node/js test frameworks by <a href="http://tjholowaychuk.com/">TJ Holowaychuk</a>. It is fast and allows for incredibly easy asynchronous testing. It supports standard assertions as well as bdd style tests using should.</p>
<h1>setup node and mocha</h1>
<p>This gist uses <a href="http://mxcl.github.com/homebrew/">homebrew</a> to install node. OSX has great support for node and homebrew is by far the best package manager. npm is among other things the command to install node packages. We&#8217;re using the -g flag to npm to install the package globally, otherwise it would be installed for just this project.</p>
<div id="gist-1491206" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c"># install node </span></div><div class='line' id='LC2'>brew install node</div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="c"># install redis</span></div><div class='line' id='LC5'>brew install redis</div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'><span class="c"># install npm</span></div><div class='line' id='LC8'>curl http://npmjs.org/install.sh | sh</div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><span class="c"># install mocha and should for testing</span></div><div class='line' id='LC11'>npm install mocha should -g</div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'><span class="c"># install node-redis to talk with redis</span></div><div class='line' id='LC14'>npm install redis</div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'><span class="c"># create the first test</span></div><div class='line' id='LC17'>mkdir <span class="nb">test</span></div><div class='line' id='LC18'>touch <span class="nb">test</span>/test_redis.js</div><div class='line' id='LC19'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1491206/7434866ee82285cd135b4615d71558304a73a5a6/setup.sh" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1491206#file_setup.sh" style="float:right;margin-right:10px;color:#666">setup.sh</a>
            <a href="https://gist.github.com/1491206">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Now, if you type &#8220;mocha&#8221; at the command line, it will execute the non existent tests in our test directory and return the results. Since we have no tests, it should look something like this:<br />
<a href="http://iknuth.com/wp-content/uploads/2011/12/Screen-shot-2011-12-17-at-10.19.38-AM.png"><img class="aligncenter size-full wp-image-429" title="zero tests with mocha" src="http://iknuth.com/wp-content/uploads/2011/12/Screen-shot-2011-12-17-at-10.19.38-AM.png" alt="" width="201" height="43" /></a></p>
<h2>Async testing with mocha and should</h2>
<p>The following gist is a basic asynchronous test using mocha and the <a href="https://github.com/visionmedia/should.js">should</a> bdd style assertion library. Async tests can be challenging because you are testing things that happen at various times. We are going to set a key and make sure the callback function gets called without an error.</p>
<p>Generally that is hard, but mocha gives us a sweet little callback called done that we can pass to our redis set command. It ensures that the callback happens successfully and no errors are passed. If you&#8217;ve done async testing in the pass, you will probably be amazed at how painless it is to do it like this.</p>
<p>In the second test we are going to retrieve the key we just set and explicitly test the value in the callback. To make sure the async happens as we expect, we manually call done() after our assertions.<br />
<div id="gist-1491206" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">var</span> <span class="nx">redis</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">&quot;redis&quot;</span><span class="p">),</span></div><div class='line' id='LC2'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">should</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;should&#39;</span><span class="p">),</span></div><div class='line' id='LC3'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">client</span> <span class="o">=</span> <span class="nx">redis</span><span class="p">.</span><span class="nx">createClient</span><span class="p">();</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'><span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;strings in redis&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="kd">var</span> <span class="nx">keyToSet</span> <span class="o">=</span> <span class="s1">&#39;bingo&#39;</span><span class="p">,</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">valueToSet</span> <span class="o">=</span> <span class="s1">&#39;the dog&#39;</span><span class="p">;</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;#set()&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should save without error&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">client</span><span class="p">.</span><span class="nx">set</span><span class="p">(</span><span class="nx">keyToSet</span><span class="p">,</span> <span class="nx">valueToSet</span><span class="p">,</span> <span class="nx">done</span><span class="p">);</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">describe</span><span class="p">(</span><span class="s1">&#39;#get()&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">it</span><span class="p">(</span><span class="s1">&#39;should be able to get the value we set&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">client</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="nx">keyToSet</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">should</span><span class="p">.</span><span class="nx">not</span><span class="p">.</span><span class="nx">exist</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">data</span><span class="p">.</span><span class="nx">should</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span><span class="nx">valueToSet</span><span class="p">);</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">done</span><span class="p">();</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">});</span></div><div class='line' id='LC27'><span class="p">});</span></div><div class='line' id='LC28'><br/></div><div class='line' id='LC29'><br/></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1491206/17fc274ae8ff31574ae91f07160ddd9e641eb446/test/test_redis.js" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1491206#file_test/test_redis.js" style="float:right;margin-right:10px;color:#666">test/test_redis.js</a>
            <a href="https://gist.github.com/1491206">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>
<br />
If we didn&#8217;t call done, the test would hang until it times out. When called correctly we should get a result like this.<br />
<a href="http://iknuth.com/wp-content/uploads/2011/12/Screen-shot-2011-12-17-at-11.22.57-AM.png"><img class="aligncenter size-full wp-image-433" title="Screen shot 2011-12-17 at 11.22.57 AM" src="http://iknuth.com/wp-content/uploads/2011/12/Screen-shot-2011-12-17-at-11.22.57-AM.png" alt="" width="207" height="56" /></a><br />
As you can see, 3 milliseconds is not bad for a couple of async tests. It definitely beats setting a clock and waiting for it to run out!</p>
<p>Just remember to <a href="http://ryanflorence.com/2011/2012/case-against-coffeescript/" target="_blank">say &#8220;no&#8221; to coffee script</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2011/12/exploring-node-redis-in-node-js-using-the-mocha-testing-framework-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>deploying a django app to heroku with easy static files on s3</title>
		<link>http://iknuth.com/2011/10/deploying-a-django-app-to-heroku-with-easy-static-files-on-s3/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=deploying-a-django-app-to-heroku-with-easy-static-files-on-s3</link>
		<comments>http://iknuth.com/2011/10/deploying-a-django-app-to-heroku-with-easy-static-files-on-s3/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 20:29:40 +0000</pubDate>
		<dc:creator>edwin</dc:creator>
				<category><![CDATA[technology]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://iknuth.com/?p=383</guid>
		<description><![CDATA[django and s3 This project doesn&#8217;t necessarily require heroku, but I&#8217;ve been interested in the service as an easy way to deploy apps. I really like the idea of not having to set up a server with nginx, postgres, gunicorn, &#8230; <a href="http://iknuth.com/2011/10/deploying-a-django-app-to-heroku-with-easy-static-files-on-s3/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<img style='float: left; margin-right: 10px; border: none;' src='http://www.gravatar.com/avatar.php?gravatar_id=9e27ba264dccbe5149fd08b17f5bdeb1&amp;default=http://use.perl.org/images/pix.gif' alt='No Gravatar' width=40 height=40/><h1>django and s3</h1>
<p>This project doesn&#8217;t necessarily require heroku, but I&#8217;ve been interested in the service as an easy way to deploy apps. I really like the idea of not having to set up a server with nginx, postgres, gunicorn, etc.  The convenience of deploying just by pushing from git is awesome.  </p>
<p>One issue I ran into was a problem with serving static content like css, javascript and image files from heroku.  I&#8217;m sure it is just a configuration problem, but this solution of using s3 to serve those files is the way you want to go in the long run.</p>
<p>You can clone my sample project from <a href="https://github.com/eknuth/django-heroku-s3-bootstrap-demo">github</a>.</p>
<p><code>git clone git@github.com:eknuth/django-heroku-s3-bootstrap-demo.git</code></p>
<h2>Django on Heroku</h2>
<p>Heroku used to be limited to ruby apps, but it has recently become much more flexible with the addition of the cedar stack.  Now it supports python 2.7 and uses pip to install modules from a standard requirements.txt file.  They have also started offering a free 5mb postgresql db to go along with their current freemium offering, which is fantastic.  That doesn&#8217;t sound like a lot of space, but you&#8217;d be surprised how much information you can cram into 5 mb.</p>
<h2>Initial Setup</h2>
<p>You can follow the django instructions from heroku here:<br />
<a href="http://devcenter.heroku.com/articles/django">http://devcenter.heroku.com/articles/django</a></p>
<p>If you are using macosx, or virtualenv uses python 2.6 by default, I would suggest specifying 2.7 when you create the environment.  Heroku is using 2.7 and will complain about pip installing importlib which was not included by default in python 2.6.</p>
<p><code>virtualenv --no-site-packages . -p /usr/local/bin/python2.7<br />
</code><br />
Open the site on heroku using the &#8220;heroku open&#8221; command and verify that you get the django welcome screen.  You should have no urls configured.</p>
<h2>Admin and Static Files</h2>
<p>You should now have a working empty project.  Let&#8217;s turn on the django admin app and fire up the development server.</p>
<p>As a side note, this config will import settings from settings_local.py, if it exists and overwrite the ones in settings.py.  This local settings file is not committed to the repo and won&#8217;t get deployed to heroku.</p>
<p>Follow the instructions to <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/" target="_blank">install the django admin app</a> and then run manage.py syncdb and then runserver.  If everything went ok, you should be able to log in to your admin console.</p>
<p>Now, commit and push your app to heroku.  Run the manage.py commands on heroku and magically your admin console is live on the web.</p>
<h2>Twitter Bootstrap and view</h2>
<p>Now, lets getting started with a template and a home view.  We can use the totally awesome <a href="http://twitter.github.com/bootstrap/" target="_blank">twitter bootstrap project</a>.  They have released a site/webapp html template, css and javascript package that provides everything you need to get started.  It is great for those that are less inclined to design.</p>
<p>Create a templates folder in your project root.  Clone the project from github and copy hero.html from the examples directory into your new templates directory.</p>
<h3>@render_to</h3>
<p>Now let&#8217;s create a view and wire up that template to a url.  Now is the time to add on a django project that will make things easier for us.  I really love the render_to decorator from <a href="https://bitbucket.org/offline/django-annoying/wiki/Home" target="_blank">django-annoying</a>.  Run &#8220;pip install django-annoying&#8221;, and it will be ready to go.  Don&#8217;t forget to save your updated requirements with a &#8220;pip freeze &gt;requirements.txt&#8221;.</p>
<h3>relative paths</h3>
<p>Add the template dir and a little snippet of python to use relative paths.  This will make life easier in the future.<br />
<script src="https://gist.github.com/1289991.js?file=settings.py"></script> In the urls.py file, uncomment the following home view:  url(r&#8217;^$&#8217;, &#8216;om.views.home&#8217;, name=&#8217;home&#8217;),  And create a views.py file to grab the template and render it.  <script src="https://gist.github.com/1289996.js?file=views.py"></script></p>
<p>Now when you open the app on your development server, you get an actual &#8220;hello world&#8221; page.  Unfortunately we are missing the css file, so it is unstyled.  In your root project, create a static folder and inside that create another folder named css.  Copy bootstrap.css into static/css.</p>
<p>To reference this css file, edit hero.html and change the line with bootstrap.css to this:<br />
<code><br />
&lt;link href="{{ STATIC_URL }}css/bootstrap.css" rel="stylesheet"&gt;<br />
</code><br />
In order to make the STATIC_URL template tag work, we need to update STATICFILES_DIRS in settings.py to:<br />
<code><br />
STATICFILES_DIRS = (        os.path.join(SITE_ROOT, 'static'),)<br />
</code></p>
<p>We also need add some template context processors with this:<br />
<code><br />
TEMPLATE_CONTEXT_PROCESSORS = (<br />
'django.contrib.messages.context_processors.messages',<br />
'django.contrib.auth.context_processors.auth',<br />
'django.core.context_processors.static',<br />
)<br />
</code></p>
<p>When we open the page served from our development server, we are good to go.  The page is styled and looks awesome.</p>
<h2>Static Files on Heroku</h2>
<p>Unfortunately when we push to heroku and open the page, we are back to the our css free look.  Seems like heroku has no problem serving up the admin static files, but it has a problem finding our static directory.  I&#8217;m sure it is just a matter of configuration, but honestly we really don&#8217;t want to use our application server to serve up static files anyway.  Images, css and javascript should all be coming out of something fast and light.</p>
<h2>Enter S3</h2>
<p>Amazon provides an excellent service for doing just that.  Amazon&#8217;s web services and the simple storage system are cheap and easy to use.  There is also an excellent module for using s3 with django&#8217;s static files app and the collectstatic management command with s3 as a backend.  <a href="http://code.welldev.org/django-storages/">django-storages</a> makes it incredibly simple to use s3 for our static files.</p>
<h3>django-storages and boto</h3>
<p>First we want to install the module with &#8220;pip install django-storages&#8221; and add &#8216;storages&#8217; to your INSTALLED_APPS tuple and set your storage type with:<br />
<code><br />
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'<br />
</code><br />
We will also need to install boto, the python module for dealing with s3.  Use &#8220;pip install boto&#8221; for that.<br />
Log in to the amazon web services management console and create a new bucket.  Add the name of the bucket and your access keys to settings.py like this:<br />
<code><br />
AWS_ACCESS_KEY_ID = 'ACCESS KEY'<br />
AWS_SECRET_ACCESS_KEY = 'SECRET'<br />
AWS_STORAGE_BUCKET_NAME = 'django-blog<br />
</code></p>
<h3>set up the s3 bucket</h3>
<p>Look at the bucket properties and grab the url for the bucket.  Update your STATIC_URL setting to point to the bucket.  In this case it will look like this:<br />
<code><br />
STATIC_URL = 'https://s3.amazonaws.com/django-blog/'<br />
</code></p>
<h3>deployment</h3>
<p>Now run manage.py collectstatic and you will see all the files being copied to your bucket.  Freeze your requirements file and commit your repo.  Now when you push to heroku, you should see your website with the bootstrap.css file pulled from s3.</p>
]]></content:encoded>
			<wfw:commentRss>http://iknuth.com/2011/10/deploying-a-django-app-to-heroku-with-easy-static-files-on-s3/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

