2 Nov 2009 – Singapore
I’ve been trying to find a way to send SMS’s as part of my upcoming iPhone app – MovieFu . Essentially why I need to access the SMS functionality is for a user to quickly share movie showtimes with friends who don’t have access to the Internet.
The iPhone URL Scheme
The iPhone OS Reference Library recommends that we use the ‘sms://’ protocol to send SMS’s. Essentially if we need to send an SMS to a number such as 87654321, we can launch the SMS app with the URL ‘sms://87654321’. 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.
My workaround (which hopefully isn’t a PITA)
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:
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: ‘Copy and Paste in SMS’. 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 ‘copy-paste-select-all’ widget, thus allowing you to paste the details of the showtime you want to share.
This is illustrated below:
Above: Action Sheet which brings up the various options, one of which is ‘Copy and Paste in SMS’.
Above: 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 ‘paste’ menu and voila, the details are ready to be sent to your friends.
The associated code-snippet is here:
Feedback
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.
31 Aug 2009 – Singapore
Just wanted to pen this down so that I don’t forget the logic behind the map-reduce function used to generate the content for i.canhazthread.com’s homepage.
Requirements
i.canhazthread.com stores threads and replies as separate documents, with threads having the field type set to thread and replies having the field type set to reply. My requirement was to have the homepage display all threads in the database with the following attributes:
- Text of the thread
- Name of the author of the thread
- Timestamp of the thread
- Timestamp of the last reply of the thread
- Threads must be sorted by recency (most recent thread first)
- Number of replies associated with the thread
This seems quite trivial, but my biggest requirement was that this must be possible using one HTTP call and not n + 1 (where n is the number of threads => 1 call to get all threads, and n calls to get details of replies for each thread).
The Map Function
The map function is relatively straightforward as given below:
This uses the view collation technique as described by Christopher Lenz and it basically emits k-v pairs where the keys represent the ID’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:
- Thread 1 T1 (id = IDT1, key = IDT1 )
→ Reply 1 to Thread 1 RT1 (id = IDR1, key = IDT1)
→ Reply 2 to Thread 1 RT2 (id = IDR2, key = IDT1)
→ Reply 3 to Thread 1 RT3 (id = IDR3, key = IDT1)
- Thread 2 T2 (id = IDT2, key = IDT2)
- Thread 3 T3 (id = IDT3, key = IDT3)
→ Reply 1 to Thread 3 RT4 (id = IDR4, key = IDT3)
→ Reply 2 to Thread 3 RT5 (id = IDR5, key = IDT3)
- Thread 4 T4 (id = IDT4, key = IDT4)
The Reduce Function
The reduce function is where all the magic happens. (Not pasting the entire source here, please check it out here)
Associativity and Commutativity
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.
Group Level
One other important feature of reduce functions (as detailed here) 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’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:
Rereduce
The other captcha we have to keep in mind is the rereduce 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.
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:
- 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.
- 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 rereduce parameter set to true. The reduce function must be able to handle this scenario.
The two scenarios are listed below:
Scenario 1
Reduce function is called once, like this:
reduce([ [IDT1, IDT1], [IDT1, IDR1], [IDT1, IDR2], [IDT1, IDR3] ], [T1, RT1, RT2, RT3], false);
→ This emits the final value of the reduce function without any intermediate steps.
Scenario 2
Reduce function is called multiple times, like this:
reduce([IDT1, IDT1], [T1], false)
→ Emits Intermediate Value O1 (called with rereduce = false)
reduce([IDT1, IDR1], [RT1], false)
→ Emits Intermediate Value O2 (called with rereduce = false)
reduce([IDT1, IDR2], [RT2], false)
→ Emits Intermediate Value O3 (called with rereduce = false)
reduce([IDT1, IDR3], [RT3], false)
→ Emits Intermediate Value O4 (called with rereduce = false)
and finally
reduce(null, [O1, O2, O3, O4], true)
→ Emits final value (called with rereduce = true)
Sorting
The final conundrum was sorting – since CouchDB does not allow sorting based on values (although there are ongoing efforts to alleviate that problem) – we need to be innovative (read hackish). It’s for this reason that the ID’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.
Profit
So in summary, the reduce function takes as input all threads and its associated replies and emits a result object per thread which gives the text associated with the thread, the thread creator’s name, time of creation of thread, time of last reply and number of replies.
Hopefully I’ve managed been able to translate Javascript map/reduce to English. If not, you can follow along at the GitHub repo and the CouchDB wiki is an excellent resource as well.
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.
That is for another day.
26 Aug 2009 – Singapore
One week before the inaugural #geekcampsg event, I was working on developing a CouchApp 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.
It was then, that I came across Joshua Schachter’s shell script (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’s capabilities for #geekcampsg.
Thus was born i.canhazthread.com. It pretty much has the same functionality as TinyThread but over the past one week, there’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 GitHub.
There are some interesting facets of i.canhazthread.com which I’d like to elaborate in detail over a few blog posts, but I’ll list them here anyway (as a reminder-to-self):
- The map/reduce view called to display information on i.canhazthread.com’s homepage is quite interesting and really helped me understand map/reduce views and the awesome power that it has.
- The Atom feeds for both the home page as well as individual threads are powered directly by CouchDB (through the _list function) without any Rails intervention.
- I use delayed_job and God to deliver tweets in the background, whenever a thread is created/reply is posted.
- This is not that interesting, but I think is a nice use-case for i.canhazthread.com – you can embed GitHub gists in your threads and discuss (and reply with) code.
Stay tuned for a few more i.canhazthread.com adventures over the course of the next few weeks.
Finally, I’d just like to give my thanks to the organizers of #geekcampsg for giving me the opportunity to speak and I’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 here (NB: This is not the entire list and will probably be updated gradually).
My slides are below:
10 Jul 2009 – Singapore
Before I begin this post, let me warn you that I’m a very poor power-user of my tools. So if this post has a high-school-girl’s-giddy-excitement ring to something which has been blindingly obvious to everybody, please excuse me.
I’ve been using GitX to look at commits to Wego.com projects for a few months now and I always wished that it had a command-line option to launch it (similar to Textmate’s mate command). I like GitX’s clean interface, search functionality and the fact that it’s open source.
But today I realized that GitX did have a command-line tool that you can use to launch it from your Git repo. It can be enabled like so:

What this does is that it copies the executable gitx to /usr/local/bin.
Some of the other useful commands that I’ve started to use (more examples can be seen at the user manual):
If you think some of the options look familiar, you’re right. GitX accepts command-line arguments which you normally provide to git log and git diff.
Happy GitXing!
08 Jul 2009 – Singapore
So, I’ve moved house again. I’ve been meaning to do this ever since I snagged the mclov.in domain sometime early this year. Tried posterous but using custom domains makes it way too slow, and after contacting them, they said it would be resolved in one of their future releases (but with no definite release date). This site is hosted at GitHub and is powered by Jekyll (for managing markup) and Disqus (for comments).
The hard part of this move was getting the few posts that I had over at Wordpress. Since I had a vanilla Wordpress blog, I needed to export all of the blog’s contents as an XML file and then use an ‘importer’ to convert to Jekyll-ready posts. My untested code is here – please feel free to fork and apply changes. Mojombo’s and Al3x’s blogs were also great starting points for me to dive deep into Jekyll and get me started.
The styling is still very rough around the edges and I know of a few people who might snigger at my pathetic attempts at CSS :) But this is definitely a living, breathing organism and has gotten me excited about blogging again.
So here’s to a new beginning (and hoping it’s not a false dawn).