<?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>SAPessi &#187; Programming</title>
	<atom:link href="http://sapessi.com/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://sapessi.com</link>
	<description>Perfection of means and confusion of aims...</description>
	<lastBuildDate>Thu, 12 Aug 2010 10:35:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Decode a GPolyline in Objective-C</title>
		<link>http://sapessi.com/2010/06/decode-a-gpolyline-in-objective-c/</link>
		<comments>http://sapessi.com/2010/06/decode-a-gpolyline-in-objective-c/#comments</comments>
		<pubDate>Mon, 14 Jun 2010 12:54:03 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[My Works]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Encoded]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[GPolyline]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Maps]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=378</guid>
		<description><![CDATA[The new version of MapKit in iOS 4 supports polylines, finally. MKPolyline to be precise. I have been working with the Google Maps API for a while and now I&#8217;m learning Objective-C and writing an iPhone app ro Route.ly Since the best way to send around the net the data to draw a polyline on [...]<!-- Easy AdSense V2.82 -->
<!-- Post[count: 2] -->
<div class="ezAdsense adsense adsense-leadout" style="text-align:center;margin:12px;"><script type="text/javascript"><!--
google_ad_client = "pub-8456780651289352";
/* 468x60, created 11/24/09 */
google_ad_slot = "7140896000";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<!-- Easy AdSense V2.82 -->

]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>The new version of MapKit in iOS 4 supports <a href="http://code.google.com/apis/maps/documentation/javascript/v2/reference.html#GPolyline" target="_blank">polylines</a>, finally. MKPolyline to be precise.</p>
<p>I have been working with the Google Maps API for a while and now I&#8217;m learning Objective-C and writing an iPhone app ro <a href="http://route.ly" target="_blank">Route.ly</a></p>
<p>Since the best way to send around the net the data to draw a polyline on a map is in <a href="http://code.google.com/apis/maps/documentation/utilities/polylinealgorithm.html" target="_blank">encoded format</a> I decided to write a small Objective-C function to decode the encoded string. Since I couldn&#8217;t find this anywhere on the net I decided to publish the code here.</p>
<p>You&#8217;ll notice that at the beginning of the function I replace &#8220;\\\\&#8221; with &#8220;\\&#8221;. This is because I use the encoded data both in web pages with javascript and my iPhone app. In javascript &#8220;\\&#8221; would be considered an escape and would therefore break my array of points. This is not the case in Objective-C so I switch back to the normal &#8220;\\&#8221;.</p>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="sy0">-</span> <span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/"><span class="kw5">NSMutableArray</span></a> <span class="sy0">*</span><span class="br0">&#41;</span> decodePolyline<span class="sy0">:</span><span class="br0">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> <span class="sy0">*</span><span class="br0">&#41;</span>encodedPoints <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> escapedEncodedPoints <span class="sy0">=</span> <span class="br0">&#91;</span>encodedPoints stringByReplacingOccurrencesOfString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;<span class="es0">\\</span><span class="es0">\\</span>&quot;</span> withString<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;<span class="es0">\\</span>&quot;</span><span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> len <span class="sy0">=</span> <span class="br0">&#91;</span>escapedEncodedPoints length<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/"><span class="kw5">NSMutableArray</span></a> waypoints <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/"><span class="kw5">NSMutableArray</span></a> alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> index <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> lat <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> lng <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>index &lt; len<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">char</span> b;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> shift <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> result <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">do</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b <span class="sy0">=</span> <span class="br0">&#91;</span>escapedEncodedPoints characterAtIndex<span class="sy0">:</span>index<span class="sy0">++</span><span class="br0">&#93;</span> <span class="sy0">-</span> <span class="nu0">63</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result |<span class="sy0">=</span> <span class="br0">&#40;</span>b <span class="sy0">&amp;</span> 0x1f<span class="br0">&#41;</span> &lt;&lt; shift;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shift <span class="sy0">+=</span> <span class="nu0">5</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">while</span> <span class="br0">&#40;</span>b &gt;<span class="sy0">=</span> 0&#215;20<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> dlat <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>result <span class="sy0">&amp;</span> 1<span class="br0">&#41;</span> ? ~<span class="br0">&#40;</span>result &gt;&gt; 1<span class="br0">&#41;</span> <span class="sy0">:</span> <span class="br0">&#40;</span>result &gt;&gt; 1<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lat <span class="sy0">+=</span> dlat;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shift <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result <span class="sy0">=</span> <span class="nu0">0</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">do</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b <span class="sy0">=</span> <span class="br0">&#91;</span>escapedEncodedPoints characterAtIndex<span class="sy0">:</span>index<span class="sy0">++</span><span class="br0">&#93;</span> <span class="sy0">-</span> <span class="nu0">63</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result |<span class="sy0">=</span> <span class="br0">&#40;</span>b <span class="sy0">&amp;</span> 0x1f<span class="br0">&#41;</span> &lt;&lt; shift;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shift <span class="sy0">+=</span> <span class="nu0">5</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">while</span> <span class="br0">&#40;</span>b &gt;<span class="sy0">=</span> 0&#215;20<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> dlng <span class="sy0">=</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>result <span class="sy0">&amp;</span> 1<span class="br0">&#41;</span> ? ~<span class="br0">&#40;</span>result &gt;&gt; 1<span class="br0">&#41;</span> <span class="sy0">:</span> <span class="br0">&#40;</span>result &gt;&gt; 1<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lng <span class="sy0">+=</span> dlng;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> finalLat <span class="sy0">=</span> lat <span class="sy0">*</span> 1e<span class="sy0">-</span>5;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">float</span> finalLong <span class="sy0">=</span> lng <span class="sy0">*</span> 1e<span class="sy0">-</span>5;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Waypoint <span class="sy0">*</span>newPoint <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>Waypoint alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newPoint.lat <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> alloc<span class="br0">&#93;</span> initWithFormat<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;%f&quot;</span>, finalLat<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; newPoint.lng <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span class="kw5">NSString</span></a> alloc<span class="br0">&#93;</span> initWithFormat<span class="sy0">:</span><span class="co3">@</span><span class="st0">&quot;%f&quot;</span>, finalLong<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>waypoints addObject<span class="sy0">:</span>newPoint<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>newPoint release<span class="br0">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> waypoints;<br />
<span class="br0">&#125;</span></div>
</div>
<p>Waypoints is a simple model class I&#8217;ve written with two NSString properties: lat and lng.</p>
<!-- Easy AdSense V2.82 -->
<!-- Post[count: 3] -->
<div class="ezAdsense adsense adsense-leadout" style="text-align:center;margin:12px;"><script type="text/javascript"><!--
google_ad_client = "pub-8456780651289352";
/* 468x60, created 11/24/09 */
google_ad_slot = "7140896000";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div>
<!-- Easy AdSense V2.82 -->

<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;submitHeadline=Decode+a+GPolyline+in+Objective-C&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;title=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;title=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;title=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;bm_description=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;T=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;title=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;title=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Decode+a+GPolyline+in+Objective-C+@+http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2010%2F06%2Fdecode-a-gpolyline-in-objective-c%2F&amp;t=Decode+a+GPolyline+in+Objective-C" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2010/06/decode-a-gpolyline-in-objective-c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The problem with software patents</title>
		<link>http://sapessi.com/2010/05/the-problem-with-software-patents/</link>
		<comments>http://sapessi.com/2010/05/the-problem-with-software-patents/#comments</comments>
		<pubDate>Sun, 09 May 2010 00:09:38 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Video]]></category>
		<category><![CDATA[AVC]]></category>
		<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Fred]]></category>
		<category><![CDATA[Mathematics]]></category>
		<category><![CDATA[Patent]]></category>
		<category><![CDATA[Patents]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Wilson]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=370</guid>
		<description><![CDATA[Brilliant video posted by Fred Wilson on his blog. If you can spare half an hour definitely watch it! Video: Patent Absurdity &#8211; Dokumentarfilm (28:54) Bookmark It]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>Brilliant video posted by <a href="http://avc.com" target="_blank">Fred Wilson on his blog</a>.</p>
<p>If you can spare half an hour definitely watch it!</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="480" height="270" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="AllowScriptAccess" value="always" /><param name="src" value="http://video.golem.de/player/videoplayer.swf?id=3070&amp;autoPl=false" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="480" height="270" src="http://video.golem.de/player/videoplayer.swf?id=3070&amp;autoPl=false" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<div style="width: 480px; text-align: center; font-family: verdana,sans-serif; font-size: 0.8em;"><a href="http://video.golem.de/politik-recht/3070/patent-absurdity-dokumentarfilm.html">Video: Patent Absurdity &#8211; Dokumentarfilm</a> (28:54)</div>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;submitHeadline=The+problem+with+software+patents&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;title=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;title=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;title=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;bm_description=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;T=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;title=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;title=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+The+problem+with+software+patents+@+http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2010%2F05%2Fthe-problem-with-software-patents%2F&amp;t=The+problem+with+software+patents" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2010/05/the-problem-with-software-patents/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Draggable directions with Google Maps APIs</title>
		<link>http://sapessi.com/2010/03/draggable-directions-with-google-maps-apis/</link>
		<comments>http://sapessi.com/2010/03/draggable-directions-with-google-maps-apis/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 11:51:20 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[My Works]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[WWW]]></category>
		<category><![CDATA[APIs]]></category>
		<category><![CDATA[Directions]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Maps]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=358</guid>
		<description><![CDATA[I love calculating driving directions on Google Maps and then drag the blue line marking my directions to change the route. Everything is updated automatically on the page and the directions are re-calculated to go through the new point I defined. I&#8217;ve been playing around with the Google Maps APIs recently and imagine my disappointment [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>I love calculating driving directions on Google Maps and then drag the blue line marking my directions to change the route. Everything is updated automatically on the page and the directions are re-calculated to go through the new point I defined.</p>
<p>I&#8217;ve been playing around with the <a href="http://code.google.com/apis/maps/" target="_blank">Google Maps APIs</a> recently and imagine my disappointment when I found out that Google does not allow directions calculated through the APIs to be dragged around.</p>
<p>Not put off by this I decided to try and replicate the directions-dragging myself. How hard can it be?<br />
As it turns out. Very, at least if you want to make it look as smooth as Google&#8217;s own solution.</p>
<p>When generating directions Google Maps adds a <a href="http://code.google.com/apis/maps/documentation/reference.html#GPolyline" target="_blank">GPolyline</a> element overlay to your map. You can set the returned line to be editable but this makes an awful lot of vertices appear on it, which makes reading your directions quite hard. Even so, once you dragged one of this vertices around you are not editing the route but just changing the shape of the line.</p>
<p>Mine is not a complete solution and I&#8217;m interested in feedback and ideas on how to improve it.</p>
<p>First off calculate your directions:</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">map <span class="sy0">=</span> <span class="kw2">new</span> google.<span class="me1">maps</span>.<span class="me1">Map2</span><span class="br0">&#40;</span>document.<span class="me1">getElementById</span><span class="br0">&#40;</span><span class="st0">&#8216;map_canvas&#8217;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="kw2">var</span> wayPoints <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
wayPoints.<span class="me1">push</span><span class="br0">&#40;</span>startPoint.<span class="me1">getLatLng</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
wayPoints.<span class="me1">push</span><span class="br0">&#40;</span>endPoint.<span class="me1">getLatLng</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="kw2">var</span> myDir <span class="sy0">=</span> <span class="kw2">new</span> google.<span class="me1">maps</span>.<span class="me1">Directions</span><span class="br0">&#40;</span>map<span class="br0">&#41;</span><br />
myDir.<span class="me1">loadFromWaypoints</span><span class="br0">&#40;</span>wayPoints<span class="sy0">,</span> <span class="br0">&#123;</span> travelMode<span class="sy0">:</span> G_TRAVEL_MODE_DRIVING <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>This will calculate your driving directions and plot a GPolyline on your map. The line is easily accessible in the GDirections object once the directions are calculated. To intercept this I have decided to use the <strong>addoverlay</strong> event on the GMap object. This event is triggered every time something is plotted over the map (says on the tin).</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">google.<span class="me1">maps</span>.<span class="me1">Event</span>.<span class="me1">addListener</span><span class="br0">&#40;</span>myDir<span class="sy0">,</span> <span class="st0">&quot;addoverlay&quot;</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="kw2">var</span> dirLine <span class="sy0">=</span> myDir.<span class="me1">getPolyline</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// Get the polyline from the directions object</span><br />
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>At this point we can ask the APIs to make the GPolyline editable. This will make the vertices appear on the line and make then draggable. As I said before this only changes the shape of the line and doesn&#8217;t actually affect your directions object. Luckily the GPolyline comes with a nifty event called <strong>lineupdated</strong>.<br />
This is triggered once the user has finished dragging a vertex. By intercepting this we can look through the vertices and know what&#8217;s been changed on the line and where the vertex has been moved to.<br />
In order to do this we must also know the previous position of the vertices (latitude and longitude) to be able to compare the old and the new &#8220;edited&#8221; line.<br />
Another challenge is the fact that the <a href="http://code.google.com/apis/maps/documentation/reference.html#GDirections" target="_blank">GDirections</a> object can accept only so many waypoints (25 if I&#8217;m not wrong). Which means we&#8217;ll have to add only the vertex that has changed to the directions and not all of them.</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="co1">// In the addoverlay event also save the original vertices of the line</span><br />
<span class="kw2">var</span> origLine <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
<span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0">&amp;</span>lt<span class="sy0">;</span> dirLine.<span class="me1">getVertexCount</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
origLine.<span class="me1">push</span><span class="br0">&#40;</span>dirLine.<span class="me1">getVertex</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<span class="co1">// DONE saving vertices</span></p>
<p><span class="co1">// Now intercept the lineupdated event and add the new waypoints</span><br />
google.<span class="me1">maps</span>.<span class="me1">Event</span>.<span class="me1">addListener</span><span class="br0">&#40;</span>dirLine<span class="sy0">,</span> <span class="st0">&quot;lineupdated&quot;</span><span class="sy0">,</span> <span class="kw2">function</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
routePoints <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
<span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw2">var</span> i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0">&amp;</span>lt<span class="sy0">;</span> dirLine.<span class="me1">getVertexCount</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<span class="kw2">var</span> savedPoint <span class="sy0">=</span> origLine<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">;</span><br />
<span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>savedPoint <span class="sy0">||</span> <span class="br0">&#40;</span>savedPoint.<span class="me1">lat</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> dirLine.<span class="me1">getVertex</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span>.<span class="me1">lat</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">&amp;</span>amp<span class="sy0">;&amp;</span>amp<span class="sy0">;</span> savedPoint.<span class="me1">lng</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">!=</span> dirLine.<span class="me1">getVertex</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span>.<span class="me1">lng</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
routePoints.<span class="me1">push</span><span class="br0">&#40;</span>dirLine.<span class="me1">getVertex</span><span class="br0">&#40;</span>i<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></p>
<p><span class="co1">// Now we remove the previous directions and recalculate the route</span><br />
map.<span class="me1">removeOverlay</span><span class="br0">&#40;</span>dirLine<span class="br0">&#41;</span><br />
calcRoute<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>This works quite well but does not look as smooth as Google&#8217;s solution.<br />
The problem is that while you are dragging a vertex only that bit of the GPolyline moves and the rest stays in its original position. which makes the shape of your directions quite awkward while you are dragging. Unforunately the GPolyline does not come with a &#8220;startdragging&#8221; event, otherwise we could just recalculate the route every few seconds while the vertex is being dragged.</p>
<p>This is not the most elegant of solutions but it does the job.</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;submitHeadline=Draggable+directions+with+Google+Maps+APIs&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;title=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;title=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;title=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;bm_description=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;T=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;title=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;title=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Draggable+directions+with+Google+Maps+APIs+@+http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2010%2F03%2Fdraggable-directions-with-google-maps-apis%2F&amp;t=Draggable+directions+with+Google+Maps+APIs" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2010/03/draggable-directions-with-google-maps-apis/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Server side JavaScript with node.js</title>
		<link>http://sapessi.com/2009/11/server-side-javascript-with-node-js/</link>
		<comments>http://sapessi.com/2009/11/server-side-javascript-with-node-js/#comments</comments>
		<pubDate>Sat, 21 Nov 2009 17:01:12 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Node]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Server]]></category>
		<category><![CDATA[V8]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=337</guid>
		<description><![CDATA[While skimming through my RSS feed I stumbled upon an interesting article on Ajaxian about server side JavaScript programming. I really, really enjoy writing JavaScript code so I decided to read through the article and take a look at the node.js library linked there. Node is a framework to build server-side event-driven JavaScript applications. Developed [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>While skimming through my RSS feed I stumbled upon an interesting <a href="http://ajaxian.com/archives/full-frontal-09-simon-willison-on-server-side-javascript-and-node-js" target="_blank">article on Ajaxian about server side JavaScript programming</a>.</p>
<p>I really, really enjoy writing JavaScript code so I decided to read through the article and take a look at the <a href="http://nodejs.org/" target="_blank">node.js library linked there</a>.</p>
<p><a href="http://nodejs.org" target="_blank"><img class="aligncenter size-full wp-image-339" title="node.js logo" src="http://sapessi.com/wp-content/uploads/2009/11/node_js_logo.jpg" alt="node.js logo" width="293" height="90" /></a></p>
<p>Node is a framework to build server-side event-driven JavaScript applications. Developed in C++ on top of <a href="http://en.wikipedia.org/wiki/V8_%28JavaScript_engine%29" target="_blank">Google&#8217;s V8 JavaScript engine</a> and accompanied by a set of JavaScript libraries Node seems to make building distributed (over a network), fast applications a piece of cake even for inexperienced developers.<br />
Event-driven here really is the keyword because it represent a big change in the way applications are built (and architected in your brain).</p>
<blockquote><p>Node is similar in design to and influenced by systems like Ruby&#8217;s <a href="http://rubyeventmachine.com/">Event Machine</a> or Python&#8217;s <a href="http://twistedmatrix.com/">Twisted</a>.  Node takes the event         model a bit further—it presents the event loop as a language         construct instead of as a library. In other systems there is always         a blocking call to start the event-loop.  Typically one defines         behavior through callbacks at the beginning of a script and at the         end starts a server through a blocking call like
<div class="codesnip-container" >EventMachine<span>::</span><span>run</span><span>()</span></div>
<p>. In Node there is no such         start-the-event-loop call.  Node simply enters the event loop after         executing the input script.</p></blockquote>
<p>The example below (taken from Node&#8217;s website) will make everything clear&#8230; hopefully.</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="kw2">var</span> sys <span class="sy0">=</span> require<span class="br0">&#40;</span><span class="st0">&#8216;sys&#8217;</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp;http <span class="sy0">=</span> require<span class="br0">&#40;</span><span class="st0">&#8216;http&#8217;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p>http.<span class="me1">createServer</span><span class="br0">&#40;</span><span class="kw2">function</span> <span class="br0">&#40;</span>req<span class="sy0">,</span> res<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; setTimeout<span class="br0">&#40;</span><span class="kw2">function</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; res.<span class="me1">sendHeader</span><span class="br0">&#40;</span><span class="nu0">200</span><span class="sy0">,</span> <span class="br0">&#123;</span><span class="st0">&#8216;Content-Type&#8217;</span><span class="sy0">:</span> <span class="st0">&#8216;text/plain&#8217;</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; res.<span class="me1">sendBody</span><span class="br0">&#40;</span><span class="st0">&#8216;Hello World&#8217;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; res.<span class="me1">finish</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><span class="sy0">,</span> 2000<span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="br0">&#41;</span>.<span class="me1">listen</span><span class="br0">&#40;</span>8000<span class="br0">&#41;</span><span class="sy0">;</span><br />
sys.<span class="me1">puts</span><span class="br0">&#40;</span><span class="st0">&#8216;Server running at http://127.0.0.1:8000/&#8217;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>Can you see the beauty?!</p>
<p>I have only one worry. This is an open-source effort. The community behind it on Google groups is just 181 members strong (so far). What if node.js suddenly stops being the cool thing and the community disappears.</p>
<p>As much as I love writing JavaScript and I can really see the value in what they are building I&#8217;ll still wait until there are 100 Google Groups for node.js and a trillion members in each before using it in anything close to a production system.</p>
<p>Having said that I&#8217;m going back to writing silly node.js apps now. Well done to all the developers involved in the project and keep it up!</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;submitHeadline=Server+side+JavaScript+with+node.js&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;title=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;title=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;title=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;bm_description=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;T=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;title=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;title=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Server+side+JavaScript+with+node.js+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fserver-side-javascript-with-node-js%2F&amp;t=Server+side+JavaScript+with+node.js" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/server-side-javascript-with-node-js/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>SVG graphics with JavaScript</title>
		<link>http://sapessi.com/2009/11/svg-graphics-with-javascript/</link>
		<comments>http://sapessi.com/2009/11/svg-graphics-with-javascript/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 13:47:03 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[My Works]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[WWW]]></category>
		<category><![CDATA[Charts]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[RaphaelJS]]></category>
		<category><![CDATA[SVG]]></category>
		<category><![CDATA[TweetSentiment]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=327</guid>
		<description><![CDATA[When I started developing TweetSentiment I decided that the interface should have as little text as possible. Most of the information I was interested in could be displayed graphically, with a chart. So I looked at all the options available for chart generation. Backend code to generate a static image (JFreeChart or PHP) Flash object [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>When I started developing <a href="http://tweetsentiment.info" target="_blank">TweetSentiment</a> I decided that the interface should have as little text as possible. Most of the information I was interested in could be displayed graphically, with a chart.</p>
<p>So I looked at all the options available for chart generation.</p>
<ol>
<li>Backend code to generate a static image (<a href="http://www.jfree.org/jfreechart/" target="_blank">JFreeChart</a> or PHP)</li>
<li>Flash object to draw a chart retrieving the data from a URL</li>
<li>Draw charts in JavaScript directly on the client&#8217;s browser</li>
</ol>
<p>I&#8217;m not a huge fan of option one. Primarily because TweetSentiment is hosted on a tiny linux box which would not be able to handle the load for the traffic the site gets, also because it&#8217;s a static image &#8211; it&#8217;s just not very funky &#8211; no interaction possible.</p>
<p>Option two would certainly create spectacular looking charts but I have almost no experience with flash and I wasn&#8217;t about to start learning a new language/technology. Plus I&#8217;m not into browser plugins if I can avoid them.</p>
<p>JavaScript is a language I&#8217;m familiar with and I remember seeing some cool-looking charts generated with <a href="http://www.dojotoolkit.org/" target="_blank">Dojo</a>. Unfortunately for TweetSentiment I have used jquery since the most important thing for me there was DOM manipulation (and jquery is just better for that).<br />
I then started shopping around for <a href="http://jquery.com/" target="_blank">jQuery</a> plugins to generate charts. There are a few around but none of them impressed me. They just weren&#8217;t as good looking as I&#8217;d hoped nor they were interactive.</p>
<p>By coincidence I stumbled on <a href="http://raphaeljs.com/" target="_blank">RaphaelJS</a>. A JavaScript library to draw <a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank">Scalable Vector Graphics</a> directly from JavaScript based on jQuery. I tested the samples on the website with a few browsers and I was happy to discover it worked just fine with all of them.</p>
<blockquote>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;"><strong>Scalable Vector Graphics</strong> (<strong>SVG</strong>) is a family of specifications of an <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="XML" href="/wiki/XML">XML</a>-based <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="File format" href="/wiki/File_format">file format</a> for describing two-dimensional <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="Vector graphics" href="/wiki/Vector_graphics">vector graphics</a>, both static and dynamic (i.e. interactive or <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="SVG animation" href="/wiki/SVG_animation">animated</a>).</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">The SVG specification is an <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="Open standard" href="/wiki/Open_standard">open standard</a> that has been under development by the <a style="text-decoration: none; color: #002bb8; background-image: none; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: initial; background-position: initial initial; background-repeat: initial initial;" title="World Wide Web Consortium" href="/wiki/World_Wide_Web_Consortium">World Wide Web Consortium</a> (W3C) since 1999.</p>
</blockquote>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">I also discovered that there is a <a href="http://g.raphaeljs.com/" target="_blank">charting library built on top of RaphaelJS</a>, which is exactly what I was looking for. However, being a geek, I decided to go ahead and try to develop something on my own. You know, just for kicks.</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">As I delved deeper into RaphaelJS I found the library to be incredibly powerful. It&#8217;s a shame that the <a href="http://raphaeljs.com/reference.html" target="_blank">documentation provided on the website</a> lets it down a bit.<br />
The most powerful bit is the ability to extend objects and attach new functions to them. Something scarcely mentioned in the available documentation.</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">For example if you need to use curved lines (paths as SVG calls them) you can just defined a default function you can then call from your code simply by adding it to the <strong>el </strong>&#8220;object&#8221; in RaphaelJS</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">Raphael.<span class="me1">el</span>.<span class="me1">curveTo</span> <span class="sy0">=</span> <span class="kw2">function</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="kw2">var</span> args <span class="sy0">=</span> Array.<span class="me1">prototype</span>.<span class="me1">splice</span>.<span class="me1">call</span><span class="br0">&#40;</span>arguments<span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> arguments.<span class="me1">length</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; d <span class="sy0">=</span> <span class="br0">&#91;</span><span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="st0">&quot;s&quot;</span><span class="sy0">,</span> <span class="nu0">0</span><span class="sy0">,</span> <span class="st0">&quot;c&quot;</span><span class="br0">&#93;</span><span class="br0">&#91;</span>args.<span class="me1">length</span><span class="br0">&#93;</span> <span class="sy0">||</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span><br />
&nbsp; <span class="kw1">this</span>.<span class="me1">isAbsolute</span> <span class="sy0">&amp;</span>amp<span class="sy0">;&amp;</span>amp<span class="sy0">;</span> <span class="br0">&#40;</span>d <span class="sy0">=</span> d.<span class="me1">toUpperCase</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="kw1">this</span>._last <span class="sy0">=</span> <span class="br0">&#123;</span>x<span class="sy0">:</span> args<span class="br0">&#91;</span>args.<span class="me1">length</span> <span class="sy0">-</span> 2<span class="br0">&#93;</span><span class="sy0">,</span> y<span class="sy0">:</span> args<span class="br0">&#91;</span>args.<span class="me1">length</span> <span class="sy0">-</span> 1<span class="br0">&#93;</span><span class="br0">&#125;</span><span class="sy0">;</span><br />
&nbsp; <span class="kw1">return</span> <span class="kw1">this</span>.<span class="me1">attr</span><span class="br0">&#40;</span><span class="br0">&#123;</span>path<span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">attrs</span>.<span class="me1">path</span> <span class="sy0">+</span> d <span class="sy0">+</span> args<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span></div>
</div>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">Another very useful function I found in one of their samples is the <strong>andClose() </strong>This is used to close a polygon you have started drawing with paths. No matter where you got to it will reconnect to the initial point.</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">Raphael.<span class="me1">el</span>.<span class="me1">andClose</span> <span class="sy0">=</span> <span class="kw2">function</span> <span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">return</span> <span class="kw1">this</span>.<span class="me1">attr</span><span class="br0">&#40;</span><span class="br0">&#123;</span>path<span class="sy0">:</span> <span class="kw1">this</span>.<span class="me1">attrs</span>.<span class="me1">path</span> <span class="sy0">+</span> <span class="st0">&quot;z&quot;</span><span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="br0">&#125;</span><span class="sy0">;</span></div>
</div>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">This can then be used this way using <a href="http://ejohn.org/blog/ultra-chaining-with-jquery/" target="_blank">chaining</a>.</p>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;">RaphaelJSElement.<span class="me1">lineTo</span><span class="br0">&#40;</span>x<span class="sy0">,</span> opts.<span class="me1">height</span> <span class="sy0">-</span> bottomgutter<span class="br0">&#41;</span>.<span class="me1">andClose</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em;">I&#8217;m still developing the chart library I used in TweetSentiment and I&#8217;m planning to publish it here with some documentation under MIT licence.</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;submitHeadline=SVG+graphics+with+JavaScript&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;title=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;title=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;title=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;bm_description=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;T=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;title=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;title=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+SVG+graphics+with+JavaScript+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fsvg-graphics-with-javascript%2F&amp;t=SVG+graphics+with+JavaScript" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/svg-graphics-with-javascript/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google Go</title>
		<link>http://sapessi.com/2009/11/google-go/</link>
		<comments>http://sapessi.com/2009/11/google-go/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 15:10:10 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[General Babbling]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Distributed]]></category>
		<category><![CDATA[Erlang]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[multi-process]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=315</guid>
		<description><![CDATA[I have just stumbled on an article on Slashdot about Google Go. A programming language which was initially developed internally and it&#8217;s now been open-sourced. Over the past few months I have been working with Erlang on multi-process distributed systems. Concurrency in Go is based on the same model Erlang uses: Hoare&#8217;s Communicating Sequential Processes, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>I have just stumbled on an <a href="http://developers.slashdot.org/story/09/11/11/0210212/Go-Googles-New-Open-Source-Programming-Language?from=rss" target="_blank">article on Slashdot about Google Go</a>. A programming language which was initially developed internally and it&#8217;s now been open-sourced.</p>
<p>Over the past few months I have been working with Erlang on multi-process distributed systems. Concurrency in <a href="http://golang.org/" target="_blank">Go</a> is based on the same model Erlang uses: Hoare&#8217;s Communicating Sequential Processes, or <a href="http://golang.org/doc/go_lang_faq.html#csp" target="_blank">CSP</a>.</p>
<blockquote><p>Go&#8217;s concurrency primitives derive from a different part of the family tree whose main contribution is the powerful notion of channels as first class objects.</p></blockquote>
<p>The thing I appreciate the most of Erlang is how easy it is to distribute &#8211; even over a network &#8211; and monitor processes. After skimming through Go&#8217;s documentation I couldn&#8217;t help but notice the lack of integrated network-distribution of processes or goroutines, as they are called.</p>
<p><span style="background-color: #ffffff;">This for me means that while Go, exactly like Erlang and Occam, simplifies the approach to multi-threaded programming (at least from a developer&#8217;s point of view), it doesn&#8217;t go all the way and leaves developers to deal with distribution of processes over a network on their own.</span></p>
<p>This is a perfectly acceptable design choice in the name of flexibility, however it creates a whole new bunch of use cases for the developers to deal with, such as sending channels/channels-data over the network).</p>
<p>What I don&#8217;t like of Erlang is its handling of strings, which makes it unsuitable for a number of application that could benefit greatly from its multi-processing capabilities. Very few people would recommend Erlang as a high performance string manipulation language. T<span style="background-color: #ffffff;">o quote Sendmail&#8217;s case study in implementing their Sendmail load balancing &#8220;Client Daemon&#8221; in Erlang:</span></p>
<blockquote>
<p style="margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; display: block; unicode-bidi: embed;">&#8230;But Erlang&#8217;s treatment of strings as lists of bytes is as elegant as it is impractical. The factor-of-eight storage expansion of text, as well as the copying that occurs during message-passing, cripples Erlang for all but the most performance-insensitive text-processing applications.</p>
</blockquote>
<p style="margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; display: block; unicode-bidi: embed;">Go totally wins on this.</p>
<p style="margin-top: 1em; margin-right: 0px; margin-bottom: 1em; margin-left: 0px; display: block; unicode-bidi: embed;">If you now asked me to pick one to use. I&#8217;d still go for Erlang.<br />
<span style="background-color: #ffffff;">Functional languages and CSP are changing the way big companies approach the development of business critical applications. In the last year alone I have seen the number of positions advertised for Erlang developers in the financial sector multiply.<br />
Go, if it continues on this path definitely has a chance of making it there. Open-sourcing the language is the right decision to give it the exposure to real-life scenarios that tend to accelerate the growth and adoption rate. </span></p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;submitHeadline=Google+Go&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;title=Google+Go" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;title=Google+Go" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;title=Google+Go" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;bm_description=Google+Go" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;T=Google+Go" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;title=Google+Go" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;title=Google+Go" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Google+Go+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fgoogle-go%2F&amp;t=Google+Go" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/google-go/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TweetSentiment &#8211; Twitter activity VS market activity</title>
		<link>http://sapessi.com/2009/11/tweetsentiment-twitter-activity-vs-market-activity/</link>
		<comments>http://sapessi.com/2009/11/tweetsentiment-twitter-activity-vs-market-activity/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 18:30:47 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[My Works]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Finance]]></category>
		<category><![CDATA[Groovy]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[Market]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[StockTwits]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=307</guid>
		<description><![CDATA[Perhaps I&#8217;m bored. Maybe I&#8217;m just too single. Anyway. A couple of days ago I was looking at StockTwits again and saw a considerable amount of activity. There and then I decided that it would have been pretty cool to check whether there was any correlation between the activity about a stock on Twitter and [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>Perhaps I&#8217;m bored. Maybe I&#8217;m just too single.<br />
Anyway. A couple of days ago I was looking at <a href="http://stocktwits.com/" target="_blank">StockTwits</a> again and saw a considerable amount of activity. There and then I decided that it would have been pretty cool to check whether there was any correlation between the activity about a stock on Twitter and the actual trading volume on the market.</p>
<p>I set off to build a small system to do just that. A couple of <a href="http://groovy.codehaus.org/" target="_blank">groovy scripts</a> to collect the data and save it plus some JavaScript and HTML to display it.</p>
<p>So here I am a couple of days later talking about <a href="http://tweetsentiment.info" target="_blank">TweetSentiment</a>.</p>
<p>Collecting the data I needed was pretty trivial thanks to the fact that StockTwits asks all its members to tweet the symbols they are trading preceded by a dollar sign ($).<br />
My first task was to build a list of securities I was interested in. I decided to go to <a href="http://www.covestor.com" target="_blank">Covestor.com</a> and pick the most traded securities list.  Once that list was ready all I had to do was call the <a href="http://apiwiki.twitter.com/Twitter-Search-API-Method:-search" target="_blank">Twitter Search APIs</a> for each stock and store the results.<br />
Groovy made these tasks incredibly simple.</p>
<div class="codesnip-container" >
<div class="java codesnip" style="font-family:monospace;">def output <span class="sy0">=</span> <span class="kw1">new</span> <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Aurl+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">URL</span></a><span class="br0">&#40;</span><span class="st0">&quot;http://search.twitter.com/search.atom?q=${&quot;</span>\$<span class="st0">&quot;+curSecurity.symbol}&amp;amp;rpp=100&quot;</span><span class="br0">&#41;</span>.<span class="me1">getText</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>def parsedXml <span class="sy0">=</span> <span class="kw1">new</span> XmlParser<span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">parseText</span><span class="br0">&#40;</span>output<span class="br0">&#41;</span></p>
<p>parsedXml.<span class="me1">entry</span>.<span class="me1">each</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> curEntry <span class="sy0">-&amp;</span>gt<span class="sy0">;</span><br />
&#8230;</div>
</div>
<p>I&#8217;m not doing much with the tweets. At the moment I just count them and look for &#8220;buy&#8221; and &#8220;sell&#8221;. I&#8217;m looking into smarter ways of analysing the text and look for positive/negative opinions. If you have any suggestion on this please do leave a comment.</p>
<p>Next in my TODO list was getting some market data. For that I&#8217;m using Yahoo finance asking for previous closing price and average volume for each security. Once again, piece of cake with Groovy. Same thing as before just different URL.<br />
Yahoo finance actually has quite a simple interface to let you grab the data. Check out this page on <a href="http://cliffngan.net/a/13" target="_blank">Cliff&#8217;s Notes</a>.</p>
<p>Now I had all the data I needed. Only thing left was to build some sort of interface to look at it. I wanted to display all of the data on a chart to be able to make sense of it as quickly as possible.<br />
My server (i.e. the machine running this blog) with its puny power could have never handled the traffic I get while generating charts. Therefore what I decided to do is to export all the data in text files (JSON format) and do all of the chart generation with JavaScript.</p>
<p>I browsed the web for a bit looking for charting components for <a href="http://jquery.com/" target="_blank">jQuery</a>. Couldn&#8217;t find anything I was happy with. Not functionality-wise but aesthetically. Or maybe I just felt like playing around with JS for some time &#8211; unfortunately as it often happens with JS I spent the best part of the last 2 days working on it.</p>
<p>I decided to use a library called <a href="http://raphaeljs.com/index.html" target="_blank">Raphaël</a>. This library makes working with vector graphics incredibly simple and the results just look amazing. I know that they are in the process of building a <a href="http://g.raphaeljs.com/" target="_blank">charting library on top of it</a> however&#8230; well I have no excuse now other than I wanted to work with JS.</p>
<p>What I did is build a very simple jQuery component called SAPchart. It only draws line charts but it&#8217;s quite simple and I think the results look pretty good.</p>
<p>You can download the <a href="http://sapessi.com/tweetsentiment/js/SAPchart.js" target="_blank">source here</a>. It requires jQuery, <a href="http://raphaeljs.com/index.html" target="_blank">Raphaël</a>, and <a href="http://sapessi.com/tweetsentiment/js/raphael.path.methods.js" target="_blank">raphael path methods</a>.</p>
<div class="codesnip-container" >
<div class="javascript codesnip" style="font-family:monospace;"><span class="co1">// Constructor. Possible options are:</span><br />
<span class="co1">// showGrid: true</span><br />
<span class="co1">// width: 800</span><br />
<span class="co1">// height: 250</span><br />
<span class="co1">// legendWidth: 200</span><br />
<span class="co1">// showLabels: true</span><br />
<span class="co1">// showDots: true</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">SAPchart</span><span class="br0">&#40;</span><span class="br0">&#123;</span>legendWidth<span class="sy0">:</span> 800<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="co1">// Give the library a list of labels for the x axis</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">setLabels</span><span class="br0">&#40;</span>theLabels<span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="co1">// Add to the chart as many series as you want &#8211; provided the length of the series is</span><br />
<span class="co1">// the same of the labels (quite unsophisticated but serves its purpose)</span><br />
<span class="co1">// array of values, unique id of the series, legend name, additional options)</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">addSeries</span><span class="br0">&#40;</span>theTweets<span class="sy0">,</span> <span class="st0">&quot;tweet&quot;</span><span class="sy0">,</span> <span class="st0">&quot;Twitter Activity&quot;</span><span class="sy0">,</span> <span class="br0">&#123;</span> <span class="st0">&quot;color&quot;</span><span class="sy0">:</span> <span class="br0">&#91;</span>.6<span class="sy0">,</span> 1<span class="sy0">,</span> .75<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">addSeries</span><span class="br0">&#40;</span>theVolumes<span class="sy0">,</span> <span class="st0">&quot;volume&quot;</span><span class="sy0">,</span> <span class="st0">&quot;Average Daily Volume&quot;</span><span class="sy0">,</span> <span class="br0">&#123;</span> <span class="st0">&quot;color&quot;</span><span class="sy0">:</span> <span class="br0">&#91;</span>.2<span class="sy0">,</span> 1<span class="sy0">,</span> .75<span class="br0">&#93;</span> <span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span></p>
<p><span class="co1">// Draws the chart in your html element</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">draw</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p><span class="co1">// This will return an HTML table containing the legend of all the series you specified</span><br />
<span class="co1">// the boolean parameter tells me whether you want your legend to be horizontal (default vertical)</span><br />
$<span class="br0">&#40;</span><span class="st0">&quot;#holder&quot;</span><span class="br0">&#41;</span>.<span class="me1">getLegend</span><span class="br0">&#40;</span><span class="kw2">true</span><span class="br0">&#41;</span>.<span class="me1">appendTo</span><span class="br0">&#40;</span>$<span class="br0">&#40;</span><span class="st0">&quot;#legend&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div>
</div>
<p>I&#8217;m now wondering whether I should keep working on it and improve it.</p>
<p>Anyway <a href="http://sapessi.com/tweetsentiment/" target="_blank">TweetSentiment is now available here</a>. I&#8217;m planning to keep it running and collecting data for a while. I&#8217;d say you need at least 3/4 months worth of data before you can make any useful observations.</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;submitHeadline=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;title=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;title=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;title=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;bm_description=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;T=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;title=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;title=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftweetsentiment-twitter-activity-vs-market-activity%2F&amp;t=TweetSentiment+%26%238211%3B+Twitter+activity+VS+market+activity" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/tweetsentiment-twitter-activity-vs-market-activity/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Tracking database records history</title>
		<link>http://sapessi.com/2009/11/tracking-database-records-history/</link>
		<comments>http://sapessi.com/2009/11/tracking-database-records-history/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 12:40:14 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[History]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=288</guid>
		<description><![CDATA[If you Google for this you&#8217;ll find that the easiest way to provide a full audit of everything that happened in your database is to create a duplicate of each table you need history and insert a copy of the record you are changing in there for every update. For example if you have a [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>If you Google for this you&#8217;ll find that the easiest way to provide a full audit of everything that happened in your database is to create a duplicate of each table you need history and insert a copy of the record you are changing in there for every update.</p>
<p>For example if you have a table called client</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> client <span class="br0">&#40;</span><br />
&nbsp; id INTEGER<span class="sy0">,</span><br />
&nbsp; firstname VARCHAR<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; lastname VARCHAR<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; datecreated TIMESTAMP<br />
<span class="br0">&#41;</span>;</div>
</div>
<p>You will also create a table called client_history</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> client_history <span class="br0">&#40;</span><br />
&nbsp; id INTEGER<span class="sy0">,</span><br />
&nbsp; firstname VARCHAR<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; lastname VARCHAR<span class="br0">&#40;</span><span class="nu0">255</span><span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; datecreated TIMESTAMP<span class="sy0">,</span><br />
&nbsp; history_creation TIMESTAMP<span class="sy0">,</span><br />
&nbsp; history_user INTEGER <span class="co1">&#8211; A foreign key to the user who updated this record if required</span><br />
<span class="br0">&#41;</span>;</div>
</div>
<p>You&#8217;ll then attach an onUpdate trigger to the client table inserting all the data in your history table. This solution gives you the ability to keep track of everything that happens in your database, when it happened and who-done-it.<br />
What this solution doesn&#8217;t deal with is schema changes. Also querying the state of a record at a point in time to join it with other tables might be a bit tricky.</p>
<p>Let&#8217;s start from the first point. <strong>Schema changes</strong>.<br />
The most obvious and simple solution is to put in place a proper process for all database schema changes. i.e. whoever touches the schema is also in charge of updating the history table structure and the trigger on the main table. Doable but a bit too prone to human error if you ask me.</p>
<p>What I generally do is use a small function/stored procedure to create the history on a table. This procedure is in charge of both creating the history table the first time it&#8217;s called and updating the structure if the main table has changed.<br />
In this example I&#8217;m going to use <a href="http://www.postgresql.org/" target="_blank">PostgreSQL</a>. First because it&#8217;s a database I&#8217;m familiar with and more importantly being open-srouce you can just download it and try this yourself.</p>
<p>My example here is a bit verbose but it serves its purpose. There are many database-specific instructions you could use to extract a table structure or perform some of the simple tasks of this function. However, what I&#8217;m trying to demonstrate is the concept and not PostgreSQL trickery.<br />
Most relational databases store the schema information in internal tables (pg_attribute, pg_class and pg_namespace in this case) so that&#8217;s what we are going to use to read the structure of our original table.</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="co1">&#8211; This function expects as a parameter the name of the table you want to</span><br />
<span class="co1">&#8211; create history for and a unique identifier for the record.</span><br />
<span class="co1">&#8211; in my case all tables have an ID column. Alternatively you could hand</span><br />
<span class="co1">&#8211; as a parameter also the name of the unique id column</span><br />
<span class="kw1">CREATE</span> <span class="kw1">OR</span> <span class="kw1">REPLACE</span> <span class="kw1">FUNCTION</span> create_history<span class="br0">&#40;</span>tablename VARCHAR<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="sy0">,</span> recordid INTEGER<span class="br0">&#41;</span> RETURNS <span class="kw1">BOOLEAN</span> <span class="kw1">AS</span> $$<br />
DECLARE<br />
&nbsp; vhisttablename NAME; <span class="co1">&#8211; history table name</span><br />
&nbsp; vhistfieldcount INTEGER; &nbsp;<span class="co1">&#8211; number of fields in history table</span><br />
&nbsp; vtablefieldcount INTEGER; <span class="co1">&#8211; number of fields in main table</span><br />
&nbsp; vtmprowcount INTEGER; <span class="co1">&#8211; temporary variable to store query results</span><br />
&nbsp; vcurfield RECORD; <span class="co1">&#8211; variable to loop over fields of main table to create history</span><br />
&nbsp; vhisttablesql TEXT; <span class="co1">&#8211; sql to create history table</span><br />
&nbsp; vfieldlist TEXT; <span class="co1">&#8211; list fo fields in main table</span><br />
&nbsp; vhisttablefields TEXT; <span class="co1">&#8211; list of fields in history table</span><br />
&nbsp; vhistinsertsql TEXT; <span class="co1">&#8211; SQL for insert statement</span><br />
&nbsp; vtmptablename VARCHAR<span class="br0">&#40;</span>255<span class="br0">&#41;</span>; <span class="co1">&#8211; temp variable to check if history exists</span><br />
BEGIN<br />
&nbsp; vhisttablename :<span class="sy0">=</span> tablename<span class="sy0">||</span><span class="st0">&#8216;_hist&#8217;</span>;</p>
<p>&nbsp; <span class="co1">&#8211; Check if the history table exists, if not we need to create it</span><br />
&nbsp; <span class="kw1">SELECT</span> <span class="kw1">INTO</span> vtmptablename relname<br />
&nbsp; <span class="kw1">FROM</span> pg_class<br />
&nbsp; <span class="kw1">WHERE</span> relname <span class="sy0">=</span> vhisttablename;</p>
<p>&nbsp; vfieldlist :<span class="sy0">=</span> <span class="st0">&#8221;</span>;<br />
&nbsp; vhisttablefields :<span class="sy0">=</span> <span class="st0">&#8221;</span>;</p>
<p>&nbsp; <span class="co1">&#8211; count the fields in the history/current table if history exists</span><br />
&nbsp; <span class="kw1">IF</span> vtmptablename <span class="kw1">IS</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><br />
&nbsp; THEN<br />
&nbsp; &nbsp; <span class="kw1">SELECT</span> <span class="kw1">INTO</span> vhistfieldcount count<span class="br0">&#40;</span><span class="sy0">*</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">FROM</span> pg_attribute <span class="kw1">AS</span> a<br />
&nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_class <span class="kw1">AS</span> c <span class="kw1">ON</span> <span class="br0">&#40;</span>c<span class="sy0">.</span>oid <span class="sy0">=</span> a<span class="sy0">.</span>attrelid<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_namespace <span class="kw1">AS</span> n <span class="kw1">ON</span> <span class="br0">&#40;</span>n<span class="sy0">.</span>oid <span class="sy0">=</span> c<span class="sy0">.</span>relnamespace<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">WHERE</span> a<span class="sy0">.</span>attnum <span class="sy0">&gt;</span> 0<br />
&nbsp; &nbsp; <span class="kw1">AND</span> c<span class="sy0">.</span>relname <span class="sy0">=</span> vhisttablename <span class="co1">&#8211; history table name</span><br />
&nbsp; &nbsp; <span class="kw1">AND</span> <span class="kw1">NOT</span> a<span class="sy0">.</span>attisdropped<br />
&nbsp; &nbsp; <span class="kw1">AND</span> pg_table_is_visible<span class="br0">&#40;</span>c<span class="sy0">.</span>oid<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; <span class="kw1">SELECT</span> <span class="kw1">INTO</span> vtablefieldcount count<span class="br0">&#40;</span><span class="sy0">*</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">FROM</span> pg_attribute <span class="kw1">AS</span> a<br />
&nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_class <span class="kw1">AS</span> c <span class="kw1">ON</span> <span class="br0">&#40;</span>c<span class="sy0">.</span>oid <span class="sy0">=</span> a<span class="sy0">.</span>attrelid<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_namespace <span class="kw1">AS</span> n <span class="kw1">ON</span> <span class="br0">&#40;</span>n<span class="sy0">.</span>oid <span class="sy0">=</span> c<span class="sy0">.</span>relnamespace<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">WHERE</span> a<span class="sy0">.</span>attnum <span class="sy0">&gt;</span> 0<br />
&nbsp; &nbsp; <span class="kw1">AND</span> c<span class="sy0">.</span>relname <span class="sy0">=</span> tablename <span class="co1">&#8211; main table</span><br />
&nbsp; &nbsp; <span class="kw1">AND</span> <span class="kw1">NOT</span> a<span class="sy0">.</span>attisdropped<br />
&nbsp; &nbsp; <span class="kw1">AND</span> pg_table_is_visible<span class="br0">&#40;</span>c<span class="sy0">.</span>oid<span class="br0">&#41;</span>;<br />
&nbsp; END <span class="kw1">IF</span>;</p>
<p>&nbsp; <span class="co1">&#8211; Get all the attributes and their type from the original table</span><br />
&nbsp; <span class="kw1">FOR</span> vcurfield <span class="kw1">IN</span><br />
&nbsp; <span class="kw1">SELECT</span> a<span class="sy0">.</span>attname <span class="kw1">AS</span> <span class="kw1">COLUMN</span><span class="sy0">,</span> format_type<span class="br0">&#40;</span>a<span class="sy0">.</span>atttypid<span class="sy0">,</span> a<span class="sy0">.</span>atttypmod<span class="br0">&#41;</span> <span class="kw1">AS</span> datatype<br />
&nbsp; <span class="kw1">FROM</span> pg_attribute <span class="kw1">AS</span> a<br />
&nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_class <span class="kw1">AS</span> c <span class="kw1">ON</span> <span class="br0">&#40;</span>c<span class="sy0">.</span>oid <span class="sy0">=</span> a<span class="sy0">.</span>attrelid<span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_namespace <span class="kw1">AS</span> n <span class="kw1">ON</span> <span class="br0">&#40;</span>n<span class="sy0">.</span>oid <span class="sy0">=</span> c<span class="sy0">.</span>relnamespace<span class="br0">&#41;</span><br />
&nbsp; <span class="kw1">WHERE</span> a<span class="sy0">.</span>attnum <span class="sy0">&gt;</span> 0<br />
&nbsp; <span class="kw1">AND</span> c<span class="sy0">.</span>relname <span class="sy0">=</span> tablename<br />
&nbsp; <span class="kw1">AND</span> <span class="kw1">NOT</span> a<span class="sy0">.</span>attisdropped<br />
&nbsp; <span class="kw1">AND</span> pg_table_is_visible<span class="br0">&#40;</span>c<span class="sy0">.</span>oid<span class="br0">&#41;</span><br />
&nbsp; LOOP<br />
&nbsp; &nbsp; <span class="co1">&#8211; populate lists of fields both for history creation and select from main table</span><br />
&nbsp; &nbsp; vhisttablefields :<span class="sy0">=</span> vhisttablefields<span class="sy0">||</span>vcurfield<span class="sy0">.</span><span class="kw1">COLUMN</span><span class="sy0">||</span><span class="st0">&#8216; &#8216;</span><span class="sy0">||</span>vcurfield<span class="sy0">.</span>datatype<span class="sy0">||</span><span class="st0">&#8216; NULL, &#8216;</span>;<br />
&nbsp; &nbsp; vfieldlist :<span class="sy0">=</span> vfieldlist<span class="sy0">||</span>vcurfield<span class="sy0">.</span><span class="kw1">COLUMN</span><span class="sy0">||</span><span class="st0">&#8216;, &#8216;</span>;</p>
<p>&nbsp; &nbsp; <span class="co1">&#8211; If the history table exists and the number of fields is different</span><br />
&nbsp; &nbsp; <span class="co1">&#8211; from the main table (+3 as we add a timestamp, a user field and an history unique id)</span><br />
&nbsp; &nbsp; <span class="kw1">IF</span> vtmptablename <span class="kw1">IS</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">AND</span> vtablefieldcount<span class="sy0">+</span><span class="nu0">3</span> <span class="sy0">&lt;&gt;</span> vhistfieldcount<br />
&nbsp; &nbsp; THEN<br />
&nbsp; &nbsp; &nbsp; <span class="co1">&#8211; make sure that this is the missing field in the history table</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;PERFORM a<span class="sy0">.</span>attname<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">FROM</span> pg_attribute <span class="kw1">AS</span> a<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_class <span class="kw1">AS</span> c <span class="kw1">ON</span> <span class="br0">&#40;</span>c<span class="sy0">.</span>oid <span class="sy0">=</span> a<span class="sy0">.</span>attrelid<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">INNER</span> <span class="kw1">JOIN</span> pg_namespace <span class="kw1">AS</span> n <span class="kw1">ON</span> <span class="br0">&#40;</span>n<span class="sy0">.</span>oid <span class="sy0">=</span> c<span class="sy0">.</span>relnamespace<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">WHERE</span> a<span class="sy0">.</span>attnum <span class="sy0">&gt;</span> 0<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">AND</span> c<span class="sy0">.</span>relname <span class="sy0">=</span> vhisttablename<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">AND</span> <span class="kw1">NOT</span> a<span class="sy0">.</span>attisdropped<br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">AND</span> a<span class="sy0">.</span>attname <span class="sy0">=</span> vcurfield<span class="sy0">.</span><span class="kw1">COLUMN</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">AND</span> pg_table_is_visible<span class="br0">&#40;</span>c<span class="sy0">.</span>oid<span class="br0">&#41;</span>;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;GET DIAGNOSTICS vtmprowcount <span class="sy0">=</span> ROW_COUNT;</p>
<p>&nbsp; &nbsp; &nbsp; <span class="co1">&#8211; If it is then generate the SQL and execute the alter table</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">IF</span> vtmprowcount <span class="sy0">=</span> <span class="nu0">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;THEN<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;vhisttablesql :<span class="sy0">=</span> <span class="st0">&#8216;ALTER TABLE &#8216;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216; ADD COLUMN &#8216;</span><span class="sy0">||</span>vcurfield<span class="sy0">.</span><span class="kw1">COLUMN</span><span class="sy0">||</span><span class="st0">&#8216; &#8216;</span><span class="sy0">||</span>vcurfield<span class="sy0">.</span>datatype<span class="sy0">||</span><span class="st0">&#8216; NULL;&#8217;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;EXECUTE vhisttablesql;<br />
&nbsp; &nbsp; &nbsp; &nbsp;END <span class="kw1">IF</span>;<br />
&nbsp; &nbsp; &nbsp;END <span class="kw1">IF</span>;<br />
&nbsp; END LOOP;</p>
<p>&nbsp; <span class="co1">&#8211; The history table doesn&#8217;t exist. Create it</span><br />
&nbsp; <span class="kw1">IF</span> vtmptablename <span class="kw1">IS</span> <span class="kw1">NULL</span> <span class="kw1">OR</span> vtmptablename <span class="sy0">=</span> <span class="st0">&#8221;</span><br />
&nbsp; THEN<br />
&nbsp; &nbsp; vhisttablesql :<span class="sy0">=</span> <span class="st0">&#8216;CREATE TABLE &#8216;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216; ( histid SERIAL PRIMARY KEY, &#8216;</span>;</p>
<p>&nbsp; &nbsp; vhisttablesql :<span class="sy0">=</span> vhisttablesql<span class="sy0">||</span>vhisttablefields<span class="sy0">||</span><span class="st0">&#8216; history_creation TIMESTAMP NOT NULL DEFAULT now() );&#8217;</span>;</p>
<p>&nbsp; &nbsp; EXECUTE vhisttablesql;</p>
<p>&nbsp; &nbsp; <span class="co1">&#8211; create indexes</span><br />
&nbsp; &nbsp; vhisttablesql :<span class="sy0">=</span> <span class="st0">&#8216; CREATE INDEX idx_&#8217;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216;_1 ON &#8216;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216; (id); &#8216;</span>;<br />
&nbsp; &nbsp; EXECUTE vhisttablesql;</p>
<p>&nbsp; &nbsp; vhisttablesql :<span class="sy0">=</span> <span class="st0">&#8216; CREATE INDEX idx_&#8217;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216;_2 ON &#8216;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216; (history_creation); &#8216;</span>;<br />
&nbsp; &nbsp; EXECUTE vhisttablesql;<br />
&nbsp; END <span class="kw1">IF</span>;</p>
<p>&nbsp; <span class="co1">&#8211; Proceed with the history creation</span><br />
&nbsp; vhistinsertsql :<span class="sy0">=</span> <span class="st0">&#8216;INSERT INTO &#8216;</span><span class="sy0">||</span>vhisttablename<span class="sy0">||</span><span class="st0">&#8216; (&#8216;</span><span class="sy0">||</span>vfieldlist<span class="sy0">||</span><span class="st0">&#8216; history_creation) SELECT &#8216;</span><span class="sy0">||</span>vfieldlist<span class="sy0">||</span><span class="st0">&#8216; now() FROM &#8216;</span><span class="sy0">||</span>tablename<span class="sy0">||</span><span class="st0">&#8216; WHERE id=&#8217;</span><span class="sy0">||</span>recordid<span class="sy0">||</span><span class="st0">&#8216;;&#8217;</span>;</p>
<p>&nbsp; RAISE NOTICE <span class="st0">&#8216;Executing %&#8217;</span><span class="sy0">,</span> vhistinsertsql;<br />
&nbsp; EXECUTE vhistinsertsql;</p>
<p>&nbsp; GET DIAGNOSTICS vtmprowcount <span class="sy0">=</span> ROW_COUNT;<br />
&nbsp; <span class="kw1">IF</span> vtmprowcount <span class="sy0">&gt;</span> 0<br />
&nbsp; THEN<br />
&nbsp; &nbsp; <span class="kw1">RETURN</span> TRUE;<br />
&nbsp; ELSE<br />
&nbsp; &nbsp; <span class="kw1">RETURN</span> FALSE;<br />
&nbsp; END <span class="kw1">IF</span>;<br />
END;<br />
$$<br />
<span class="kw1">LANGUAGE</span> plpgsql;</div>
</div>
<p>You&#8217;ll notice this function only adds fields to the history table. That&#8217;s because even if we remove a field from the original table we still want to keep track of it in our history.</p>
<p>Now on to <strong>querying the history to retrieve the state of a record at a specific date</strong>.</p>
<p>This is a bit tricky. At the moment as far as I know only Oracle has the ability return a &#8220;virtual table&#8221; from a function. PostgreSQL can return a RECORD variable &#8211; which is great to use inside functions but once outside it loses its structure and turns into a comma separated list of values &#8211; or a %ROWTYPE you can define.<br />
This unfortunately means that you&#8217;d have to create a custom function for each history table to returns a SET OF client &#8211; in our case.</p>
<p>What we are trying to achieve is something like what this query does.</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="kw1">SELECT</span> h<span class="sy0">.</span>id<span class="sy0">,</span> firstname<span class="sy0">,</span> lastname<span class="sy0">,</span> datecreated<span class="sy0">,</span> hist_creation<br />
<span class="kw1">FROM</span> client_hist <span class="kw1">AS</span> h<br />
<span class="kw1">INNER</span> <span class="kw1">JOIN</span> <span class="br0">&#40;</span><br />
&nbsp; <span class="kw1">SELECT</span> min<span class="br0">&#40;</span>history_creation<span class="br0">&#41;</span> <span class="kw1">AS</span> mintstamp<span class="sy0">,</span> id <span class="kw1">AS</span> id<br />
&nbsp; <span class="kw1">FROM</span> client_hist<br />
&nbsp; <span class="kw1">WHERE</span> history_creation <span class="sy0">&gt;</span> THE<span class="sy0">-</span>TIME<span class="sy0">-</span>YOU<span class="sy0">-</span>NEED<br />
&nbsp; <span class="kw1">AND</span> id<span class="sy0">=</span> YOUR<span class="sy0">-</span>RECORD<span class="sy0">-</span>ID<br />
&nbsp; <span class="kw1">GROUP</span> <span class="kw1">BY</span> id<br />
<span class="br0">&#41;</span> <span class="kw1">AS</span> m <span class="kw1">ON</span> <span class="br0">&#40;</span>m<span class="sy0">.</span>id <span class="sy0">=</span> h<span class="sy0">.</span>id <span class="kw1">AND</span> m<span class="sy0">.</span>mintstamp <span class="sy0">=</span> h<span class="sy0">.</span>history_creation<span class="br0">&#41;</span>;</div>
</div>
<p>Basically the next record in the history after the time specified.</p>
<p>At this point so far as I can see we have two options. Either create a function that returns a specific type of ROW, or write a more generic history function to return only the id of the history record we need and not the whole row (If you look at the history creation function we are putting a histid column in there).</p>
<p>You could use this function in your queries to get the history record id out like this.</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="co1">&#8211; This function returns the histid you need to look at in your history table</span><br />
<span class="kw1">CREATE</span> <span class="kw1">OR</span> <span class="kw1">REPLACE</span> <span class="kw1">FUNCTION</span> select_hist_id<span class="br0">&#40;</span>tablename VARCHAR<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="sy0">,</span> recordid INTEGER<span class="sy0">,</span> tstamp TIMESTAMP<span class="br0">&#41;</span> RETURNS INTEGER <span class="kw1">AS</span> $$<br />
DECLARE<br />
&nbsp; curs REFCURSOR;<br />
&nbsp; vid INTEGER;<br />
BEGIN<br />
&nbsp; OPEN curs <span class="kw1">FOR</span> EXECUTE <span class="st0">&#8216;SELECT h.histid<br />
&nbsp; FROM &#8216;</span><span class="sy0">||</span>tablename<span class="sy0">||</span><span class="st0">&#8216;_hist AS h <br />
&nbsp; INNER JOIN (<br />
&nbsp; &nbsp; SELECT min(history_creation) AS mintstamp, id <br />
&nbsp; &nbsp; FROM &#8216;</span><span class="sy0">||</span>tablename<span class="sy0">||</span><span class="st0">&#8216;_hist<br />
&nbsp; &nbsp; WHERE history_creation &gt; &#8216;</span><span class="st0">&#8221;</span><span class="sy0">||</span>tstamp<span class="sy0">||</span><span class="st0">&#8221;</span><span class="st0">&#8216;<br />
&nbsp; &nbsp; AND id=&#8217;</span><span class="sy0">||</span>recid<span class="sy0">||</span><span class="st0">&#8216;<br />
&nbsp; &nbsp; GROUP BY id<br />
&nbsp; ) AS m ON (m.id = h.id AND m.mintstamp = h.history_creation);&#8217;</span>;</p>
<p>&nbsp; FETCH curs <span class="kw1">INTO</span> vid;</p>
<p>&nbsp; <span class="kw1">RETURN</span> vid;<br />
END;<br />
$$<br />
<span class="kw1">LANGUAGE</span> plpgsql;</p>
<p><span class="co1">&#8211; At this point you can just get ids like this</span><br />
<span class="co1">&#8211; records in client as of this time 2009-11-02 21:13:41.552601</span><br />
<span class="kw1">SELECT</span> select_hist_id<span class="br0">&#40;</span><span class="st0">&#8216;client&#8217;</span><span class="sy0">,</span> id<span class="sy0">,</span> <span class="st0">&#8217;2009-11-02 21:13:41.552601&#8242;</span>::TIMESTAMP<span class="br0">&#41;</span> <span class="kw1">FROM</span> client;</div>
</div>
<p>I&#8217;m sure you can figure out the rest.</p>
<p>Be careful this is very slow on large data sets. If you are planning to work on millions of records then you should consider building a history lookup function for each table either defining data types for your RECORD or using OUT variables.</p>
<div class="codesnip-container" >
<div class="sql codesnip" style="font-family:monospace;"><span class="kw1">CREATE</span> <span class="kw1">FUNCTION</span> foo<span class="br0">&#40;</span>recordid int<span class="sy0">,</span> firstname OUT VARCHAR<span class="br0">&#40;</span><span class="nu0">10</span><span class="br0">&#41;</span><span class="sy0">&#8230;</span><span class="br0">&#41;</span></div>
</div>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;submitHeadline=Tracking+database+records+history&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;title=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;title=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;title=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;bm_description=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;T=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;title=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;title=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+Tracking+database+records+history+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Ftracking-database-records-history%2F&amp;t=Tracking+database+records+history" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/tracking-database-records-history/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MVC frameworks users FAIL</title>
		<link>http://sapessi.com/2009/11/mvc-frameworks-users-fail/</link>
		<comments>http://sapessi.com/2009/11/mvc-frameworks-users-fail/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 12:23:16 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[My Works]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[Loose Coupling]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Struts]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=283</guid>
		<description><![CDATA[I have been interviewing quite a few people recently for a position as Java developer. Every single CV came with either a Struts or Spring mention. If not both. Oh yes, I have even discussed systems where both frameworks were used at the same time. Of course it&#8217;s your system, you are free to use [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>I have been interviewing quite a few people recently for a position as Java developer.<br />
Every single CV came with either a <a href="http://struts.apache.org/" target="_blank">Struts</a> or <a href="http://www.springsource.org" target="_blank">Spring</a> mention. If not both. Oh yes, I have even discussed systems where both frameworks were used at the same time.</p>
<p>Of course it&#8217;s your system, you are free to use whichever technology you prefer. However, you must also be able to explain why you picked that particular framework. And &#8220;It wasn&#8217;t me who picked it&#8221; is not a good answer. If you had a better idea why didn&#8217;t you question the decision?</p>
<p>Perhaps my problem is not exactly with MVC frameworks but with the people out there who use them without thinking things through. These are the sort of people who go around telling you that they used both Spring and Struts because it&#8217;s an &#8220;Architectural pattern&#8221;. The truth is that they haven&#8217;t thought about their architecture at all. They just thought that by using an MVC framework the problem would solve itself.</p>
<p>Yesterday I was reading a post by <a href="http://continuations.com/post/227973186/one-truth-about-technology-architecture-loose-coupling" target="_blank">Albert Wenger at Union Square Ventures about Loose Coupling</a>. I&#8217;m not going to repeat here what Albert already explained quite thoroughly. I will just say I agree with everything he said. Especially with this paragraph:</p>
<blockquote><p>So how does loose coupling enable scaling and innovation?  Scaling bottlenecks tend to move around as a site or service grows.  With loose coupling it is often possible to isolate a bottleneck and prevent it from slowing down everything else.<br />
&#8230;<br />
This also points to how loose coupling enables innovation.  Different teams can more easily be in charge of their own part and make changes to it more quickly.  Entirely new parts can be added more easily too (a great example here is Facebook adding chat).</p></blockquote>
<p>MVC frameworks themselves do not prevent loose coupling as an architectural decision. The problem is that most of the people who use them are the sort of over-engeneering maniacs who try to build the perfect system in one big blob of code, and inescapably, fail.<br />
So here&#8217;s my point. Using an MVC should not be considered an architectural decision. Architecture is at a much higher level.</p>
<p>Most architecture design nowadays show systems split horizontally.</p>
<p><img class="aligncenter size-full wp-image-284" title="TWING MVC structure" src="http://sapessi.com/wp-content/uploads/2009/11/TWING_MVC_structure_0.preview.png" alt="TWING MVC structure" width="300" height="153" /></p>
<p>This may allow your application to support higher load, but doesn&#8217;t give you the ability to isolate bottlenecks in your application. I believe what we&#8217;ll see in the future is architecture diagrams that are split vertically with every single component (or task your app has to perform) being completely independent from the rest, and feel free to use the MVC of your choice in each component. Just make sure you know why you decided to use it.</p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;submitHeadline=MVC+frameworks+users+FAIL&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;title=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;title=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;title=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;bm_description=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;T=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;title=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;title=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+MVC+frameworks+users+FAIL+@+http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F11%2Fmvc-frameworks-users-fail%2F&amp;t=MVC+frameworks+users+FAIL" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/11/mvc-frameworks-users-fail/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WebGL and O3D</title>
		<link>http://sapessi.com/2009/10/webgl-and-o3d/</link>
		<comments>http://sapessi.com/2009/10/webgl-and-o3d/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 13:51:36 +0000</pubDate>
		<dc:creator>Stefano Buliani</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[WWW]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[O3D]]></category>
		<category><![CDATA[OpenGL]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[WebGL]]></category>

		<guid isPermaLink="false">http://sapessi.com/?p=237</guid>
		<description><![CDATA[You may have read recently that Khronos is implementing something called WebGL. The objective of the project is to expose all of OpenGL ES calls to javascript. Thus allowing hardware accellerated 3d graphics within a browser. Google has also been working on an alternative, called O3D. Let&#8217;s first talk about the technical differencies between the [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;source=sapessi&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>You may have read recently that <a href="http://www.khronos.org/news/press/releases/khronos-webgl-initiative-hardware-accelerated-3d-graphics-internet/" target="_blank">Khronos is implementing something called WebGL</a>. The objective of the project is to expose all of OpenGL ES calls to javascript. Thus allowing hardware accellerated 3d graphics within a browser.<br />
Google has also been working on an alternative, called <a href="http://code.google.com/apis/o3d/" target="_blank">O3D</a>.</p>
<p>Let&#8217;s first talk about the technical differencies between the two projects.</p>
<p>O3D and WebGL while both trying to bring accellerated 3D graphics to the web have taken two fairly different courses. As I mentioned in the introduction to this post WebGL&#8217;s plan is just to expose to JavaScript OpenGL ES 2.0 APIs. Whereas Google&#8217;s solution is based on a browser plugin.</p>
<p>If we think about this we&#8217;ll soon realise that WebGL depends entirely on JavaScript. JavaScript, as of today, is a fairly slow language. This point was made in a <a href="http://groups.google.com/group/o3d-discuss/browse_thread/thread/7bfa31efcc03b5f6?pli=1" target="_blank">discussion thread on the O3D project website</a>.</p>
<blockquote><p>WebGL, being 100% dependent on JavaScript to do an application&#8217;s scene  graph, is going to have serious problems drawing more than a few pieces of  geometry at 60hz except in very special cases or on very fast machines. This  means WebGL requires JavaScript to:</p>
<p>*) do all parent-child matrix calculations for a transform graph.</p>
<p>*) all culling calculations (bounding box to frustum or other)</p>
<p>*) all sorting calculations for dealing with transparent objects.</p>
<p>*) all animation calculations.</p>
<p>As an example the kitty demo in O3D is doing linear  interpolations on 2710 floats to animate 170 transforms.  The point is not that the artist that created  the kitty should probably not have used 170 bones. <img src='http://sapessi.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />   Rather the point is it seems unlikely that JavaScript<br />
will be able to do that anytime soon and if it can then  just add more than one kitty to pass its limits.</p></blockquote>
<p>Also we have to keep in mind that not all hardware supports OpenGL ES.</p>
<p>O3D, By virtue of being a browser plugin written in C++, so an additional (hopefully fast) abstraction layer on top of the GPU, allowed Google to define a new set of APIs to expose to JavaScript and keep us (the JavaScript developers) away from the hardware. O3D will take care of the interaction with either DirectX or OpenGL.</p>
<p>Furthermore Google has open-sourced O3D through its Google Code website. Which means we can all have a look at their code and participate in the project. This resulted in a lot of documentation being available. For a full overview of how O3D works check out the <a href="http://code.google.com/apis/o3d/docs/techoverview.html" target="_blank">technical overview</a> on the O3D project page.</p>
<p>Do you think that this is the making of a new &#8220;Standards war&#8221;? Both Google and Khronos are adamant that they are not competing. However I believe that ultimately only one project will come out as a standard. As the complexity of 3D web applications increases it is not feasible to write code for both &#8220;APIs&#8221;. The only question for me at this point is who will come out on top.</p>
<p>To answer this I would look at the audience of the two projects. OpenGL has been out in the wild for a long while and many developers of videogames, or general graphic application, are already familiar with the APIs and the way it works, therefore it would probably make sense for them to embrace WebGL.<br />
Nonetheless O3D still stands a chance. For a very simple reason. It&#8217;s the web we&#8217;re talking about.</p>
<p>Frankly I can&#8217;t see myself playing a big videogame like fallout in a browser window anytime soon. These APIs will be used to enrich web application. Some examples are already coming out using O3D. Have a look at this <a href="http://o3d.googlecode.com/svn/trunk/samples/home-configurators/homedesigner.html" target="_blank">Home Designer</a>. Can&#8217;t you already see IKEA using it.<br />
My point here is that we&#8217;re not likely to see game developers switch to the web. We&#8217;re much more likely to see web developers start working on games or application involving 3d graphics, and this is where Google wins.</p>
<blockquote><p>O3D extends application JavaScript code with an <strong>API for 3D graphics</strong>. It uses standard JavaScript event processing and callback methods.</p></blockquote>
<p>As a web developer I can keep writing JavaScript code as I&#8217;m used to without having to change the way I think to how a game developer does.</p>
<p>What do you think?</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="425" height="344" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param name="src" value="http://www.youtube.com/v/uofWfXOzX-g&amp;rel=0&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1" /><param name="allowfullscreen" value="true" /><embed type="application/x-shockwave-flash" width="425" height="344" src="http://www.youtube.com/v/uofWfXOzX-g&amp;rel=0&amp;color1=0xb1b1b1&amp;color2=0xcfcfcf&amp;hl=en&amp;feature=player_embedded&amp;fs=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<!-- Social Bookmarks BEGIN -->
<div class="social_bookmark">
<a><strong><em>Bookmark It</em></strong></a>
<br />
<div class="d">
<br />
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://buzz.yahoo.com/submit?submitUrl=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;submitHeadline=WebGL+and+O3D&amp;submitSummary=" rel="nofollow" title="Add to&nbsp;Buzz"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/buzz.png" title="Add to&nbsp;Buzz" alt="Add to&nbsp;Buzz" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://del.icio.us/post?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;title=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Del.icio.us"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/delicious.png" title="Add to&nbsp;Del.icio.us" alt="Add to&nbsp;Del.icio.us" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://digg.com/submit?phase=2&amp;url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;title=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;digg"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/digg.png" title="Add to&nbsp;digg" alt="Add to&nbsp;digg" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.facebook.com/sharer.php?u=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F" rel="nofollow" title="Add to&nbsp;Facebook"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/facebook.png" title="Add to&nbsp;Facebook" alt="Add to&nbsp;Facebook" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.google.com/bookmarks/mark?op=edit&amp;output=popup&amp;bkmk=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;title=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Google Bookmarks"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/google.png" title="Add to&nbsp;Google Bookmarks" alt="Add to&nbsp;Google Bookmarks" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.mister-wong.com/index.php?action=addurl&amp;bm_url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;bm_description=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Mister Wong"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/misterwong.png" title="Add to&nbsp;Mister Wong" alt="Add to&nbsp;Mister Wong" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.netscape.com/submit/?U=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;T=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Netscape"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/netscape.png" title="Add to&nbsp;Netscape" alt="Add to&nbsp;Netscape" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://reddit.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;title=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;reddit"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/reddit.png" title="Add to&nbsp;reddit" alt="Add to&nbsp;reddit" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.stumbleupon.com/submit?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;title=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Stumble Upon"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/stumbleupon.png" title="Add to&nbsp;Stumble Upon" alt="Add to&nbsp;Stumble Upon" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://www.technorati.com/faves?add=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F" rel="nofollow" title="Add to&nbsp;Technorati"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/technorati.png" title="Add to&nbsp;Technorati" alt="Add to&nbsp;Technorati" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://tipd.com/submit.php?url=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F" rel="nofollow" title="Add to&nbsp;Tip'd"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/tipd.png" title="Add to&nbsp;Tip'd" alt="Add to&nbsp;Tip'd" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://twitter.com/home/?status=Check+out+WebGL+and+O3D+@+http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F" rel="nofollow" title="Add to&nbsp;Twitter"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/twitter.png" title="Add to&nbsp;Twitter" alt="Add to&nbsp;Twitter" /></a>
<a onclick="window.open(this.href, '_blank', 'scrollbars=yes,menubar=no,height=600,width=750,resizable=yes,toolbar=no,location=no,status=no'); return false;" href="http://myweb2.search.yahoo.com/myresults/bookmarklet?u=http%3A%2F%2Fsapessi.com%2F2009%2F10%2Fwebgl-and-o3d%2F&amp;t=WebGL+and+O3D" rel="nofollow" title="Add to&nbsp;Yahoo My Web"><img class="social_img" src="http://sapessi.com/wp-content/plugins/social-bookmarks/images/yahoo.png" title="Add to&nbsp;Yahoo My Web" alt="Add to&nbsp;Yahoo My Web" /></a>
<br />
</div>
</div>
<!-- Social Bookmarks END -->
]]></content:encoded>
			<wfw:commentRss>http://sapessi.com/2009/10/webgl-and-o3d/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>
