<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
 <title>Arun Thampi</title>
 
 <link href="http://mclov.in/" />
 <updated>2013-02-04T14:36:42-08:00</updated>
 <id>http://mclov.in/</id>
 <author>
   <name>Arun Thampi</name>
   <email>arun.thampi@gmail.com</email>
 </author>
 
 
 <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/mclovin" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="mclovin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
   <title>Introducing Action.IO - A Revolutionary New Cloud Development Platform</title>
   <link href="http://mclov.in/2012/06/21/introducing-action-io-a-revolutionary-new-cloud-development-platform.html" />
   <updated>2012-06-21T00:00:00-07:00</updated>
   <id>http://mclov.in/2012/06/21/introducing-action-io-a-revolutionary-new-cloud-development-platform</id>
   <content type="html">&lt;h1 id='introducing_actionio__a_revolutionary_new_cloud_development_platform'&gt;&lt;a href='/2012/06/21/introducing-action-io-a-revolutionary-new-cloud-development-platform.html'&gt;Introducing Action.IO - A Revolutionary New Cloud Development Platform&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;21 Jun 2012 - Singapore&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s been a crazy few sleepless weeks as we ploughed through some pretty heavy tech problems, but it&amp;#8217;s finally a reality. We are proud to take the covers off &lt;a href='https://www.action.io'&gt;Action.IO&lt;/a&gt;. It&amp;#8217;s days like these which make it all worth it, as I sit here with my friends at 3AM basking in all the love that we&amp;#8217;re getting from our fellow developers. It is truly humbling.&lt;/p&gt;
&lt;iframe src='http://www.youtube.com/embed/9GIylBBh2zk?rel=0' frameborder='0' height='360' width='640'&gt;   &lt;/iframe&gt;
&lt;p&gt;We have some amazing stories to tell about all the code that has gone into action.io, but that is for another day. In the meantime, take a look at this walkthrough video, and sign up to be part of the future.&lt;/p&gt;

&lt;p&gt;Also, would really appreciate some &lt;a href='http://news.ycombinator.com'&gt;Hacker News love&lt;/a&gt; for our story (look for action.io on the homepage)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/aWhFABczieA" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>Journey - The Unofficial Path Client for OS X</title>
   <link href="http://mclov.in/2012/02/28/journey-the-unofficial-path-client-for-os-x.html" />
   <updated>2012-02-28T00:00:00-08:00</updated>
   <id>http://mclov.in/2012/02/28/journey-the-unofficial-path-client-for-os-x</id>
   <content type="html">&lt;h1 id='journey__the_unofficial_path_client_for_os_x'&gt;&lt;a href='/2012/02/28/journey-the-unofficial-path-client-for-os-x.html'&gt;Journey - The Unofficial Path Client for OS X&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;28 Feb 2012 - Singapore&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s taken us a while, but we&amp;#8217;re happy to announce that the little side project we&amp;#8217;ve been working on &amp;#8211; an &lt;a href='http://journeyformac.com'&gt;unofficial Path Client for OS X&lt;/a&gt; is live. What&amp;#8217;s more it is open-source and is available under an MIT License on &lt;a href='http://github.com/JourneyForMac/Journey'&gt;GitHub&lt;/a&gt;. You can read a more in-depth behind-the-scenes story &lt;a href='http://dev.anideo.com/2012/02/26/introducing-journey-the-unofficial-path-client-for-os-x.html'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s been a challenge working on &lt;a href='http://getdenso.com'&gt;Denso&lt;/a&gt; as well as this side project, but I had a lot of fun working with &lt;a href='http://twitter.com/raingrove'&gt;Peter&lt;/a&gt;, &lt;a href='http://twitter.com/ntluan'&gt;Kent&lt;/a&gt; and &lt;a href='http://twitter.com/ajhit406'&gt;AJ&lt;/a&gt; on this Journey ;) (no pun intended).&lt;/p&gt;

&lt;p&gt;We think the &lt;a href='http://anideo.com'&gt;Anideo&lt;/a&gt; Hackathon experiment has been a success and we hope to continue to host more hackathons and foster a culture of building good software here in Singapore.&lt;/p&gt;

&lt;p&gt;Real Artists Ship.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/LmAI86NqgPU" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>Path uploads your entire iPhone address book to its servers</title>
   <link href="http://mclov.in/2012/02/08/path-uploads-your-entire-address-book-to-their-servers.html" />
   <updated>2012-02-08T00:00:00-08:00</updated>
   <id>http://mclov.in/2012/02/08/path-uploads-your-entire-address-book-to-their-servers</id>
   <content type="html">&lt;h1 id='path_uploads_your_entire_iphone_address_book_to_its_servers'&gt;&lt;a href='/2012/02/08/path-uploads-your-entire-address-book-to-their-servers.html'&gt;Path uploads your entire iPhone address book to its servers&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;8 Feb 2012 - Singapore&lt;/p&gt;

&lt;h3 id='update_2'&gt;Update #2&lt;/h3&gt;

&lt;p&gt;Path has released a &lt;a href='http://itunes.apple.com/us/app/path/id403639508?mt=8'&gt;new version&lt;/a&gt; of the app which asks for permission before it sends your address book to its servers and has &lt;a href='http://blog.path.com/post/17274932484/we-are-sorry'&gt;blogged&lt;/a&gt; about the episode.&lt;/p&gt;

&lt;h3 id='update_1'&gt;Update #1&lt;/h3&gt;

&lt;p&gt;Dave Morin, the CEO of Path has responded in the comments and I&amp;#8217;ve pasted it below. As an aside &amp;#8211; never in my wildest dreams did I imagine this to blow up like this. I hope we can keep calm and continue to discuss this sensibly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Arun, thanks for pointing this out. We actually think this is an important conversation and take this very seriously. We upload the address book to our servers in order to help the user find and connect to their friends and family on Path quickly and effeciently as well as to notify them when friends and family join Path. Nothing more.&lt;/p&gt;

&lt;p&gt;We believe that this type of friend finding &amp;amp; matching is important to the industry and that it is important that users clearly understand it, so we proactively rolled out an opt-in for this on our Android client a few weeks ago and are rolling out the opt-in for this in 2.0.6 of our iOS Client, pending App Store approval.&lt;/p&gt;

&lt;p&gt;Dave Morin Co-Founder and CEO of Path&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id='original_post'&gt;Original Post&lt;/h3&gt;

&lt;p&gt;It all started innocently enough. I was thinking of implementing a Path Mac OS X app as part of our regularly scheduled &lt;a href='http://dev.anideo.com/2012/01/14/the-inaugural-anideo-hackathon.html'&gt;hackathon&lt;/a&gt;. Using the awesome &lt;a href='http://mitmproxy.org'&gt;mitmproxy&lt;/a&gt; tool which was featured on the front page of &lt;a href='https://news.ycombinator.com/item?id=3556688'&gt;Hacker News&lt;/a&gt; yesterday, I started to observe the various API calls made to Path&amp;#8217;s servers from the iPhone app. It all seemed harmless enough until I observed a &lt;code&gt;POST&lt;/code&gt; request to &lt;code&gt;https://api.path.com/3/contacts/add&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Upon inspecting closer, I noticed that my &lt;strong&gt;entire address book&lt;/strong&gt; (including full names, emails and phone numbers) was being sent as a plist to Path. Now I don&amp;#8217;t remember having given permission to Path to access my address book and send its contents to its servers, so I created a completely new &amp;#8220;Path&amp;#8221; and repeated the experiment and I got the same result - my address book was in Path&amp;#8217;s hands.&lt;/p&gt;

&lt;h3 id='disclaimer'&gt;Disclaimer&lt;/h3&gt;

&lt;p&gt;I&amp;#8217;m not insinuating that Path is doing something nefarious with my address book but I feel quite violated that my address book is being held remotely on a third-party service. I love Path as an iOS app and I think there are some brilliant people working on it, but this seems a little creepy. I wonder how many other iOS apps actually do the same&amp;#8230;&lt;/p&gt;

&lt;h3 id='the_trail_of_events'&gt;The Trail of Events&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; &lt;code&gt;https://api.path.com/1/users.plist&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As soon as you create a new account to Path, a call is made to &lt;code&gt;https://api.path.com/1/users.plist&lt;/code&gt; with your first name, last name, gender and password. An plist is returned which contains the user&amp;#8217;s ID as well as other information such as the date of creation.&lt;/p&gt;
&lt;img class='screenshot' src='/images/path/signup-1.png' /&gt;
&lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; &lt;code&gt;https://api.path.com/3/moment/feed/home?all_friends=1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This API call uses basic HTTP authentication (with a certain key) to obtain some metadata about myself - from the binary plist file it looks like it contains my first name, last name, cover photo, profile picture, etc.&lt;/p&gt;
&lt;img class='screenshot' src='/images/path/feed-home-2.png' /&gt;
&lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt;&lt;code&gt;https://api.path.com/3/contacts/add&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the actual offending call which uploads my entire address book to Path.&lt;/p&gt;
&lt;img class='screenshot' src='/images/path/contacts-add-3.png' /&gt;
&lt;p&gt;This is followed by normal API calls which among others, updates my location, fetches my activity stream and tracks events within the app using &lt;a href='http://mixpanel.com'&gt;Mixpanel&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='how_to_do_this_at_home'&gt;How to do this at home&lt;/h3&gt;

&lt;p&gt;This has been tried out on Mac OS X Lion 10.7.2.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the &lt;a href='http://mitmproxy.org/'&gt;mitmproxy&lt;/a&gt; tool and set it up by going to the folder of mitmproxy and running &lt;code&gt;sudo python setup.py install&lt;/code&gt;. If all goes well, mitmproxy must be available in your $PATH.&lt;/li&gt;

&lt;li&gt;Start mitmproxy by running &lt;code&gt;mitmproxy&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;Obtain the IP address of your computer by running &lt;code&gt;ifconfig en1&lt;/code&gt; (or whatever is the interface that you are using).&lt;/li&gt;

&lt;li&gt;Set the proxy on your iPhone by going to your wireless settings, setting the proxy to be &amp;#8220;Manual&amp;#8221;, and set the IP to be your computer&amp;#8217;s IP and the port as 8080.&lt;/li&gt;
&lt;/ol&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/a8SvDuyibGk" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>A Fresh Coat of Bootstrapped Paint</title>
   <link href="http://mclov.in/2011/12/30/a-fresh-coat-of-bootstrapped-paint.html" />
   <updated>2011-12-30T00:00:00-08:00</updated>
   <id>http://mclov.in/2011/12/30/a-fresh-coat-of-bootstrapped-paint</id>
   <content type="html">&lt;h1 id='a_fresh_coat_of_bootstrapped_paint'&gt;&lt;a href='/2011/12/30/a-fresh-coat-of-bootstrapped-paint.html'&gt;A Fresh Coat of Bootstrapped Paint&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;30 Dec 2011 - Singapore&lt;/p&gt;

&lt;p&gt;Decided to give my blog a fresh coat of &lt;a href='http://twitter.github.com/bootstrap'&gt;Bootstrap&lt;/a&gt; paint. I used Bootstrap for a small project called &lt;a href='http://muxx.it'&gt;muxx.it&lt;/a&gt; earlier this month and loved it &amp;#8212; it is definitely one of the best pieces of software to come out this year (especially for design-sense-challenged folks such as myself).&lt;/p&gt;

&lt;p&gt;The main reason I wanted to re-design my blog was that I&amp;#8217;ve been meaning to pen a year-end of review of what&amp;#8217;s been quite a roller-coaster twelve months. I didn&amp;#8217;t want to publish something on what was quite frankly, an ugly and dated site, and so here we are.&lt;/p&gt;

&lt;p&gt;Hopefully I&amp;#8217;ll get down to writing my year-end review in the next couple of days.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/thpIA07oXME" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>Fergie - Gameplan's Stats Dashboard</title>
   <link href="http://mclov.in/2010/06/24/fergie-gameplans-stats-dashboard-presentation-given-at-the-singapore-ruby-brigade-june-meetup.html" />
   <updated>2010-06-24T00:00:00-07:00</updated>
   <id>http://mclov.in/2010/06/24/fergie-gameplans-stats-dashboard-presentation-given-at-the-singapore-ruby-brigade-june-meetup</id>
   <content type="html">&lt;h1 id='fergie__gameplans_stats_dashboard'&gt;&lt;a href='/2010/06/24/fergie-gameplans-stats-dashboard-presentation-given-at-the-singapore-ruby-brigade-june-meetup.html'&gt;Fergie - Gameplan&amp;#8217;s Stats Dashboard&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;24 Jun 2010 - Singapore&lt;/p&gt;

&lt;p&gt;I gave a quick presentation yesterday at the June installment of the &lt;a href='http://groups.google.com/group/singapore-rb'&gt;Singapore Ruby Brigade&lt;/a&gt; held at &lt;a href='http://hackerspace.sg/'&gt;HackerspaceSG&lt;/a&gt;. As always, SRB is a great place to meet people and catch up with all the great work that&amp;#8217;s going on here. Many thanks to &lt;a href='http://twitter.com/jasonong'&gt;Jason&lt;/a&gt; for organising the monthly meetups and to Zhenyi for his camerawork yesterday which has brought SRB June online.&lt;/p&gt;

&lt;p&gt;It was also great to listen to &lt;a href='http://twitter.com/mingyeow'&gt;Ming Yeow&lt;/a&gt; and his experiences (both the highs and the lows) while building &lt;a href='http://mrtweet.com/'&gt;MrTweet&lt;/a&gt; as well as experiencing every layer of the &amp;#8216;startup stack&amp;#8217; (as he put it) such as product management, fund raising, hiring and networking. For a person who&amp;#8217;s been three months into a startup, his talk definitely gave some good pointers as well as validation for the processes &lt;a href='http://gameplanapp.com'&gt;we&amp;#8217;ve&lt;/a&gt; already implemented.&lt;/p&gt;

&lt;p&gt;My slides from yesterday are &lt;a href='http://www.slideshare.net/gameplanapp/gameplans-panicinspired-stats-dashboard-called-fergie'&gt;at Slideshare&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/t3t25UbV2BA" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>The similarity between the iPhone in 2010 and Ruby On Rails in 2007</title>
   <link href="http://mclov.in/2010/04/30/the-similarity-between-the-iphoneipad-and-ruby-on-rails.html" />
   <updated>2010-04-30T00:00:00-07:00</updated>
   <id>http://mclov.in/2010/04/30/the-similarity-between-the-iphoneipad-and-ruby-on-rails</id>
   <content type="html">&lt;h1 id='the_similarity_between_the_iphone_in_2010_and_ruby_on_rails_in_2007'&gt;&lt;a href='/2010/04/30/the-similarity-between-the-iphoneipad-and-ruby-on-rails.html'&gt;The similarity between the iPhone in 2010 and Ruby On Rails in 2007&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;30 Apr 2010 - Singapore&lt;/p&gt;

&lt;p&gt;The whole brouhaha about the openness (or lack thereof) of Apple and its evilness has had me confused for a while now. On the one hand, I really admire Apple&amp;#8217;s gumption in taking on the behemoth that was the mobile phone industry, turning it around and winning in the marketplace because of its sheer awesomeness. On the other hand, the closed nature of the AppStore, the haphazard way in which Apple rejects apps and it&amp;#8217;s borderline anti-competitive stance against Adobe and languages which are neither C or C++ have gone against the principles of openness of the Web - principles I firmly believe in.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s when the epiphany struck. Turn your clocks back to 2005, when a Danish guy with a funny accent demoed how easy it was to make an AJAX-powered blog in a shiny new web-framework called Ruby On Rails. While there were existing web frameworks at the time (Struts, Servlets, PHP et al), Rails changed the way you developed web applications. No more spaghetti SQL in your HTML templates, no more worrying about databases and no more figuring out how you can do AJAX (because Rails came with a snazzy DSL called RJS). For a developer who had no experience doing web applications and databases, Rails was a dream come true. It is my belief that Rails empowered a new generation of developers (and cross-over developers like myself) to get into web application development.&lt;/p&gt;

&lt;p&gt;Even after a couple of years after the introduction of Rails, all was not well. It was still a bitch to deploy your web application. Ruby as a language was severely handicapped by poor performance, as compared to its other counterparts such as PHP and Python, which led to a lot of FUD that Rails can&amp;#8217;t scale. The enterprise mocked Rails as a toy and not something you can build &amp;#8220;serious&amp;#8221; applications with. Even serious Rails developers complained that Rails forced you to tread the golden-path prescribed by DHH, and if you had to deviate from it, it certainly meant that you were entering a ball of hurt (Merb was a result of such a complaint).&lt;/p&gt;

&lt;p&gt;Fast-forward to 2010, and look at how all-encompassing the Rails landscape has become. Ruby On Rails has become such a game-changer that there are multiple companies providing simple deployment solutions which enable you to deploy web applications to the cloud with the press of a button. Sun (sorry EngineYard), Microsoft, Smalltalk and Apple have multiple implementations of Ruby all conforming to a single spec. The fact that Microsoft (and the erstwhile Sun) is pushing for IronRuby to become a part of the .NET suite is certainly proof that Ruby is ready for the enterprise. And, Merb itself is being merged into Rails 3 to address concerns of modularity, while still maintaining the Rails ethos of convention over configuration and sensible defaults.&lt;/p&gt;

&lt;p&gt;So, on to the iPhone. The iPhone has changed the mobile phone in a similar way to how Rails changed the world for web developers. Can you imagine being able to distribute applications to mobile phones and actually make money off it before 2008? Can you imagine the mobile internet being mainstream before the iPhone? The iPhone is still a relative child in &amp;#8220;technology-years&amp;#8221;. Call me naive but in my opinion, the iPhone platform is not evil, it&amp;#8217;s just young and immature. Distractions such as the dogmatic App Store and the perceived anti-competitiveness are growing pains. Apple and the iPhone have been able to do so much more than so many other mobile phone companies in the last 20 years. So give it some time.&lt;/p&gt;

&lt;p&gt;I understand that there are crucial differences between the stories of Rails and the iPhone - the number one being that Rails itself was open-source and thus is the exact opposite of the iPhone/iPhone OS. But the whole Rails 3 project shows the ability of the Rails Core (and DHH) to admit that Rails is not perfect and that it&amp;#8217;s willing to adapt and keep ahead of the competition. They realised that it&amp;#8217;s not just enough that Rails is easy to use, it now has to be both powerful and modular &lt;em&gt;and&lt;/em&gt; easy to use. They felt that it was now mature and mainstream enough (in that there were enough Rails copycats) that they needed to raise the bar again.&lt;/p&gt;

&lt;p&gt;Similarly, it&amp;#8217;s absurd to think that the iPhone and it&amp;#8217;s associated ecosystem will not adapt to how users view their mobile phones in a few years time. The mobile web will be more mature by then and mobile operating systems and hardware will have advanced to such a stage that it would make my MacBook Pro feel like a calculator from the 80s. Most importantly, more people will begin to see mobile phones as information/communication appliances and not just devices used to make calls. It&amp;#8217;s in Apple&amp;#8217;s best interests to adapt and keep raising the bar, and it is my belief that they will.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/uNkANWvrJBc" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>Two tidbits from first three days of building Gameplan</title>
   <link href="http://mclov.in/2010/04/06/two-tidbits-from-first-three-days-of-building-gameplan.html" />
   <updated>2010-04-06T00:00:00-07:00</updated>
   <id>http://mclov.in/2010/04/06/two-tidbits-from-first-three-days-of-building-gameplan</id>
   <content type="html">&lt;h1 id='two_tidbits_from_first_three_days_of_building_gameplan'&gt;&lt;a href='/2010/04/06/two-tidbits-from-first-three-days-of-building-gameplan.html'&gt;Two tidbits from first three days of building Gameplan&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;6 Apr 2010 - Singapore&lt;/p&gt;

&lt;p&gt;So as you may or may not know, &lt;a href='http://andycroll.com'&gt;Andy&lt;/a&gt; and I are building &lt;a href='http://gameplanapp.com'&gt;Gameplan&lt;/a&gt; (which, to paraphrase &lt;a href='http://thedailyshow.com'&gt;Jon Stewart&lt;/a&gt; will be the best &lt;em&gt;expletive&lt;/em&gt; sports league management software on the planet). We&amp;#8217;ve already started in great earnest, and we&amp;#8217;re looking forward to kicking on and making lots of progress. By the way, we are chronicling our progress at &lt;a href='http://nakedstartup.com'&gt;Naked Startup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There&amp;#8217;re two interesting technical gotchas which we experienced in the last three days, that I&amp;#8217;d like to share.&lt;/p&gt;

&lt;h2 id='how_do_you_test_that_a_model_acts_as_authentic'&gt;How do you test that a model acts_as_authentic?&lt;/h2&gt;

&lt;p&gt;We could check if any of the standard AuthLogic methods, such as password or password= are present in the model, but that felt a little dirty. The other way is to see if AuthLogic modules are included in the model. Trouble is that, AuthLogic includes a bunch of modules to every ActiveRecord class as Rails boots up. However, we discovered that there are certain modules which are only included when you use the method &amp;#8216;acts_as_authentic&amp;#8217; in your class. So the corresponding unit test will be:&lt;/p&gt;
&lt;script src='http://gist.github.com/357565.js?file=acts_as_authentic_user.rb'&gt;  &lt;/script&gt;
&lt;p&gt;If there is a simpler way we&amp;#8217;ve missed, we&amp;#8217;d love to hear about it!&lt;/p&gt;

&lt;h2 id='uniqueness_validation_tests_fail_in_shoulda'&gt;Uniqueness validation tests fail in Shoulda&lt;/h2&gt;

&lt;p&gt;All we wanted to do was to test whether we&amp;#8217;ve included the uniqueness_validation for the &amp;#8216;permalink&amp;#8217; attribute in our model, but it gave us a cryptic &amp;#8216;Can&amp;#8217;t find Competition&amp;#8217; error. Turns out that existing records in a database is a pre-requisite for Shoulda to run these tests successfully, as &lt;a href='http://blog.tuxicity.se/rails/shoulda/testing/2009/06/03/shoulda-requires-a-database-record.html'&gt;Johan Andersson&lt;/a&gt; points out. The corresponding unit test will be:&lt;/p&gt;
&lt;script src='http://gist.github.com/357574.js?file=competition_test.rb'&gt;  &lt;/script&gt;
&lt;p&gt;As a bonus tidbit, I&amp;#8217;d just like to say that pair programming is pretty darn awesome. For the last few days, I haven&amp;#8217;t checked my email, Twitter, Facebook or browsed anything other than RDocs (and Googling for answers) any time between 9am and 6pm, and that makes us very productive. Long may it continue!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/VVuoVPre5Fc" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>Sending SMS's using iPhone SDK 3.0 - A workaround</title>
   <link href="http://mclov.in/2009/11/02/sending-smss-using-iphone-sdk-30-a-workaround.html" />
   <updated>2009-11-02T00:00:00-08:00</updated>
   <id>http://mclov.in/2009/11/02/sending-smss-using-iphone-sdk-30-a-workaround</id>
   <content type="html">&lt;h1 id='sending_smss_using_iphone_sdk_30__a_workaround'&gt;&lt;a href='/2009/11/02/sending-smss-using-iphone-sdk-30-a-workaround.html'&gt;Sending SMS&amp;#8217;s using iPhone SDK 3.0 - A workaround&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;2 Nov 2009 - Singapore&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been trying to find a way to send SMS&amp;#8217;s as part of my upcoming iPhone app - &lt;a href='http://www.moviefuapp.com'&gt;MovieFu&lt;/a&gt;. Essentially why I need to access the SMS functionality is for a user to quickly share movie showtimes with friends who don&amp;#8217;t have access to the Internet.&lt;/p&gt;

&lt;h2 id='the_iphone_url_scheme'&gt;The iPhone URL Scheme&lt;/h2&gt;

&lt;p&gt;The &lt;a href='http://developer.apple.com/iphone/library/featuredarticles/iPhoneURLScheme_Reference/Articles/sms.html'&gt;iPhone OS Reference Library&lt;/a&gt; recommends that we use the &amp;#8216;sms://&amp;#8217; protocol to send SMS&amp;#8217;s. Essentially if we need to send an SMS to a number such as 87654321, we can launch the SMS app with the URL &amp;#8216;sms://87654321&amp;#8217;. While this is fine and dandy for most cases, I would also like the body of the SMS pre-filled so that the user does not have to re-enter all that information.&lt;/p&gt;

&lt;h2 id='my_workaround_which_hopefully_isnt_a_pita'&gt;My workaround (which hopefully isn&amp;#8217;t a PITA)&lt;/h2&gt;

&lt;p&gt;Bear in mind that this solution will probably be rendered obsolete by the next update of iPhone OS which will include an awesome MFSMSComposeViewController (sic) of some sort, but for the time being my workaround flows like this:&lt;/p&gt;

&lt;p&gt;The body of the SMS which I want to be sent is copied to the clipboard. The user is then presented with a UIActionSheet which provides this option: &amp;#8216;Copy and Paste in SMS&amp;#8217;. When the user selects that option, the SMS app is opened with a blank recipient list, and the user can then tap once in the body to invoke the &amp;#8216;copy-paste-select-all&amp;#8217; widget, thus allowing you to paste the details of the showtime you want to share.&lt;/p&gt;

&lt;p&gt;This is illustrated below:&lt;/p&gt;

&lt;p class='image'&gt;&lt;img src='/images/blog/actionsheet.png' alt='Sending SMS Action Sheet' /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Above&lt;/strong&gt;: Action Sheet which brings up the various options, one of which is &amp;#8216;Copy and Paste in SMS&amp;#8217;.&lt;/p&gt;

&lt;p class='image'&gt;&lt;img src='/images/blog/paste.jpg' alt='SMS App Launches with this screen' /&gt; &lt;img src='/images/blog/pasted.jpg' alt='After Pasting this is what it looks like' /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Above&lt;/strong&gt;: Once the SMS screen is launched, the user can then tap the text area, by which time the details would have copied to the clipboard, bring up the &amp;#8216;paste&amp;#8217; menu and voila, the details are ready to be sent to your friends.&lt;/p&gt;

&lt;p&gt;The associated code-snippet is here:&lt;/p&gt;
&lt;script src='http://gist.github.com/224068.js'&gt;  &lt;/script&gt;
&lt;h2 id='feedback'&gt;Feedback&lt;/h2&gt;

&lt;p&gt;What do you guys think of this solution? While this is not ideal, I think this solves the problem of pre-generating content for an SMS to be sent. Would love to hear what you think about it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/84GAInzGcDg" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>An explanation of the CouchDB views</title>
   <link href="http://mclov.in/2009/08/31/an-explanation-of-the-couchdb-view-powering-icanhazthreadcoms-homepage.html" />
   <updated>2009-08-31T00:00:00-07:00</updated>
   <id>http://mclov.in/2009/08/31/an-explanation-of-the-couchdb-view-powering-icanhazthreadcoms-homepage</id>
   <content type="html">&lt;h1 id='an_explanation_of_the_couchdb_views'&gt;&lt;a href='/2009/08/31/an-explanation-of-the-couchdb-view-powering-icanhazthreadcoms-homepage.html'&gt;An explanation of the CouchDB views&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;31 Aug 2009 - Singapore&lt;/p&gt;

&lt;p&gt;Just wanted to pen this down so that I don&amp;#8217;t forget the logic behind the map-reduce function used to generate the content for &lt;a href='http://i.canhazthread.com'&gt;i.canhazthread.com&lt;/a&gt; homepage.&lt;/p&gt;

&lt;h2 id='requirements'&gt;Requirements&lt;/h2&gt;

&lt;p&gt;i.canhazthread.com stores threads and replies as separate documents, with threads having the field &lt;em&gt;type&lt;/em&gt; set to &lt;em&gt;thread&lt;/em&gt; and replies having the field &lt;em&gt;type&lt;/em&gt; set to &lt;em&gt;reply&lt;/em&gt;. My requirement was to have the homepage display all threads in the database with the following attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text of the thread&lt;/li&gt;

&lt;li&gt;Name of the author of the thread&lt;/li&gt;

&lt;li&gt;Timestamp of the thread&lt;/li&gt;

&lt;li&gt;Timestamp of the last reply of the thread&lt;/li&gt;

&lt;li&gt;Threads must be sorted by recency (most recent thread first)&lt;/li&gt;

&lt;li&gt;Number of replies associated with the thread&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This seems quite trivial, but my biggest requirement was that this must be possible using &lt;em&gt;one&lt;/em&gt; HTTP call and not n + 1 (where n is the number of threads =&amp;gt; 1 call to get all threads, and n calls to get details of replies for each thread).&lt;/p&gt;

&lt;h2 id='the_map_function'&gt;The Map Function&lt;/h2&gt;

&lt;p&gt;The map function is relatively straightforward as given below:&lt;/p&gt;
&lt;script src='http://gist.github.com/178696.js'&gt;  &lt;/script&gt;
&lt;p&gt;This uses the &lt;a href='http://www.cmlenz.net/archives/2007/10/couchdb-joins'&gt;view collation technique&lt;/a&gt; as described by Christopher Lenz and it basically emits k-v pairs where the keys represent the ID&amp;#8217;s of the threads and the values can be either threads or replies; but replies will always be preceded by the thread that it belongs to. Something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thread 1 &lt;em&gt;T1&lt;/em&gt; (id = &lt;em&gt;IDT1&lt;/em&gt;, key = &lt;em&gt;IDT1&lt;/em&gt; ) -&amp;gt; Reply 1 to Thread 1 &lt;em&gt;RT1&lt;/em&gt; (id = &lt;em&gt;IDR1&lt;/em&gt;, key = &lt;em&gt;IDT1&lt;/em&gt;) -&amp;gt; Reply 2 to Thread 1 &lt;em&gt;RT2&lt;/em&gt; (id = &lt;em&gt;IDR2&lt;/em&gt;, key = &lt;em&gt;IDT1&lt;/em&gt;) -&amp;gt; Reply 3 to Thread 1 &lt;em&gt;RT3&lt;/em&gt; (id = &lt;em&gt;IDR3&lt;/em&gt;, key = &lt;em&gt;IDT1&lt;/em&gt;)&lt;/li&gt;

&lt;li&gt;Thread 2 &lt;em&gt;T2&lt;/em&gt; (id = &lt;em&gt;IDT2&lt;/em&gt;, key = &lt;em&gt;IDT2&lt;/em&gt;)&lt;/li&gt;

&lt;li&gt;Thread 3 &lt;em&gt;T3&lt;/em&gt; (id = &lt;em&gt;IDT3&lt;/em&gt;, key = &lt;em&gt;IDT3&lt;/em&gt;) -&amp;gt; Reply 1 to Thread 3 &lt;em&gt;RT4&lt;/em&gt; (id = &lt;em&gt;IDR4&lt;/em&gt;, key = &lt;em&gt;IDT3&lt;/em&gt;) -&amp;gt; Reply 2 to Thread 3 &lt;em&gt;RT5&lt;/em&gt; (id = &lt;em&gt;IDR5&lt;/em&gt;, key = &lt;em&gt;IDT3&lt;/em&gt;)&lt;/li&gt;

&lt;li&gt;Thread 4 &lt;em&gt;T4&lt;/em&gt; (id = &lt;em&gt;IDT4&lt;/em&gt;, key = &lt;em&gt;IDT4&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='the_reduce_function'&gt;The Reduce Function&lt;/h2&gt;

&lt;p&gt;The reduce function is where all the magic happens. (Not pasting the entire source here, please check it out &lt;a href='http://github.com/arunthampi/icanhazthread/blob/98575f2d370aa9676da7c6022bce7ee0754952ee/views/threads_with_num_replies/reduce.js'&gt;here&lt;/a&gt;)&lt;/p&gt;

&lt;h3 id='associativity_and_commutativity'&gt;Associativity and Commutativity&lt;/h3&gt;

&lt;p&gt;One very important thing we have to keep in mind while implementing reduce functions (and which burned me a few times) is that views have to be associative and commutative, i.e. we should not assume that the reduce function will be called in a given order.&lt;/p&gt;

&lt;h3 id='group_level'&gt;Group Level&lt;/h3&gt;

&lt;p&gt;One other important feature of reduce functions (as detailed &lt;a href='http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views'&gt;here&lt;/a&gt;) which allowed me to do this is the group_level parameter. This lets you run the reduce function for sets of unique keys. In i.canhazthread.com&amp;#8217;s case, for example, when group_level is set to 1, the reduce function will be run four times - for Thread 1 ands its 3 associated replies; Thread 2 and its zero replies; Thread 3 and its 2 associated replies and finally Thread 4 - since each group has the same key (i.e. the ID of the thread). Thus when group_level=1, the final output of the reduce function will be like so:&lt;/p&gt;
&lt;script src='http://gist.github.com/178706.js'&gt;  &lt;/script&gt;
&lt;h3 id='rereduce'&gt;Rereduce&lt;/h3&gt;

&lt;p&gt;The other captcha we have to keep in mind is the &lt;em&gt;rereduce&lt;/em&gt; property of CouchDB reduce functions. Rereduce is a step which happens with CouchDB when the reduce function is called not with the emitted k-v pairs from the map function, but with intermediate computed values from a previous call of the reduce function itself. Confused? Let me try again.&lt;/p&gt;

&lt;p&gt;In the example for the first group (i.e. Thread 1 and its 3 associated replies) the reduce function can be called in many possible ways, two of which are detailed below:&lt;/p&gt;

&lt;p&gt;The simplest scenario is when all four values are passed to the reduce function at once. In this case, re-reduce is not called and we get the final output with a single call of the reduce function.&lt;/p&gt;

&lt;p&gt;The extreme case when the reduce function is called separately for each object: i.e. Reduce is called first for Thread 1; a second time for Reply 1; a third time for Reply 2 and finally a fourth time for Reply 3. Each call of the reduce function emits an intermediate value which will be sent again to the reduce function with the &lt;em&gt;rereduce&lt;/em&gt; parameter set to true. The reduce function must be able to handle this scenario.&lt;/p&gt;

&lt;p&gt;The two scenarios are listed below:&lt;/p&gt;

&lt;h4 id='scenario_1'&gt;Scenario 1&lt;/h4&gt;

&lt;p&gt;Reduce function is called &lt;em&gt;once&lt;/em&gt;, like this:&lt;/p&gt;

&lt;p&gt;reduce(&lt;span&gt;&lt;span&gt;IDT1, IDT1&lt;/span&gt;, &lt;span&gt;IDT1, IDR1&lt;/span&gt;, &lt;span&gt;IDT1, IDR2&lt;/span&gt;, &lt;span&gt;IDT1, IDR3&lt;/span&gt;&lt;/span&gt;, &lt;span&gt;T1, RT1, RT2, RT3&lt;/span&gt;, false); -&amp;gt; This emits the final value of the reduce function without any intermediate steps.&lt;/p&gt;

&lt;h4 id='scenario_2'&gt;Scenario 2&lt;/h4&gt;

&lt;p&gt;Reduce function is called &lt;em&gt;multiple times&lt;/em&gt;, like this:&lt;/p&gt;

&lt;p&gt;reduce(&lt;span&gt;IDT1, IDT1&lt;/span&gt;, &lt;span&gt;T1&lt;/span&gt;, false) -&amp;gt; Emits Intermediate Value O1 (called with rereduce = false) reduce(&lt;span&gt;IDT1, IDR1&lt;/span&gt;, &lt;span&gt;RT1&lt;/span&gt;, false) -&amp;gt; Emits Intermediate Value O2 (called with rereduce = false) reduce(&lt;span&gt;IDT1, IDR2&lt;/span&gt;, &lt;span&gt;RT2&lt;/span&gt;, false) -&amp;gt; Emits Intermediate Value O3 (called with rereduce = false) reduce(&lt;span&gt;IDT1, IDR3&lt;/span&gt;, &lt;span&gt;RT3&lt;/span&gt;, false) -&amp;gt; Emits Intermediate Value O4 (called with rereduce = false)&lt;/p&gt;

&lt;p&gt;and finally&lt;/p&gt;

&lt;p&gt;reduce(null, &lt;span&gt;O1, O2, O3, O4&lt;/span&gt;, true) -&amp;gt; Emits final value (called with rereduce = true)&lt;/p&gt;

&lt;h3 id='sorting'&gt;Sorting&lt;/h3&gt;

&lt;p&gt;The final conundrum was sorting - since CouchDB does not allow sorting based on values (although there are ongoing effortsfforts) to alleviate that problem) - we need to be innovative (read hackish). It&amp;#8217;s for this reason that the ID&amp;#8217;s of documents are a combination of the timestamp of the creation of the thread + the username of the creator (the username is added for uniqueness). With this it becomes very trivial to sort, since the key (or ID of the document) is a timestamp.&lt;/p&gt;

&lt;h3 id='profit'&gt;Profit&lt;/h3&gt;

&lt;p&gt;So in summary, the reduce function takes as input all threads and its associated replies and emits a &lt;em&gt;result&lt;/em&gt; object per thread which gives the text associated with the thread, the thread creator&amp;#8217;s name, time of creation of thread, time of last reply and number of replies.&lt;/p&gt;

&lt;p&gt;Hopefully I&amp;#8217;ve managed been able to translate Javascript map/reduce to English. If not, you can follow along at the &lt;a href='http://github.com/arunthampi/icanhazthread'&gt;GitHub repo&lt;/a&gt; and the &lt;a href='http://wiki.couchdb.org'&gt;CouchDB wiki&lt;/a&gt; is an excellent resource as well.&lt;/p&gt;

&lt;p&gt;The challenging task now is to go beyond simple sort-by-recency and use a popularity score (based on number of replies, age of thread, age of last reply, etc.) and use that popularity score to sort threads.&lt;/p&gt;

&lt;p&gt;That is for another day.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/QBBLwqUoDa0" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 <entry>
   <title>icanhazthread, CouchApps and adventures with GeekCampSG 2009</title>
   <link href="http://mclov.in/2009/08/26/icanhazthread-couchapps-and-adventures-with-geekcampsg-2009.html" />
   <updated>2009-08-26T00:00:00-07:00</updated>
   <id>http://mclov.in/2009/08/26/icanhazthread-couchapps-and-adventures-with-geekcampsg-2009</id>
   <content type="html">&lt;h1 id='icanhazthread_couchapps_and_adventures_with_geekcampsg_2009'&gt;&lt;a href='/2009/08/26/icanhazthread-couchapps-and-adventures-with-geekcampsg-2009.html'&gt;icanhazthread, CouchApps and adventures with GeekCampSG 2009&lt;/a&gt;&lt;/h1&gt;

&lt;p class='meta'&gt;26 Aug 2009 - Singapore&lt;/p&gt;

&lt;p&gt;One week before the inaugural &lt;a href='http://geekcamp.pbworks.com'&gt;#geekcampsg&lt;/a&gt; event, I was working on developing a &lt;a href='http://github.com/couchapp/couchapp'&gt;CouchApp&lt;/a&gt; which would would let users play around with the entire English Premier League schedule. My reasoning was that it would be an interesting problem which would bring in a lot of cool CouchDB/CouchApp features - such as map/reduce, list and show functions, etc.&lt;/p&gt;

&lt;p&gt;It was then, that I came across Joshua Schachter&amp;#8217;s &lt;a href='http://a.tinythread.com'&gt;shell script&lt;/a&gt; (as he put it) called TinyThread, which let Twitter users create threaded conversations in a simple web application. It had a very simple premise and the fact that I happened to be the first/second person to reply to one the first TinyThread thread, made me feel very connected to the whole launch of the product (which seems kinda stupid in hindsight, but never mind). It struck me that this would be an awesome demo application to code up, to showcase CouchDB&amp;#8217;s capabilities for #geekcampsg.&lt;/p&gt;

&lt;p class='image'&gt;&lt;img src='/images/blog/canhazthread.png' alt='i.canhazthread.com thread view page' /&gt;&lt;/p&gt;

&lt;p&gt;Thus was born &lt;a href='http://i.canhazthread.com'&gt;i.canhazthread.com&lt;/a&gt;. It pretty much has the same functionality as TinyThread but over the past one week, there&amp;#8217;ve been some new features added which I like, and there are some more that I would like to be in the product as well. As mentioned during #geekcampsg, i.canhazthread.com is powered by Ruby On Rails and CouchDB. Rails handles all the nitty-gritty behind Twitter-OAuth authorizations and HTML rendering etc, while CouchDB powers the back-end. The CouchDB back-end behind i.canhazthread.com is open source and is available on &lt;a href='http://github.com/arunthampi/icanhazthread'&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are some interesting facets of i.canhazthread.com which I&amp;#8217;d like to elaborate in detail over a few blog posts, but I&amp;#8217;ll list them here anyway (as a reminder-to-self):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The map/reduce view called to display information on i.canhazthread.com&amp;#8217;s homepage is quite interesting and really helped me understand map/reduce views and the awesome power that it has.&lt;/li&gt;

&lt;li&gt;The Atom feeds for both the &lt;a href='http://i.canhazthread.com/atom.xml'&gt;home page&lt;/a&gt; as well as individual threads are powered directly by CouchDB (through the &lt;span&gt;&lt;em&gt;list function](http://wiki.apache.org/couchdb/Formatting&lt;/em&gt;with_Show_and_List)) without any Rails intervention.&lt;/span&gt;&lt;/li&gt;

&lt;li&gt;The Rails application runs on &lt;a href='http://www.rubyenterpriseedition.com/'&gt;Ruby Enterprise Edition&lt;/a&gt; and &lt;a href='http://www.modrails.com/'&gt;Passenger&lt;/a&gt; with Nginx and so far, I&amp;#8217;m really happy with it.&lt;/li&gt;

&lt;li&gt;I use &lt;a href='http://github.com/shopify/delayed_job'&gt;delayed_job&lt;/a&gt; and &lt;a href='http://god.rubyforge.org'&gt;God&lt;/a&gt; to deliver tweets in the background, whenever a thread is created/reply is posted.&lt;/li&gt;

&lt;li&gt;This is not that interesting, but I think is a nice use-case for i.canhazthread.com - you can embed GitHub &lt;a href='http://gist.github.com'&gt;gists&lt;/a&gt; in your threads and discuss (and reply with) code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for a few more i.canhazthread.com adventures over the course of the next few weeks.&lt;/p&gt;

&lt;p&gt;Finally, I&amp;#8217;d just like to give my thanks to the organizers of #geekcampsg for giving me the opportunity to speak and I&amp;#8217;d just like to say that I had a great time and hope for more kick-ass GeekCamps in the future. You can get slides of a few #geekcampsg presentations &lt;a href='http://www.slideshare.net/search/slideshow?q=+%23geekcampsg&amp;amp;submit=post&amp;amp;searchfrom=header'&gt;here&lt;/a&gt; (NB: This is not the entire list and will probably be updated gradually).&lt;/p&gt;

&lt;p&gt;My slides are &lt;a href='http://www.slideshare.net/arunthampi/geekcamp-sg-2009-couchapps-with-couchdb'&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/mclovin/~4/PADRWOdfM5I" height="1" width="1"/&gt;</content>
   <author>
     <name>Arun Thampi</name>
     <uri>http://mclov.in/</uri>
   </author>
 </entry>
 
 
</feed>
