<?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>Kickass Labs &#187; Javascript</title>
	<atom:link href="http://www.kickasslabs.com/category/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kickasslabs.com</link>
	<description>We &#9829; code.</description>
	<lastBuildDate>Wed, 28 Dec 2011 16:57:56 +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>Yet Another Backbone.js Tutorial – Part 2 – Pre-Reqs &amp; The Spec</title>
		<link>http://www.kickasslabs.com/2011/11/27/yet-another-backbone-js-tutorial-%e2%80%93-part-2-%e2%80%93-prereqs-and-the-spec/</link>
		<comments>http://www.kickasslabs.com/2011/11/27/yet-another-backbone-js-tutorial-%e2%80%93-part-2-%e2%80%93-prereqs-and-the-spec/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 04:50:01 +0000</pubDate>
		<dc:creator>abel</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[underscore.js]]></category>

		<guid isPermaLink="false">http://www.kickasslabs.com/?p=529</guid>
		<description><![CDATA[Please checkout Part 1 where I explain the philosophy behind Backbone.js It&#8217;s time to build our Backbone.js app, &#8220;Comment on the Movies&#8221;.  This tutorial will, ideally, give you something interesting to build.  Take a look at the finished app (so far) on &#8230; <a href="http://www.kickasslabs.com/2011/11/27/yet-another-backbone-js-tutorial-%e2%80%93-part-2-%e2%80%93-prereqs-and-the-spec/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em><a title="Yet Another Backbone.js Tutorial – Part 1 – Backbone.js Philosophy" href="http://www.kickasslabs.com/2011/04/16/yet-another-backbone-js-tutorial-part-1-backbone-js-philosophy/">Please checkout <strong>Part 1</strong> where I explain the philosophy behind Backbone.js</a></em></p>
<p>It&#8217;s time to build our Backbone.js app, &#8220;Comment on the Movies&#8221;.  This tutorial will, ideally, give you something interesting to build.  Take a look at <strong><a href="http://commentonthemovies.heroku.com" target="_blank">the finished app (so far) on Heroku</a></strong> &amp; feel free to <strong><a href="https://github.com/abelmartin/Comment-On-The-Movies/tree/KAL_Post_Part_2" target="_blank">pull it from GitHub</a></strong>.  In addition, I&#8217;ve updated the code to use Backbone.js 0.5.3, Underscore 1.2.2, Mustache 0.3 &amp; jQuery 1.7.1.  Let&#8217;s do this!<span id="more-529"></span></p>
<p>*Before we get started, check out one more resource: Charlie Robbins (Co-Founder of <a href="http://nodejitsu.com/" target="_blank">Nodejitsu</a>) wrote an awesome article about <a href="http://blog.nodejitsu.com/scaling-isomorphic-javascript-code" target="_blank">Scaling Isomorphic Javascript Code</a>.  In the writeup, he describes popular methodologies in retrieving data and presenting it to the user.  It&#8217;s a great read.  The image below from that article:</p>
<div class="wp-caption aligncenter" style="width: 450px"><img src="http://blog.nodejitsu.com/scaling-isomorphic-javascript-code/mvvm.png" alt="" width="440" height="369" /><p class="wp-caption-text">Backbone.js interactions: Model-View-ViewModel</p></div>
<h2>Prerequisites:  Rotten Tomatoes API Account, Ruby, Sinatra, &amp; Haml</h2>
<h3>Rotten Tomatoes API Account</h3>
<p>The app we&#8217;re writing is called &#8220;Comment On The Movies&#8221;.  The RottenTomatoes API is full of well formed data (which is more than I can say about the New York Times movie api calls).  Real data is always more interesting than building dummy datasets ourselves.</p>
<p><strong><a href="http://developer.rottentomatoes.com/" target="_blank">The Rotten Tomatoes API registration is free, quick &amp; painless</a></strong>.  Get your api_key &amp; come back to this tutorial.</p>
<p>We&#8217;ll also be using <strong><a href="http://images.rottentomatoes.com/assets.html" target="_blank">the R.T. assets</a></strong>.  R.T. makes their images available to developers to use in their apps and we&#8217;ll be taking advantage.</p>
<h3>Ruby (<a href="http://www.ruby-lang.org/en/" target="_blank">Project Site</a>)</h3>
<p>Realistically, if you&#8217;re reading this webpage, you probably already have it installed (even if you don&#8217;t use it) <img src='http://www.kickasslabs.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> .  I chose Ruby here because I 9-5 in Ruby and I really enjoy it.  You can use ANY server side scripting language here (PHP, Asp.NET, JSP), but <span style="text-decoration: underline;"><strong>you need to use something</strong></span>. You don&#8217;t want to simply expose your R.T. API App Key to the world.  By using a server side language, you can create a proxy page that protects your API App Key.  Here&#8217;s how this app will work:</p>
<ol>
<li>Your Backbone app makes an AJAX call with R.T. API parameters to the proxy page</li>
<li>The proxy page appends your API_KEY &amp; makes the call to a R.T. servers</li>
<li>The proxy page receives the response and returns it to your Backbone app</li>
<li>The Backbone app updates it&#8217;s UI.</li>
</ol>
<h3>Sinatra (<a href="http://www.sinatrarb.com/intro" target="_blank">Project Site</a>)</h3>
<p>Since we only need an index page and a proxy, Sinatra is a perfect option here.  A full Rails app would be WAY too much.</p>
<h3>Haml (<a href="http://haml-lang.com/" target="_blank">Project Site</a>)</h3>
<p>I enjoy haml.  It&#8217;s really easy to create markup with it.</p>
<h2>The &#8220;Comment on the Movies&#8221; Spec</h2>
<p>Here&#8217;s what the app needs to accomplish:<br />
<span style="color: #ff6600;">**Items in orange will be implemented in future tutorial posts**</span></p>
<ul>
<li>Users should be able to switch between the various lists of R.T. data:</li>
<ul>
<li>Box Office (default view on page load)</li>
<li>In Theaters</li>
<li>Opening</li>
<li>Upcoming</li>
</ul>
<li>The &#8220;Movies Table&#8221; should display:
<ul>
<li>Title</li>
<li>Year</li>
<li>MPAA Rating (R, PG-13, etc)</li>
<li>Runtime</li>
<li>Release Date (default sort)</li>
<li>Critic&#8217;s Score</li>
<ul>
<li>If it&#8217;s &#8216;certified fresh&#8217; that should be indicated.</li>
</ul>
<li><span style="color: #ff6600;">Number of comments</span></li>
</ul>
</li>
<li><span class="Apple-style-span" style="color: #000000;">Clicking on a table column title should sort the current set of movies in the table.</span></li>
<li><span style="color: #ff6600;">Clicking on a movie&#8217;s row should take you to a &#8220;detailed&#8221; view of the film.  The &#8220;detailed&#8221; view should display: </span>
<ul>
<li><span style="color: #ff6600;">Links [all links that lead us away from the site should open in a new window] to&#8230;</span>
<ul>
<li><span style="color: #ff6600;">Showtimes</span></li>
<li><span style="color: #ff6600;">Awards (if any)</span></li>
<li><span style="color: #ff6600;">Trailers</span></li>
<li><span style="color: #ff6600;">Abridged Cast</span></li>
<li><span style="color: #ff6600;">IMDB records</span></li>
</ul>
</li>
</ul>
</li>
<li><span style="color: #ff6600;">Comments </span>
<ul>
<li><span class="Apple-style-span" style="color: #ff6600;">Add a new comment</span></li>
<li><span class="Apple-style-span" style="color: #ff6600;">Edit an existing comment</span></li>
<li><span class="Apple-style-span" style="color: #ff6600;">Delete a comment</span></li>
<li><span class="Apple-style-span" style="color: #ff6600;">Require that the review indicates if the comment is BEFORE or AFTER you&#8217;ve seen the movie</span></li>
<li><span class="Apple-style-span" style="color: #ff6600;">Comments should persists across browser restarts</span></li>
</ul>
</li>
<li>The app needs to be crawl-able by Google.</li>
<li><span style="color: #ff6600;">It needs to be well tested</span></li>
</ul>
<h2>Make your Backbone App Google Crawl-able via hashbang URLs</h2>
<p>Hashbanging (/#!) your URLs let&#8217;s the <a href="http://code.google.com/web/ajaxcrawling/docs/getting-started.html">Google crawling bot know that there&#8217;s AJAXed content on this page</a>.  Fortunately, it&#8217;s really easy in Backbone.js <a href="http://commentonthemovies.heroku.com/" target="_blank">as you can see in the live demo</a></p>
<h2>In The Next Post&#8230;</h2>
<p>I&#8217;ll explain how I implemented the app thus far.  That&#8217;ll include the filling the index view &amp; the hashbang technique mentioned above.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.kickasslabs.com%2F2011%2F11%2F27%2Fyet-another-backbone-js-tutorial-%25e2%2580%2593-part-2-%25e2%2580%2593-prereqs-and-the-spec%2F&amp;title=Yet%20Another%20Backbone.js%20Tutorial%20%E2%80%93%20Part%202%20%E2%80%93%20Pre-Reqs%20%26%23038%3B%20The%20Spec" id="wpa2a_2"><img src="http://www.kickasslabs.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kickasslabs.com/2011/11/27/yet-another-backbone-js-tutorial-%e2%80%93-part-2-%e2%80%93-prereqs-and-the-spec/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Yet Another Backbone.js Tutorial &#8211; Part 1 &#8211; Backbone.js Philosophy</title>
		<link>http://www.kickasslabs.com/2011/04/16/yet-another-backbone-js-tutorial-part-1-backbone-js-philosophy/</link>
		<comments>http://www.kickasslabs.com/2011/04/16/yet-another-backbone-js-tutorial-part-1-backbone-js-philosophy/#comments</comments>
		<pubDate>Sun, 17 Apr 2011 02:18:19 +0000</pubDate>
		<dc:creator>abel</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[underscore.js]]></category>

		<guid isPermaLink="false">http://www.kickasslabs.com/?p=513</guid>
		<description><![CDATA[At my new job I'm getting pretty friendly with Backbone.js. This 2-part post will teach you some backbone basics &#038; show you how to create your own backbone.js app with multiple routes. <a href="http://www.kickasslabs.com/2011/04/16/yet-another-backbone-js-tutorial-part-1-backbone-js-philosophy/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h2>A couple of house keeping notes</h2>
<p>It&#8217;s been a while since our last post.  Gabe&#8217;s been hard at work in Australia, hacking on a number of things.  Rebecca &amp; Brad have large, awesome projects in the works.  Meanwhile  I&#8217;ve switched jobs a couple of times <img src='http://www.kickasslabs.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .  All the while, we&#8217;ve been coding like mad and learning a ton of interesting things.  While I can&#8217;t promise that we&#8217;ll &#8220;turn the posting faucet back on&#8221;, I can say that we&#8217;ll try to reduce the big draughts.  Now then, on to the show!</p>
<h2>Backbone.js Philosophy (as I see it)</h2>
<p>I&#8217;ve been getting pretty friendly with Backbone.js lately.  This 2-part post will teach you some backbone basics &amp; show you how to create your own backbone.js app with multiple routes.<span id="more-513"></span></p>
<p>Before we begin, take a look at some of these other tutorials to get a sense of what we&#8217;re about to do.  I learned a LOT from them:</p>
<ul>
<li><a href="http://documentcloud.github.com/backbone/" target="_blank">Document Cloud&#8217;s backbone.js framework documentation</a></li>
<li><a href="http://documentcloud.github.com/backbone/examples/todos/index.html" target="_blank">Jérôme Gravel-Nique&#8217;s &#8221;Todo list&#8221; example</a></li>
<li><a href="http://www.plexical.com/blog/2010/11/18/backbone-js-tutorial/" target="_blank">The Meta Cloud&#8217;s backbone tutorial</a></li>
<li><a href="http://liquidmedia.ca/blog/2011/01/backbone-js-part-1/" target="_blank">Liquid Media&#8217;s backbone tutorial (3 parts)</a></li>
<li><a href="http://www.elfsternberg.com/2010/12/08/backbonejs-introducing-backbone-store/" target="_blank">Elf Sternberg&#8217;s backbone tutorial</a></li>
<li><a href="http://www.jamesyu.org/2011/01/27/cloudedit-a-backbone-js-tutorial-by-example/" target="_blank">James Yu&#8217;s tutorial</a></li>
<li><a href="http://fleetventures.com/2011/02/08/quiet-clarity" target="_blank">David Richard&#8217;s thoughts on backbone.js</a></li>
</ul>
<p>The most important thing to understand about a Backbone.js app is the separations of concerns.  Each of the parts below can do even more than what I&#8217;m describing, but here&#8217;s the minimum of what you need to know about them.</p>
<h3>Models and Collections (an array of models)</h3>
<ul>
<li>knows how to speak to the data source (both restful resources and api calls).</li>
<li>can <a href="http://documentcloud.github.com/backbone/#Model-parse" target="_blank">parse data</a> before handed responses off to a view.</li>
</ul>
<h3>Views</h3>
<ul>
<li>knows how to display your models and collections.  You define the markup rules in the <a href="http://documentcloud.github.com/backbone/#View-render" target="_blank">render method</a></li>
<li>handles events (clicks, changes to markup, changes to models) and changes the markup appropriately.</li>
<li>can initialize your js plugins that should be attached to markup.</li>
</ul>
<p>Gabe had this to say about views:</p>
<p style="padding-left: 30px;">&#8220;I see two ways to use backbone views:</p>
<p style="padding-left: 30px;">1. A view can be bound directly to a model or collection.  Whenever that model/collection changes, the view would re-call it’s render method and redraw itself. In essence, the view’s job is to represent a model’s state in the DOM now.  Also keep in mind that the model doesn’t have to be something bound to your db.</p>
<p style="padding-left: 30px;">2. A view can be more of a <span style="text-decoration: underline;"><strong>stateful widget</strong></span> that remembers some of its own state.  In this widget style, the view would keep track of some state and maybe decide what parts of itself it should show/hide depending on its state.</p>
<p style="padding-left: 30px;">In conclusion, the two view philosophies are very similar:</p>
<p style="padding-left: 30px;">- one is more modular<br />
- one is more monolithic</p>
<p style="padding-left: 30px;"><strong>The view can be an island OR it can be obsessed with something.</strong>&#8220;</p>
<p>Thanks Gabe! <img src='http://www.kickasslabs.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>Controllers/Router</h2>
<ul>
<li>handle all of your &#8216;#&#8217; routes.</li>
<li>the app is started by creating a new instance of this class.</li>
<li>your app only needs 1 controller/router</li>
</ul>
<h2>[5/7/2011 : Amendment]  A quick word about markup</h2>
<p>In a Backbone app you&#8217;ll have markup that lives on your page (index.html) &amp; markup that you&#8217;ll need to generate as new elements are added (This will become clearer when you see our tutorial app in action in the next post).  While Backbone gives you <a href="http://documentcloud.github.com/backbone/#View-make" target="_blank">view.make()</a> to create markup, you&#8217;ll want to use a templating library to help you out with more complicated stuff.  A fellow KAL member recently how I draw the line between what markup lives on the page and what markup lives in a template.</p>
<p><span style="text-decoration: underline;"><strong>My Rule</strong></span>: If the markup has an <span style="text-decoration: underline;"><strong>ID</strong></span>, then it should live on the <span style="text-decoration: underline;"><strong>page</strong></span>.  By maintaing this idea, you can create your page layout in it&#8217;s empty state.  The Views that you create will attach to ID&#8217;ed elements to dynamically fill/update them as events occur.  Also, with Backbone, you don&#8217;t need to have markup that contain the object&#8217;s ID (&#8220;foo_1&#8243;, &#8220;foo_2&#8243;, &#8220;foo_3&#8243;, etc).  The <span style="text-decoration: underline;"><strong>object is bound to the markup</strong></span> (if you do it correctly) which removes the need to parse it out of the ID in the markup (or other well known chicanery that we&#8217;ve all done at one point or another <img src='http://www.kickasslabs.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ).  It&#8217;s often better to have your template markup use the &#8216;class&#8217; attribute declaration since they&#8217;re best used when you&#8217;re representing models in a collection.  This also fits with the W3C&#8217;s HTML spec which says that an ID/Name &#8220;<a href="http://www.w3.org/TR/html40/struct/global.html#h-7.5.2" target="_blank">must be unique in a document</a>&#8220;.</p>
<p>Consider my rule when constructing a table (the tutorial app will do this):  The table&#8217;s markup lives on the page with an ID (id=&#8221;MoviesTable&#8221;) without any rows.  We&#8217;ll generate/update the rows (class=&#8221;movie&#8221;) of the table on the fly via a template fueled by my View&#8217;s Collection.  The Collection is filled by the response from our movie API.</p>
<h2>That&#8217;s a lot to digest</h2>
<p>Stay tuned for Part 2 where we&#8217;ll build our app, &#8220;Comment on the Movies&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kickasslabs.com/2011/04/16/yet-another-backbone-js-tutorial-part-1-backbone-js-philosophy/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Google Maps events in Mobile Safari and PhoneGap for iPhone</title>
		<link>http://www.kickasslabs.com/2009/04/29/google-maps-events-in-mobile-safari-and-phonegap-for-iphone/</link>
		<comments>http://www.kickasslabs.com/2009/04/29/google-maps-events-in-mobile-safari-and-phonegap-for-iphone/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 20:23:27 +0000</pubDate>
		<dc:creator>Brad</dc:creator>
				<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Events]]></category>
		<category><![CDATA[gmaps]]></category>

		<guid isPermaLink="false">http://www.kickasslabs.com/?p=255</guid>
		<description><![CDATA[Having trouble getting your Google Maps div to respond to events like you want in Mobile Safari or a PhoneGap app for iPhone? So was I. Disabling pinch-zoom is simple enough, but getting a finger drag to (a) not move &#8230; <a href="http://www.kickasslabs.com/2009/04/29/google-maps-events-in-mobile-safari-and-phonegap-for-iphone/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Having trouble getting your <a href="http://code.google.com/apis/maps/" target="gmaps" title="Google Maps">Google Maps</a> div to respond to events like you want in Mobile Safari or a <a href="http://www.phonegap.com/" target="phonegap" title="PhoneGap">PhoneGap</a> app for iPhone?  So was I.  Disabling pinch-zoom is simple enough, but getting a finger drag to (a) not move the map and (b) draw something on the map was a major pain.  I share my solution below:  Proxying events through a transparent div overlaid on the Google Maps div.</p>
<p>To play along at home, you&#8217;ll need your own <a href="http://code.google.com/apis/maps/signup.html" target="gmaps_key" title="Google Maps API Key signup">Google Maps key</a> or you can just aim your mobile browser to my <a href="http://kickasslabs.com/examples/gmap_events.html" target="gmaps_example" title="Google Maps Event Proxying Example">example code at http://kickasslabs.com/examples/gmap_events.html</a>.  (Note that this will <i>not</i> work in a regular desktop browser.)  Besides a <tt>&lt;script&gt;</tt> tag importing the GMaps JavaScript, you should not need any other libraries or tools besides Mobile Safari to view and use the example page.  If the page is zoomed way out when you start, just double-tap the map tile in the upper-left corner &#8211; it should zoom to fill your viewport.</p>
<p>What you should see is a map tile with a line painted on it.  If you touch the screen, you should see one end of the line follow your finger.</p>
<p>It looks simple but I had a bit of trouble getting it to work, because touch events are not like mouse events (curious as to <a href="http://www.quirksmode.org/blog/archives/2008/08/iphone_events.html" target="mouse_vs_touch" title="Mouse vs. Touch">why?</a>), and GMaps doesn&#8217;t respond to touch events by default.</p>
<p><b>Step by Step</b></p>
<p>First, you need 2 divs:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    &lt;!-- This div holds our map --&gt;
    &lt;div id=&quot;map&quot; style=&quot;width: 320; height: 320px&quot;&gt;&lt;/div&gt;
&nbsp;
    &lt;!-- This div lies on top of the map and acts as an event proxy --&gt;
    &lt;div id=&quot;mapoverlay&quot; style=&quot;height:320px; width: 320px; position: absolute;&quot;&gt;&lt;/div&gt;</pre></div></div>

<p>And you need to position one div over the other:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    mapDiv = document.getElementById('map');
    mapOverlayDiv = document.getElementById('mapoverlay');
    mapOverlayDiv.style.top = (mapDiv.offsetTop + 0) + 'px';
    mapOverlayDiv.style.left = (mapDiv.offsetLeft + 0) + 'px';</pre></div></div>

<p>You set up the map div like you would for any other GMaps-enabled page:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    // the map
    _map = new GMap2(document.getElementById(&quot;map&quot;));
&nbsp;
    // coordinates for home base
    _lat = 37;
    _lng = -95;
    mapCenter = new GLatLng(_lat, _lng);
    _map.setCenter(mapCenter, 15);</pre></div></div>

<p>Set up the overlay div to respond to touch events by firing a custom event for your map, e.g.:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    mapOverlayDiv.ontouchstart = function(e) {
      GEvent.trigger(_map, 'customTouchStart',
        (e.touches[0].pageX - mapDiv.offsetLeft),
        (e.touches[0].pageY - mapDiv.offsetTop));
    }</pre></div></div>

<p>Now have your map respond to that event:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    GEvent.addListener(_map, 'customTouchStart', mapTouchStart);</pre></div></div>

<p>&#8230;where <tt>mapTouchStart</tt> is a callback function that does something useful in response to a touch:</p>

<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">    function mapTouchStart(xPixel, yPixel) {
      redrawLine(xPixel, yPixel);
    }</pre></div></div>

<p>And&#8230; well, then you&#8217;re done.  My example also responds to the touchMove event and has a little code for drawing lines, but you&#8217;ve seen all you need to know to get event proxying up and running for your app.</p>
<p>Got a question?  Got working code for an easier way?  Drop me a line in the comments!</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.kickasslabs.com%2F2009%2F04%2F29%2Fgoogle-maps-events-in-mobile-safari-and-phonegap-for-iphone%2F&amp;title=Google%20Maps%20events%20in%20Mobile%20Safari%20and%20PhoneGap%20for%20iPhone" id="wpa2a_4"><img src="http://www.kickasslabs.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kickasslabs.com/2009/04/29/google-maps-events-in-mobile-safari-and-phonegap-for-iphone/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Quick and Dirty Messaging</title>
		<link>http://www.kickasslabs.com/2008/11/22/93/</link>
		<comments>http://www.kickasslabs.com/2008/11/22/93/#comments</comments>
		<pubDate>Sat, 22 Nov 2008 20:05:55 +0000</pubDate>
		<dc:creator>Brad</dc:creator>
				<category><![CDATA[Great Minds]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[gm]]></category>
		<category><![CDATA[message queue]]></category>
		<category><![CDATA[messaging]]></category>
		<category><![CDATA[rails rumble]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[rumble]]></category>

		<guid isPermaLink="false">http://www.kickasslabs.com/?p=93</guid>
		<description><![CDATA[Our Rails Rumble 2008 entry, Great Minds (you can have a look at the latest version or the original Rumble version), required a messaging system. Such systems are easy to do wrong, and we knew we&#8217;d need something that would &#8230; <a href="http://www.kickasslabs.com/2008/11/22/93/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Our <a href="http://railsrumble.com/" title="Rails Rumble 2008" target="rr2008">Rails Rumble 2008</a> entry, <i>Great Minds</i> (you can have a look at the <a href="http://greatminds.kickasslabs.com/" title="Great Minds" target="gmkal">latest version</a> or the <a href="http://greatminds.r08.railsrumble.com/" title="Great Minds - Rumble Version" target="gmrr">original Rumble version</a>), required a messaging system.  Such systems are easy to do wrong, and we knew we&#8217;d need something that would stay solid under unknown load during Rumble judging.</p>
<p>The solution was quick &amp; dirty (as most solutions are during Rails Rumble), but the results worked, and allowed us to qualify for judging and reach a respectable 28th place finish in the &#8220;Completeness&#8221; category.</p>
<p>Check out the details after the fold.</p>
<p><span id="more-93"></span></p>
<h3>Design Constraints</h3>
<p><i>Great Minds</i> is a word game played by 2 or more players.  The game is played in a virtual chat <b>Room</b>, containing one or more <b>Players.</b>  Players can take various actions, such as submitting a word to the game, chatting, or changing their handle/username.  The results of these actions must be transmitted to other players in the room.</p>
<p>Other constraints on the design included:</p>
<ul>
<li><b>No New Technologies:</b>  There are tools like <a href="http://juggernaut.rubyforge.org/" title="Juggernaut" target="juggernaut">Juggernaut</a> that make messaging pretty easy, but we had no hands-on experience with them, and learning a new tool on a 48-hour schedule was deemed a risk to completing the project &#038; qualifying for Rumble judging.</li>
<li><b>Broadcast:</b>  We needed something more than a simple message queue like <a href="http://xph.us/software/beanstalkd/" title="Beanstalk" target="beanstalk">Beanstalk</a>; the consumer of a message couldn&#8217;t remove it from the queue, as there might be other consumers needing the same message.</li>
<li><b>Room State Reconstruction:</b>  Someone coming to the room for the first time (or leaving and returning) should be able to see the current room state, including all participants, recently played words, and recent chat.</li>
<li><b>Replay:</b>  Though we didn&#8217;t get around to implementing it, we wanted to offer the ability to review a particularly funny game.</li>
</ul>
<p>The first two constraints affected our design and technology choices; the second two demanded that the messages be persisted.  (Alternatively, we could have saved the room state in some other way, but as long as we had the messages anyway, it seemed simpler to just keep them and reconstruct the state.)</p>
<h3>Client Implementation</h3>
<p>In the absence of a viable push solution like Juggernaut, we opted for a polling solution:  Clients would periodically send a signal that:</p>
<ul>
<li>let the server know they&#8217;re still alive and connected,</li>
<li>sent any new messages to the server, and</li>
<li>requested any pending messages from the server.</li>
</ul>
<p>On the client side, this meant that every message got packaged as JSON, stuck in a queue, and periodically collected and sent to the server as the optional payload of a keep-alive signal.  With some help from Prototype, this was as simple as:</p>
<pre>
  function SyncMessages() {
          var data = Object.toJSON(MESSAGES_QUEUE);
          var url = '/room/sync_messages';
          var params = {
                  authenticity_token: AUTH_TOKEN,
                  messages: '[]',
                  //messages: Object.toJSON(MESSAGES_QUEUE),
                  last_message_id: LAST_MESSAGE_ID };

          new Ajax.Request(url, {
            method: 'post',
                  parameters: params,
            onSuccess: HandleMessages });
  }

  SyncMessages(); //start first on load
  var message_syncer = new PeriodicalExecuter(SyncMessages, 3);
</pre>
<p><code>HandleMessages()</code> updates the DOM based on messages coming back.</p>
<p>The other feature to note is the <code>LAST_MESSAGE_ID</code> token above.  Each client is responsible for keeping track of the last message ID it got.  On the server side, message IDs are assigned sequentially, so all new messages are guaranteed to have a higher ID.</p>
<p>We could have kept track of each client&#8217;s last message on the server side, but this would have been much more complex &#8211; we would have needed to store data either in the session (which already held a fair amount of stuff) or in another table in order to keep track of who had received what.</p>
<h3>Server Implementation</h3>
<p>On the server side, messages were persisted in a table.  This table would have relatively frequent inserts, somewhat more frequent reads, and no updates or deletions.  For this reason, we went with the default MyISAM table architecture.  (We had considered a design that would have updated the table with delivery status information and would have required InnoDB&#8217;s row-level locking, but in the end we opted for the simpler design.)  The table looks like:</p>
<pre>
  class CreateMessages < ActiveRecord::Migration
    def self.up
      create_table :messages do |t|
        t.integer :message_type_id, :room_id, :game_id, :user_id
        t.string  :data, :user_handle
        t.timestamps
      end
    end

    def self.down
      drop_table :messages
    end
  end
</pre>
<p>It also has an index:</p>
<pre>
  class AddRoomIndexToMessages < ActiveRecord::Migration
    def self.up
      add_index :messages, [:room_id, :id]
    end

    def self.down
      remove_index :messages, [:room_id, :id]
    end
  end
</pre>
<p>Recall that the client keeps track of the last message it got, and periodically requests all messages since.  This index speeds that request - which is just <code>msgs = Message.find :all, :conditions => ['room_id = ? AND id > ?', session['room_id'], last_message_id], <img src='http://www.kickasslabs.com/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> rder => 'id'</code>.  (Yes, I know that should be a <a href="http://ryandaigle.com/articles/2008/8/20/named-scope-it-s-not-just-for-conditions-ya-know" title="Named Scopes" title="namedscopes">named scope</a>.  I hadn't gotten around to learning those yet at the time of the Rumble.)</p>
<p>When the a keep-alive signal hits the server:</p>
<ul>
<li>any new messages attached to the signal are added to the <code>messages</code> table,</li>
<li>any game mechanics related to those messages are executed (which may result in more messages being added to the table), and</li>
<li>all messages for the caller's room with an ID greater than the caller's LAST_MESSAGE_ID are packaged as JSON and sent back down in the HTTP response.</li>
</ul>
<p>A note:  If you're in a room and you enter (for example) a chat message, there's actually a server round-trip involved (pushing the message to the server and getting the same message back as a response) before that chat message is shown in your browser.  We worried about this, but not for long - the interactivity delay turned out to be minimal, and it was much simpler to keep it this way (every message is treated the same for all clients) than to create an exception (you update your DOM with your chat messages immediately, but your own chat messages are somehow filtered from your message stream).</p>
<h3>What's Missing?</h3>
<p>Obviously, this was a quick &amp; dirty solution, tailored to the immediate needs of a Rails Rumble project.  Here's what I'd do differently (and indeed, will do differently, as we have plans for the future of Great Minds - stay tuned):</p>
<ul>
<li><b>Security:</b>  We do use the Rails session <code>authenticity_token</code>, but there's still no protection from a server flood from someone who has a token, either by cranking down the polling interval or by fiddling with the LAST_MESSAGE_ID.</li>
<li><b>Server Push:</b>  Polling is wasteful - requests are made whether or not there are any messages to send or receive.  We plan to move to Juggernaut soon.</li>
<li><b>Decoupling from Game Mechanics:</b>  In the first iteration, message receipt and delivery were too intimately tied to game mechanics, with <code>Message</code> objects being explictly constructed and followed by <code>Message.save!</code> calls.  I've already started the process of teasing them apart in preparation for the move to Juggernaut, factoring this into a <code>deliver_message()</code> method.</li>
</ul>
<p>Questions?  Thoughts?  Add a comment!  I promise to get back to you.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fwww.kickasslabs.com%2F2008%2F11%2F22%2F93%2F&amp;title=Quick%20and%20Dirty%20Messaging" id="wpa2a_6"><img src="http://www.kickasslabs.com/wp-content/plugins/add-to-any/share_save_120_16.png" width="120" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://www.kickasslabs.com/2008/11/22/93/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

