<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-6836909</id><updated>2009-10-26T21:38:29.463+05:30</updated><title type='text'>Just another Blog</title><subtitle type='html'>All my stuff... everything and anything that I think of.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default?start-index=26&amp;max-results=25'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>171</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6836909.post-459208493753437789</id><published>2009-08-03T09:14:00.003+05:30</published><updated>2009-08-03T09:19:42.873+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>Another cute error message</title><content type='html'>Firefox seems to be getting a personality too! This error message, which I saw the first thing after starting up my laptop, made me smile :-)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_r5H3VUoapik/SnZdek1jjCI/AAAAAAAAAfM/Jbnwzvl_BAA/s1600-h/firefox-error-message.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 275px;" src="http://2.bp.blogspot.com/_r5H3VUoapik/SnZdek1jjCI/AAAAAAAAAfM/Jbnwzvl_BAA/s400/firefox-error-message.png" alt="" id="BLOGGER_PHOTO_ID_5365578785924287522" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So, it's not only web applications that have cute error messages, now.&lt;br /&gt;&lt;br /&gt;A post I made earlier about &lt;a href="http://nandz.blogspot.com/2007/02/best-down-for-maintenance-message.html"&gt;Flickr's "down for maintenance" message.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-459208493753437789?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/459208493753437789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=459208493753437789&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/459208493753437789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/459208493753437789'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/08/another-cute-error-message.html' title='Another cute error message'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_r5H3VUoapik/SnZdek1jjCI/AAAAAAAAAfM/Jbnwzvl_BAA/s72-c/firefox-error-message.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-280692730946003731</id><published>2009-07-30T21:01:00.007+05:30</published><updated>2009-07-30T21:57:38.494+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='hive'/><category scheme='http://www.blogger.com/atom/ns#' term='hadoop'/><title type='text'>How to make your Hive cluster blazingly fast</title><content type='html'>Squeeze it! Literally.&lt;br /&gt;&lt;br /&gt;Always, always, always - compress your tables. Most of your Hive query execution time is not going into doing complex computations. Aggregates,  averages, and counts across tons of weblog data are not exactly computationally complex. It's the reading &amp;amp; writing of tons of data that's taking time.&lt;br /&gt;&lt;br /&gt;In computer science parlance, it's not CPU bound, it's I/O bound.&lt;br /&gt;&lt;br /&gt;If your data is already compressed (which in all probability, is the case), then nothing can beat the speed at which you can import it into Hive. Simply use the LOAD DATA LOCAL command to load compressed files into a TextFile table. Hive will automatically detect the compression and decompress on-the-fly when executing queries.&lt;br /&gt;&lt;br /&gt;Leaving aside the data import times, here are some (unscientific) benchmarks for a SELECT COUNT(1) query on my raw data tables. From 106 sec down to 60 sec. At 10% of the storage space.&lt;br /&gt;&lt;br /&gt;&lt;table class="fullWidth"&gt;&lt;tr&gt;&lt;th&gt;Storage&lt;/th&gt;&lt;th&gt;Row count&lt;/th&gt;&lt;th&gt;Table size&lt;/th&gt;&lt;th&gt;Query time&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Uncompressed&lt;/td&gt;&lt;td&gt;8,259,720&lt;/td&gt;&lt;td&gt;7,686 MB&lt;/td&gt;&lt;td&gt;106 sec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compressed &amp;ndash; GzipCodec (RECORD)&lt;/td&gt;&lt;td&gt;8,259,720&lt;/td&gt;&lt;td&gt;4,773 MB&lt;/td&gt;&lt;td&gt;101 sec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compressed &amp;ndash; native gzip&lt;/td&gt;&lt;td&gt;8,259,720&lt;/td&gt;&lt;td&gt;736 MB&lt;/td&gt;&lt;td&gt;60 sec&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Now, each of these tables was put through a moderately complex Hive query [1], which processed the data using two custom map/reduce scripts, and inserted the procssed data into a new table. Sure, the initial ETL phase is not significantly faster, but look at the amount of space I'm saving.&lt;br /&gt;&lt;br /&gt;&lt;table class="fullWidth"&gt;&lt;tr&gt;&lt;th&gt;Storage&lt;/th&gt;&lt;th&gt;Resultant row count&lt;/th&gt;&lt;th&gt;Resultant table size&lt;/th&gt;&lt;th&gt;Query time&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Uncompressed&lt;/td&gt;&lt;td&gt;1,561,633&lt;/td&gt;&lt;td&gt;1,608 MB&lt;/td&gt;&lt;td&gt;699 sec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compressed &amp;ndash; GzipCodec (RECORD)&lt;/td&gt;&lt;td&gt;1,561,633&lt;/td&gt;&lt;td&gt;N/A [2]&lt;/td&gt;&lt;td&gt;563 sec&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Compressed &amp;ndash; native gzip&lt;/td&gt;&lt;td&gt;1,561,633&lt;/td&gt;&lt;td&gt;86 MB&lt;/td&gt;&lt;td&gt;510 sec&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;I'll try to run some complex queries on the table with processed data to compared between compressed and uncompressed storage.&lt;br /&gt;&lt;br /&gt;Learn how to compress your Hive tables at &lt;a href="http://wiki.apache.org/hadoop/CompressedStorage"&gt;Hive Wiki &amp;ndash; Compressed Storage&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;[1] Take a look at the section titled "Processing the raw data (ETL)" &lt;a href="http://nandz.blogspot.com/2009/07/using-hive-for-weblog-analysis.html"&gt;here&lt;/a&gt;&lt;br /&gt;[2] I forgot to record the table size before dropping the table :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-280692730946003731?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/280692730946003731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=280692730946003731&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/280692730946003731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/280692730946003731'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/how-to-make-your-hive-cluster-blazingly.html' title='How to make your Hive cluster blazingly fast'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-8769666768162932814</id><published>2009-07-24T14:23:00.009+05:30</published><updated>2009-07-25T14:36:10.934+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='etl'/><category scheme='http://www.blogger.com/atom/ns#' term='weblog'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='hive'/><category scheme='http://www.blogger.com/atom/ns#' term='clickstream'/><category scheme='http://www.blogger.com/atom/ns#' term='hadoop'/><title type='text'>Using Hive for weblog analysis</title><content type='html'>&lt;h2&gt;Introduction&lt;/h2&gt;&lt;br /&gt;I've been playing around with &lt;a href="http://hadoop.apache.org/"&gt;Hadoop&lt;/a&gt; since the last fortnight to see how it performs with our weblog data processing jobs (Apache access logs). Right now we're using a blink-and-it-breaks system running a bunch of custom Perl scripts for log processing and MySQL for data storage. It's running on a single server class machine. It takes it about 3-4 hours to extract, transform, and load (into MySQL) one day of weblogs (this includes identifying sessions based on a 30min timeout). Another 1-2 hours to aggregate data and generate various CSV reports.&lt;br /&gt;&lt;br /&gt;So, a total of 6-7 hours, when it's not crashing.&lt;br /&gt;&lt;br /&gt;With &lt;a href="http://hadoop.apache.org/"&gt;Hadoop&lt;/a&gt; + &lt;a href="http://hadoop.apache.org/hive/"&gt;Hive&lt;/a&gt; I've brought the first phase down from 3-4 hours  to under an hour!  Anywhere between 15 minutes to 45 minutes to copy log files into a raw Hive table (depending upon how much replication you've configured your cluster to have). After that, 12 minutes to extract, transform, and load into a new table (including session identification).&lt;br /&gt;&lt;br /&gt;I gave &lt;a href="http://cloudbase.sourceforge.net/"&gt;Cloudbase&lt;/a&gt; a shot before Hive. Cloudbase was *dead* easy to setup and get off the ground (I love their simple approach to UDFs &amp;amp; UDTs). However, it's performance was not as good as Hive. On the other hand, I spent quite a lot of time trying to even import my custom log formats into Hive (I'm looking at you GenericUDF). But once I got started, man, was I blown away! Take a look at my &lt;a href="http://twitter.com/#search?q=saurabhnanda%20hadoop"&gt;Twitter updates&lt;/a&gt; on Cloudbase and Hive comparisons.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Cluster setup:&lt;/strong&gt; I managed to corner 4 desktop machines in the office for my experimental cluster. They are Core-2 Duo 2.4 GHz machines with 1GB of RAM and standard SATA hard disks. All four are connected to each other using a switch.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Setting up the Hive tables&lt;/h2&gt;&lt;br /&gt;Here's how I've set up my Hive tables:&lt;br /&gt;&lt;br /&gt;The following table (raw) stores the raw, unprocessed log files. I've partitioned the table by date so that the ETL operations can be run on bite sized chunks consisting of a day's worth of data.&lt;br /&gt;&lt;pre&gt;create table raw(line string) partitioned by(dt string)&lt;br /&gt;row format delimited fields terminated by '\t' lines terminated by '\n';&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The following table (hits) contains the processed &amp;amp; filtered hits, partitioned by date. Within each partition the rows are clustered by Apache user-id (aid) and within each cluster they are again sorted by page view times (ts). According to &lt;a href="http://wiki.apache.org/hadoop/Hive/LanguageManual/DDL"&gt;Hive Wiki&lt;/a&gt; this clustering &amp;amp; sorting can improve efficiency in certain queries. Although it does lead to an increase during the ETL phase. I'm really not sure what the buckets do - and 1,000 is just a number I pulled out of thin air.&lt;br /&gt;&lt;pre&gt;create table streamed_hits(ip_address string, aid string, uid string,&lt;br /&gt;                          ts string, method string, uri string,&lt;br /&gt;                          response string, session_id string,&lt;br /&gt;                          session_start string, pv_number int,&lt;br /&gt;                          clickstream string)&lt;br /&gt;partitioned by(dt string)&lt;br /&gt;clustered by (aid) sorted by (aid, ts) into 1000 buckets&lt;br /&gt;row format delimited fields terminated by '\t' lines terminated by '\n';&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Importing the raw data&lt;/h2&gt;&lt;br /&gt;Here's how one import data into the raw table. The import process is a simple HDFS file copy operation[1]. The more replication you have, the larger number of nodes the data needs to be copied to. Hence, the more time it takes during this operation.&lt;br /&gt;&lt;pre&gt;load data local inpath '/weblogs/20090602-access.log'&lt;br /&gt;into table raw partition(dt='2009-06-02');&lt;br /&gt;&lt;br /&gt;load data local inpath '/weblogs/20090603-access.log'&lt;br /&gt;into table raw partition(dt='2009-06-03');&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Processing the raw data (ETL)&lt;/h2&gt;&lt;br /&gt;Here's the Hive query for the ETL operation. I'm making sure that uninteresting rows are discarded upfront using the WHERE clause in the inner query. I had earlier put this in the outer query (which was causing LOTS of uninteresting rows to go through the parsing logic). The (apparently, in hindsight) stupid placement of the WHERE clause was bumping up the completion time of this query from 15mins to 2+ hours!&lt;br /&gt;&lt;br /&gt;I'm using a custom map script to read my log files, which are in a 'non-standard' format. There is another way to do this - UDFs &amp;amp; SerDe - but according to the &lt;a href="http://mail-archives.apache.org/mod_mbox/hadoop-hive-user/200907.mbox/browser"&gt;discussion I had on the mailing list&lt;/a&gt;, these features are not fit for newbie consumption yet. The DISTRUBUTE BY &amp;amp; SORT BY is essential for my session &amp;amp; clickstream identification script to work (thanks to the &lt;a href="http://wiki.apache.org/hadoop/Hive/LanguageManual/SortBy"&gt;Hive Wiki&lt;/a&gt;).&lt;br /&gt;&lt;pre style="overflow: scroll; width: 100%;"&gt;from&lt;br /&gt;   (from raw&lt;br /&gt;   select transform line using 'parse_logs.pl' as     ip_address, aid, uid, ts, method, uri,&lt;br /&gt;                                                   response, referer, user_agent, cookies, ptime&lt;br /&gt;   where lower(line) rlike '^(\\S+) (\\S+) (\\S+) \\[(.*?)\\] "(.*?)" (\\d+) (\\d+|-) "(.*?)" ".*?(mozilla|msie|opera).*?".*'&lt;br /&gt;           and not line rlike '^(\\S+) (\\S+) (\\S+) \\[(.*?)\\] "(\\S+) (/images.*?|/styles.*?|/javascripts.*?|/adserver.*?|.*?favicon.*?) (\\S+)".*'&lt;br /&gt;           and dt='2009-06-30'&lt;br /&gt;   distribute by aid sort by aid, ts asc) parsed&lt;br /&gt;insert overwrite table streamed_hits partition(dt='2009-06-30')&lt;br /&gt;   select transform parsed.ip_address, parsed.aid, parsed.uid, parsed.ts, parsed.method, parsed.uri,&lt;br /&gt;           parsed.response, parsed.referer, parsed.user_agent, parsed.cookies, parsed.ptime&lt;br /&gt;   using 'identify_sessions_and_clickstream.pl' as ip_address, aid, uid, ts, method, uri,&lt;br /&gt;                                   response, session_id, session_start, pv_number, clickstream;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Custom map/reduce scripts used&lt;/h2&gt;&lt;br /&gt;Here's the parse_logs.pl Perl script. Please excuse my Perl - I'm not a Perl programmer. I was just trying to reuse the funky regular expressions that we had lying around in our current log processing system. You use plug in any script, that reads/writes from standard input/output, into Hive.&lt;br /&gt;&lt;pre style="overflow: scroll; width: 100%; height: 10em;"&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;my %monthNum=(&lt;br /&gt;   "Jan" =&gt; 1,&lt;br /&gt;   "Feb" =&gt; 2,&lt;br /&gt;   "Mar" =&gt; 3,&lt;br /&gt;   "Apr" =&gt; 4,&lt;br /&gt;   "May" =&gt; 5,&lt;br /&gt;   "Jun" =&gt; 6,&lt;br /&gt;   "Jul" =&gt; 7,&lt;br /&gt;   "Aug" =&gt; 8,&lt;br /&gt;   "Sep" =&gt; 9,&lt;br /&gt;   "Oct" =&gt; 10,&lt;br /&gt;   "Nov" =&gt; 11,&lt;br /&gt;   "Dec" =&gt; 12,&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;while (defined($line = &lt;stdin&gt;)) {&lt;br /&gt;   if (($host,$user,$apache,$rfc931,$method, $url, $ver, $status,$size,$referrer,$agent,$cookies,$ptime) = $line =~ m/^(\S+) (\S+) (\S+) \[(\S+ \S+)\] "(\S+) (.*?) HTTP\/([0-9\.]*)" (\d+) (\d+|-) "([^"]*)" "([^"]*)" "([^"]*)" (\d+|-)$/) {&lt;br /&gt;       # everything found -- nothing to be done&lt;br /&gt;   }elsif (($host,$user,$apache,$rfc931, $method, $url, $ver, $status,$size,$referrer,$agent,$cookies) = $line =~ m/^(\S+) (\S+) (\S+) \[(\S+ \S+)\] "(\S+) (.*?) HTTP\/([0-9\.]*)" (\d+) (\d+|-) "([^"]*)" "([^"]*)" "([^"]*)"$/) {&lt;br /&gt;       $ptime="";&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   $ts="";&lt;br /&gt;   # Converting date to yyyy-MM-dd hh:mm:ss&lt;br /&gt;   if (($day, $monthname, $year, $hour, $minute, $sec)= $rfc931 =~/^(\d{2})[\/-]([^\/-]+)[\/-](\d{4}):(\d{2}):(\d{2}):(\d{2})/) {&lt;br /&gt;       $month=$monthNum{$monthname};&lt;br /&gt;       $ts=sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $month, $day, $hour, $minute, $sec);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   $agent=lc($agent);&lt;br /&gt;   $user=lc($user);&lt;br /&gt;   print "$host\t$apache\t$user\t$ts\t$method\t$url\t$status\t$referrer\t$agent\t$cookies\t$ptime\n"&lt;br /&gt;}&lt;/stdin&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here's the identify_sessions_and_clickstream.pl Perl script. Again, same disclaimer about my Perl as above. Also, please excuse the extremely naive way in which I'm trying to construct the clickstream. That work in progress.&lt;br /&gt;&lt;br /&gt;This script depends on the fact that the incoming data is sorted on Apache user-id and timestamp (that's what the DISTRIBUTE BY &amp;amp; SORT BY in the Hive query achieve). Apart from identifying 60min sessions I'm cleaning up the URLs to make them more 'generic' (removing query strings, removing trip IDs etc.)&lt;br /&gt;&lt;pre style="overflow: scroll; width: 100%; height: 15em;"&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;use Date::Parse;&lt;br /&gt;&lt;br /&gt;$session_duration=60*60; # in seconds&lt;br /&gt;$prev_apache=undef;&lt;br /&gt;$prev_ts=undef;&lt;br /&gt;$pv_number=undef;&lt;br /&gt;$session_id=undef;&lt;br /&gt;$session_num=undef;&lt;br /&gt;$session_start=undef;&lt;br /&gt;$clickstream='';&lt;br /&gt;&lt;br /&gt;while (defined($line = &lt;stdin&gt;)) {&lt;br /&gt;   chomp($line);&lt;br /&gt;   ($ip_address, $apache, $user, $ts, $method, $url, $status, $referrer, $agent, $cookies, $ptime) = split(/\t/, $line);&lt;br /&gt;$url, $status, $referrer, $agent, $cookies, $ptime\n";&lt;br /&gt;   $url =~ s/(.*?)\?.*/$1/i;&lt;br /&gt;   $url =~ s/^\/(trains|flights)\/itinerary\/.*?\/(.*?)/\/$1\/itinerary\/itinerary-id\/$2/;&lt;br /&gt;   $url =~ s/^\/(trains|flights)\/itinerary\/(\d+)$/\/$1\/itinerary\/itinerary-id/;&lt;br /&gt;   $url =~ s/^\/(activate|reactivate|reset)\/.*/\/$1/;&lt;br /&gt;   $url =~ s/^\/share.*/\/share/;&lt;br /&gt;   $url =~ s/^\/account\/trips\/.*/\/account\/trips\/trip-id/;&lt;br /&gt;   $url =~ s/^\/trains\/stations\/[0-9]*/\/trains\/stations\/numeric-id/;&lt;br /&gt;   $url =~ s/^\/trains\/stations\/[A-Za-z]*/\/trains\/stations\/alphanumeric-id/;&lt;br /&gt;   $url =~ s/^\/hotels\/info\/.*/\/hotels\/info\/hotel-id/;&lt;br /&gt;   $url =~ s/^\/places\/hotels\/.*\/images.*/\/places\/hotels\/images/;&lt;br /&gt;   $url =~ s/^\/places\/hotels\/images.*/\/places\/hotels\/images/;&lt;br /&gt;   $url =~ s/^\/newsletters\/images\/.*/\/newsletters\/images/;&lt;br /&gt;   $url =~ s/^\/index.*/\//;&lt;br /&gt;   $url =~ s/\/$//; # remove trailing slashes&lt;br /&gt;&lt;br /&gt;   if(!defined($prev_apache) || $prev_apache ne $apache){&lt;br /&gt;       if($apache eq '-' or $apache eq '')  {&lt;br /&gt;           # TODO -- use IP address &amp;amp; user_agent to identify sessions?&lt;br /&gt;           $pv_number='';&lt;br /&gt;           $session_start='';&lt;br /&gt;           $session_id='';&lt;br /&gt;           $clickstream='';&lt;br /&gt;       } else {&lt;br /&gt;           $pv_number=1;&lt;br /&gt;           $session_start=$ts;&lt;br /&gt;           $session_num=1;&lt;br /&gt;           $session_id="$apache|$session_start";&lt;br /&gt;           $clickstream="$url"&lt;br /&gt;       }&lt;br /&gt;   } elsif($prev_apache eq $apache) {&lt;br /&gt;       if((str2time($ts)-str2time($prev_ts))&lt;=$session_duration) {             $pv_number=$pv_number+1;             if($pv_number&lt;70) clickstream="$clickstream|$url" pv_number="1;" session_num="$session_num+1;" session_id="$apache|$session_start" clickstream="$url" prev_apache="$apache;" prev_ts="$ts;"&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] A small warning here, if your Hive session is running on one of your active nodes. Beware that because of HDFS default policy your Hive node's disk is going to be filled up first. This might lead to a disk space problem if your HDFS partition is being used by other processes as well. I ran into this and had to run the HDFS balancer, which, btw, is extremely slow! (even after increasing the dfs.balance.bandwidthPerSec property).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-8769666768162932814?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/8769666768162932814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=8769666768162932814&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/8769666768162932814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/8769666768162932814'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/using-hive-for-weblog-analysis.html' title='Using Hive for weblog analysis'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-2123372694345492579</id><published>2009-07-07T10:41:00.004+05:30</published><updated>2009-07-07T11:24:48.500+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>Capitalism and the environment</title><content type='html'>Sadly, &lt;a href="http://dilbert.com/strips/comic/2009-07-06/"&gt;this&lt;/a&gt; is not a joke - it's the truth. All large-scale projects see "environmental concerns" just as a nuisance they have to put up with it. Something that will eventually have to yield, because, well, you just can't stop "development", can you?&lt;br /&gt;&lt;br /&gt;Why aren't existing trees part of "beautification drives"? Why does beautification always mean pouring massive amounts of concrete on the ground and building railings and felling of trees?&lt;br /&gt;&lt;br /&gt;On that note, I would recommend &lt;a href="http://www.amazon.com/Small-Beautiful-Economics-People-Mattered/dp/0060916303/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1246943604&amp;amp;sr=8-1"&gt;'Small is Beautiful: Economic as if People Mattered' by E.F. Schumacher&lt;/a&gt; as compulsory reading to everyone studying the pseudo-science of economics. And to everyone who thinks growth is good - perpetually.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-2123372694345492579?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/2123372694345492579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=2123372694345492579&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2123372694345492579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2123372694345492579'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/capitalism-and-environment.html' title='Capitalism and the environment'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-6288270305750556489</id><published>2009-07-06T14:54:00.003+05:30</published><updated>2009-07-06T14:57:00.227+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>Directi Ads on Facebook</title><content type='html'>Nice :-) This must be resonating with the uber-geeks really well. Check out the &lt;a href="http://careers.directi.com/display/CAR/Open+Techie+positions;jsessionid=348FC49106CE2FE645700983CEAF988F"&gt;careers page&lt;/a&gt; as well -- "Open Techie Positions"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_r5H3VUoapik/SlHDATBGL9I/AAAAAAAAAd4/84iy2qLdPtc/s1600-h/directi.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 197px; height: 227px;" src="http://3.bp.blogspot.com/_r5H3VUoapik/SlHDATBGL9I/AAAAAAAAAd4/84iy2qLdPtc/s400/directi.png" alt="" id="BLOGGER_PHOTO_ID_5355275841792520146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-6288270305750556489?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/6288270305750556489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=6288270305750556489&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/6288270305750556489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/6288270305750556489'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/directi-ads-on-facebook.html' title='Directi Ads on Facebook'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_r5H3VUoapik/SlHDATBGL9I/AAAAAAAAAd4/84iy2qLdPtc/s72-c/directi.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-1679663090247209233</id><published>2009-07-02T13:39:00.003+05:30</published><updated>2009-07-02T13:47:33.370+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>My comments to Ministry of IT about Section 69A of IT Act</title><content type='html'>&lt;span style="font-style: italic;"&gt;Emailed to grai (at) mit (dot) gov (dot) in as given at &lt;a href="http://www.mit.gov.in/default.aspx?id=969"&gt;http://www.mit.gov.in/default.aspx?id=969&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dear Sir,&lt;br /&gt;&lt;br /&gt;With reference to the Draft Rules under section 69A of the Information  Technology (Amendment) Act, 2008, available at &lt;a href="http://www.mit.gov.in/download/sec69A_Rules.pdf" onmousedown="'UntrustedLink.bootstrap($(this)," target="_blank" rel="nofollow"&gt;&lt;span&gt;http://www.mit.gov.in/down&lt;/span&gt;&lt;wbr&gt;&lt;span class="word_break"&gt;&lt;/span&gt;load/sec69A_Rules.pdf&lt;/a&gt; , I would like to bring to your notice the following comments --&lt;br /&gt;&lt;br /&gt;(i) &lt;span style="font-weight: bold;"&gt;Lack of neutral party:&lt;/span&gt; There is no provision in the Draft Rules where the request for blocking information is examined by a neutral third-party (say, a court designated for this purpose) before being enforced. This leaves the law open to abuse by persons "in power" who want to curb any criticism (published on the Internet) aimed towards them. In other words this creates a situation where the plaintiff, himself is the judge.&lt;br /&gt;&lt;br /&gt;(ii) &lt;span style="font-weight: bold;"&gt;Lack of representation:&lt;/span&gt; There is absolutely no provision in the Act which gives the publisher (against whom the request for blocking has been initiated) a right to a fair hearing in front of a neutral third-party. I realize that on the Internet, which lends itself to anonymity, identifying &amp;amp; notifying the publisher of a particular information resource is difficult. However, there needs to be a process in place using which the Designated Officer first needs to notify the publisher against whom a Request for blocking is pending. This process may include: (a) emailing the contact person mentioned on the website/resource, (b) notifying the ISP on which the website/resource is hosted, (c) general notice on the Minister of Information Technology's website, etc. This is analogous to various "Notices" that any government agency serves before taking drastic action against a person -- like sealing of property, or disconnection of electricity/water supply.&lt;br /&gt;&lt;br /&gt;I have worked in the IT industry for 5 years and I understand the need for tighter regulation and stronger cyber-laws. However, these need to be balanced against (a) right to freedom of speech &amp;amp; expression, and (b) right to a fair trial. In my opinion, the Draft Rules completely oversteps these constitutional rights in a bid to provide the governing agencies with more power.&lt;br /&gt;&lt;br /&gt;Regards,&lt;br /&gt;Saurabh Nanda.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-1679663090247209233?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/1679663090247209233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=1679663090247209233&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1679663090247209233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1679663090247209233'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/my-comments-to-mistitry-of-it-about.html' title='My comments to Ministry of IT about Section 69A of IT Act'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-909387155713705492</id><published>2009-07-02T12:10:00.005+05:30</published><updated>2009-07-02T12:33:39.445+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>A SIM-card along-with the National ID card?</title><content type='html'>Taking on from &lt;a href="http://www.medianama.com/2009/07/223-why-the-sim-card-should-be-india%E2%80%99s-national-id-card/"&gt;Sanjay Swamy's post at Medianama&lt;/a&gt;, I think it's an excellent idea. Sure, there are the rough edges that one needs to smoothen out, but that's the case with any scheme of this magnitude. The kind of opportunities that open if your national ID can be part of your mobile SIM card are amazing. Especially in the mobile banking and m-commerce area.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Picture this:&lt;/span&gt; Your bank and telecom provider, both as part of their KYC, will need to know your national ID. Now, if you have the ability to link-up your SIM with your national ID (both smart cards), you can perform a fully authenticated financial transaction through your mobile phone. Just think of the number of services that can be made available to the rural population through such a thing!&lt;br /&gt;&lt;br /&gt;The biggest challenge this idea will face is from people getting paranoid about&lt;br /&gt;(a)a telecom operator "owning their identity", and&lt;br /&gt;(b) not everyone having a mobile phone.&lt;br /&gt;&lt;br /&gt;The National ID should be a complete in itself even without a SIM or a mobile phone. Something like the new vehicle registration smart cards you get in Maharashtra nowadays. However, it should have a detachable SIM card built right into it. If you want to use the additional features of your National ID, just remove the SIM and plug it in. You can keep your current phone number and even switch operators -- thanks to Number Portability.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The telecom operator (or anyone else on the mobile network) will NOT have access to your identity unless you authorize them during a transaction which requires such an access. It's just that if the SIM and your National ID live on the same hardware (which is, the smart card) you can link them up with ease, as and when required!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_r5H3VUoapik/SkxZWVUjoII/AAAAAAAAAdw/9I6Sf0q05wo/s1600-h/national-id.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 258px; height: 400px;" src="http://3.bp.blogspot.com/_r5H3VUoapik/SkxZWVUjoII/AAAAAAAAAdw/9I6Sf0q05wo/s400/national-id.png" alt="" id="BLOGGER_PHOTO_ID_5353752297252036738" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-909387155713705492?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/909387155713705492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=909387155713705492&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/909387155713705492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/909387155713705492'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2009/07/sim-card-along-with-national-id-card.html' title='A SIM-card along-with the National ID card?'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_r5H3VUoapik/SkxZWVUjoII/AAAAAAAAAdw/9I6Sf0q05wo/s72-c/national-id.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-4535387385683808726</id><published>2008-11-21T13:14:00.004+05:30</published><updated>2008-11-21T17:28:36.697+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='bad'/><title type='text'>ICICI Bank -- Email shy?</title><content type='html'>Has anyone ever been able to successfully email ICICI Bank? I've tried twice and failed. Today was my second attempt. After being asked a series of questions (four, I think) I finally get this form.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_r5H3VUoapik/SSZo9AFeKJI/AAAAAAAAAW4/ngT-3VDbkm8/s1600-h/icici-bank-email-form.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 310px;" src="http://3.bp.blogspot.com/_r5H3VUoapik/SSZo9AFeKJI/AAAAAAAAAW4/ngT-3VDbkm8/s320/icici-bank-email-form.png" alt="" id="BLOGGER_PHOTO_ID_5271015811088001170" border="0" /&gt;&lt;/a&gt;Even after asking my account number (which will give them instant access to all my contact details -- KYC, remember) they still want me to type out my email address, phone number (along with STD code -- mobile numbers don't work), and complete contact address.&lt;br /&gt;&lt;br /&gt;And finally, the damn thing doesn't work!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_r5H3VUoapik/SSZo9CSdxPI/AAAAAAAAAWw/oPyvRgTVeWw/s1600-h/icici-bank-error.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 55px;" src="http://2.bp.blogspot.com/_r5H3VUoapik/SSZo9CSdxPI/AAAAAAAAAWw/oPyvRgTVeWw/s320/icici-bank-error.png" alt="" id="BLOGGER_PHOTO_ID_5271015811679372530" border="0" /&gt;&lt;/a&gt;What's wrong with just giving an email address? Saves them from the development and maintenance cost of developing this stupid tool. Isn't customer support on email cheaper than doing it over the phone?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update:&lt;/span&gt; A friend tell me that the form works on IE and not on Firefox. Irks me even more!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-4535387385683808726?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/4535387385683808726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=4535387385683808726&amp;isPopup=true' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4535387385683808726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4535387385683808726'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/11/icici-bank-email-shy.html' title='ICICI Bank -- Email shy?'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_r5H3VUoapik/SSZo9AFeKJI/AAAAAAAAAW4/ngT-3VDbkm8/s72-c/icici-bank-email-form.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-8987022412862584621</id><published>2008-10-30T13:10:00.002+05:30</published><updated>2008-10-30T13:17:45.102+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>Email archival without mailing list software?</title><content type='html'>I believe that the &lt;a href="http://nandz.blogspot.com/2008/10/in-support-of-top-posting.html"&gt;lack of archives in business communication&lt;/a&gt; is a serious enough problem to solve. Especially in these times, when a lot of brainstorming happens on email amongst team members located in different geographies.&lt;br /&gt;&lt;br /&gt;I've tried using &lt;a href="http://www.basecamphq.com/"&gt;Basecamp&lt;/a&gt; for all business communication and succeeded only partially. Although Basecamp can serve as a good archive for email communication, it just doesn't beat the simplicity of adding any random email address to the CC list when you hit "Reply all". You have to first add a user to a project, then add him to the message, and then reply to the message. This, of course, will work only if the person knows how to use Basecamp. Otherwise, add the additional overhead of evangelizing Basecamp over regular email before getting him to accept this new mode of communication. [1] If something confidential is being discussed, there's also this fear of archiving your trade secrets on someone else's servers.&lt;br /&gt;&lt;br /&gt;Probably there's a good use-case to add a new feature in SMTP servers -- an archive header and an email archiving module. If an incoming email has the archive header (X-Archive: true) the SMTP server will archive the email by storing a copy of that email and making it accessible on a web page. All replies to that email (and further replies to those emails) will automatically get archived, regardless of whether they have the archive header or not [2]. The server can also add a footer to each email in the thread to direct the user to the archive. Optionally, the archiving module may also archive email attachments and make them available on the company intranet (or the web).&lt;br /&gt;&lt;br /&gt;Various mail clients will also need to be modified to present a user with a checkbox while composing the mail that sets/unsets the archive header.&lt;br /&gt;&lt;br /&gt;I think this feature can be easily hacked into postfix (or sendmail) and a couple of open source email clients (like Evolution and Thunderbird).&lt;br /&gt;&lt;br /&gt;Alternatively, this can also be achieved by having a record-keeper email ID (something like archive@somecompany.com). Any email CCed to the record-keeper will be archived and available on the company intranet (or the web). The only drawback of this is that the archival chain can break very easily if someone removes the record-keeper from the CC list. This approach can probably be an easier path towards implementation, both from the client's as well as the server's side. (Aren't such archival modules already available?)&lt;br /&gt;&lt;br /&gt;If anyone wants to collaborate on this project with me, please drop me an email at saurabhnanda (at) gmail (dot) com. I've been wanting to work on a decent tech project for quite some time now.&lt;br /&gt;&lt;br /&gt;[1] Given, recipients of Basecamp messages can now simply reply to messages just like normal email, it's still not perfect. All formatting (even line-breaks) are stripped. And you still have to log on to Basecamp to compose a completely new message.&lt;br /&gt;&lt;br /&gt;[2] I think it's reasonable to assume that since the parent wanted the email thread to be archived, it must be archived in its entirety.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-8987022412862584621?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/8987022412862584621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=8987022412862584621&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/8987022412862584621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/8987022412862584621'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/10/email-archival-without-mailing-list.html' title='Email archival without mailing list software?'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-2026216414954894868</id><published>2008-10-30T13:01:00.002+05:30</published><updated>2008-10-30T13:09:50.214+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>In Support of "Top Posting"</title><content type='html'>All over the web, on mailing lists, especially in the open source geek circles [1], top posting is frowned upon. Even while bottom posting, you're not considered cultured if you don't truncate the parent post to the exact specific part(s) your reply pertains to. I, too, used to follow this religiously until recently.&lt;br /&gt;&lt;br /&gt;After three years of communicating with non-geeks (you know, the business and marketing types), I realized that a lot of business communication was simply not possible in the typical quote-reply-quote-reply format that is prevelant on mailing lists. This is because of a couple of reasons, which I'll try to enumerate in the following paragraphs.&lt;br /&gt;&lt;br /&gt;One of the reasons given for not including the parent post in its entirety is that anyone wanting to refer to the thread can always look up the mailing list archives. Cultured folk should not waste bandwidth and screen real estate by repeating what is available a click away. This is not the case with typical business communication, which starts between two people (with usually their bosses on the CC list -- to be "kept in the loop"). Along the course of a reasonably sized email discussion, the CC list grows exponentially (believe me)! First the bosses' bosses are added -- if the small fry realize that they'll need to save their ass if something goes wrong. Suddenly something is under the purview of a chappy in some other department and him and his boss and boss' boss are added to the list. Later someone realizes that the legal department also needs to be "kept in the loop". Within no time you're having an orgy on email! With each new addition to the CC list you need a place where the latecomers can read-up on the discussion till then. In normal business communication there are no "archives". The latest email, itself, serves as an archive. I've had a tough time catching up on the discussion where each email was regularly truncated by the participants. I had to piece together more than 25 different emails forwarded to me as the "archive" -- believe me, it wasn't an easy task. Therefore it's much better to preserve the entire thread in the body and add your reply to the top of the email.&lt;br /&gt;&lt;br /&gt;A side-effect of not having an archive is that you can't really follow the quote-reply-quote-reply pattern ("Comments inline...") very effectively. If five different people are communicating, you suddenly lose track of (a) who said what, (b) in reply to what, and (c) in reply to whom. With an archive, each post can easily be identified on all three parameters. Take away the archives, and within two or three replies you lose track of (a) and (c) very easily. Inline comments, even in business communication, are useful when each paragraph or point in your email can be answered independent of the others. For example, when you're seeking answers to a list of technical questions. However as soon as you want to reply to the reply of your questions you start losing track of (a) and (c). One decent solution I've noticed is prefixing your reply with your name in square brackets. So, a typical email after a couple of back and forth replies looks like:&lt;br /&gt;&lt;blockquote&gt;* Can I pass the customer's shipping address instead of the billing address in the API?&lt;br /&gt;[Alice] It's possible, but why would you want to do it? You already have the billing address in the DB, don't you?&lt;br /&gt;[Bob] Yes, we do -- but we don't want to share it due to privacy concerns.&lt;br /&gt;[Alice] Okay, then you can pass the shipping address.&lt;br /&gt;&lt;/blockquote&gt;I've observed a significant side effect of following the quote-reply-quote-reply model of communication -- especially on tech mailing lists. A lot of discussions regularly morph into flame-wars, mudslinging matches, or "preachers preaching the lesser mortals." Don't get me wrong -- the communication style is not the sole reason for discussions going off track. Obviously a lot depends on the attitude of the people involved in the discussion, but I feel the communication style definitely promotes the degeneration of the discussion. When you read a post you generally disagree with, it's very tempting to pick each line, quote it, and try to rebut it individually. It's very easy to get lost in the trees for the woods.&lt;br /&gt;&lt;br /&gt;[1] These are the only circles which seem to have a respectable mailing list culture.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-2026216414954894868?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/2026216414954894868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=2026216414954894868&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2026216414954894868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2026216414954894868'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/10/in-support-of-top-posting.html' title='In Support of &quot;Top Posting&quot;'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-1498568116063486566</id><published>2008-10-15T12:12:00.004+05:30</published><updated>2008-10-15T12:33:48.708+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Overestimating users of technology</title><content type='html'>Most software products assume too much about their users. After reading Alan Cooper's "The Inmates Are Running The Asylum" (&lt;a href="http://www.amazon.com/Inmates-Are-Running-Asylum-Products/dp/0672326140/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1224053153&amp;amp;sr=8-1"&gt;at Amazon&lt;/a&gt; and &lt;a href="http://www.indiaplaza.in/books/all/0672326140/all/the-inmates-are-running-the-asylum.htm"&gt;at IndiaPlaza&lt;/a&gt;) I realized how much I used to presume about a user's comfort level with technology while designing products. I now consciously switch off the developer/geek side of my brain while writing product specs or mocking up UI prototypes.&lt;br /&gt;&lt;br /&gt;Here's a &lt;a href="http://pogue.blogs.nytimes.com/2008/10/02/tech-tips-for-the-basic-computer-user/?em"&gt;post by David Pogue&lt;/a&gt; on what everyone assumes that everyone else knows but is wrong. I thought I would know every single thing on the list but was surprised to find a keyboard shortcut that was new to me - using shift + space to scroll up in a web page.&lt;br /&gt;&lt;blockquote&gt;You can tap the Space bar to scroll down on a Web page one screenful. Add the Shift key to scroll back up.&lt;/blockquote&gt;Yahoo! recently released their &lt;a href="http://developer.yahoo.net/blog/archives/2008/10/open_id_research.html"&gt;research findings&lt;/a&gt; about an &lt;a href="http://openid.net/what/"&gt;OpenID&lt;/a&gt; usability report. They were not surprising:&lt;br /&gt;&lt;blockquote&gt;None of the users had heard of &lt;a href="http://www.openid.net/"&gt;OpenID&lt;/a&gt; before, and none of them even noticed the OpenID sign-in box displayed below the traditional email/password login form on the site. [...] Observing these tests was more than a bit frustrating for the Yahoo! OpenID team, and the test subjects may have been distracted by the sounds of the groans and head-pounding coming from the other side of the one-way mirror. Certainly there is a lot of work to be done on the OpenID UX (user experience) front.  &lt;/blockquote&gt;(At the risk of over-simplification,  OpenID is a common username/password using which you can login to multiple websites without creating individual username/passwords for each.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-1498568116063486566?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/1498568116063486566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=1498568116063486566&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1498568116063486566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1498568116063486566'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/10/overestimating-users-of-technology.html' title='Overestimating users of technology'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-3582493050477639061</id><published>2008-09-30T17:58:00.007+05:30</published><updated>2008-09-30T18:13:58.922+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='bad'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>Scary: CSRF and REST</title><content type='html'>The latest exploit to hit the web is &lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;CSRF&lt;/a&gt;. It's nothing fancy, very simple to execute and understand. In a nutshell:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;You're signed in to website A&lt;/li&gt;&lt;br /&gt;&lt;li&gt;You open a new tab and visit website B. Website B is a malicious website (or is a trusted website which has the potential of being malicious because of allowing user generate content-UGC).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Website B has an image tag (not necessarily, but the simplest to inject via UGC) which points to a &lt;b&gt;predictable URL&lt;/b&gt; on website A. For example, &amp;lt;img src="http://www.a.com/account/delete?confirm=yes" /&amp;gt; which basically deletes your account on website A.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Your browser will try to fetch the "image" from website A, merrily sending your session cookie along with the request. And BOOM! On website B you don't get the image ('cuz there is none) but your account has just been deleted from website A.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;This is the simplest scenario I've explained. Read the &lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;Wikipedia article CSRF&lt;/a&gt; to understand how it can be executed in a variety of ways and situations.&lt;br /&gt;&lt;br /&gt;Over the past year or so I've been going ga-ga over &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;RESTful architecture&lt;/a&gt; and stateless servers. I've tried making URLs predictable and discoverable. Personally, I click on the "keep me signed in" checkbox whenever on browsing the web on my laptop. This just turns my world around!&lt;br /&gt;&lt;br /&gt;Does it mean that we now need to make sure we're not signed-in to one site while visiting another? Or that all web applications now have to be stateful and URLs have to be non-predictable? Which means that while generating a page the webserver will have to add a random token to each URL and validate that when the browser requests the URL? The horror!&lt;br /&gt;&lt;br /&gt;Any thoughts, anyone? This sounds like impending doom!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-3582493050477639061?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/3582493050477639061/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=3582493050477639061&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/3582493050477639061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/3582493050477639061'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/09/scary-csrf-and-rest.html' title='Scary: CSRF and REST'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-4452238796846074772</id><published>2008-08-29T12:57:00.003+05:30</published><updated>2008-08-29T13:17:23.381+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='good'/><category scheme='http://www.blogger.com/atom/ns#' term='review'/><category scheme='http://www.blogger.com/atom/ns#' term='movie'/><title type='text'>Review: Rock on!!</title><content type='html'>So, last night I was conned into buying discounted paid preview tickets for &lt;a href="http://rockon.bigadda.com" title="Official website"&gt;Rock On&lt;/a&gt; screening at &lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;geocode=&amp;q=metro+adlabs,+mumbai&amp;ie=UTF8&amp;cd=1&amp;ll=18.945136,72.820559&amp;spn=0.018388,0.043945&amp;z=15&amp;iwloc=A" title="Google maps link for Metro Adlabs"&gt;Metro Adlabs.&lt;/a&gt; I went there all hyped up thinking of catching a glimpse of the Rock On crew and general P3 types crowd. But I was let down. &lt;i&gt;Cast/crew chhodo, acchi ladkiyon ki bhi kami thi!&lt;/i&gt; Anyways, but I was not let down by the movie.&lt;br /&gt;&lt;br /&gt;Superb music - especially if you like rock (you'll like it even otherwise). Heard such good Hindi rock after a long time - nice lyrics and singing. Superb acting by the entire cast - never knew Arjun Rampal could act well. Superb singing by Farhaan Akhtar.&lt;br /&gt;&lt;br /&gt;Movie is a tad slow and dwells upon each character and relationship and lets it build. But, I guess that's required. That's how the audience connects with each character. &lt;br /&gt;&lt;br /&gt;Loved the end note - "Don't download the music. Buy the CD!" Heh, I will. Hope you will too. I wonder why these guys don't sell music CDs + posters + t-shirts right outside the movie hall. I'm sure I would've bought a CD without a second thought had I seen a stall right after I stepped out after watching the movie.&lt;br /&gt;&lt;br /&gt;PS: Vote for it on the &lt;a href="http://www.imdb.com/title/tt1230165/" title="IMDB page for Rock On"&gt;IMDB page for Rock On!!&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-4452238796846074772?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/4452238796846074772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=4452238796846074772&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4452238796846074772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4452238796846074772'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/08/review-rock-on.html' title='Review: Rock on!!'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-1320119732801851618</id><published>2008-08-12T13:20:00.002+05:30</published><updated>2008-08-12T13:24:43.153+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>FM</title><content type='html'>&lt;blockquote&gt;BMC aur Dharmendra mein ab zyaada farak nahin hai bacha, kutton ka khoon peene mein dono ko aata hai maza!&lt;/blockquote&gt;&lt;br /&gt;That's Mallishka on Red FM! Absolutely hilarious. &lt;br /&gt;&lt;br /&gt;I'm hooked onto FM these days. Especially &lt;a href="http://nandz.blogspot.com/2007/01/rainbow-fm-rocks.html"&gt;Rainbow FM&lt;/a&gt; in the mornings and late nights - they play amazing English music. The RJs mostly suck, but the music rocks.&lt;br /&gt;&lt;br /&gt;Why do the other stations play the same songs over and over and over again? They haven't yet gotten over Jab We Met. I'm sick of listening to those songs. Get a new playlist guys!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-1320119732801851618?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/1320119732801851618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=1320119732801851618&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1320119732801851618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/1320119732801851618'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/08/fm.html' title='FM'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-2629940518878299740</id><published>2008-07-09T23:52:00.003+05:30</published><updated>2008-11-13T21:25:53.723+05:30</updated><title type='text'>Lazy programmer and why Lisp templates suck</title><content type='html'>I was reading some random article on Rediff and happened to notice this block shoved in one corner. What caught my eye was the first question - "Are commodity exchanges responsible for price raise of food grains?" - but I got easily distracted by the sheer laziness of the developer who implemented this. Check out the screenshot below:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_r5H3VUoapik/SHUC-ivxhgI/AAAAAAAAAP0/xKZznRC6ETY/s1600-h/lazy-programmer-screenshot.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_r5H3VUoapik/SHUC-ivxhgI/AAAAAAAAAP0/xKZznRC6ETY/s400/lazy-programmer-screenshot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5221082616508286466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;1 answer(s)&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;5 answer(s)&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I mean for god's sake! On one hand we have people who're trying to teach computers natural language processing, and artificial intelligence; and on the other hand computers can't figure out if was one &lt;b&gt;answer&lt;/b&gt; or five &lt;b&gt;answers.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Then I thought, how easy it would be to implement this in ERb:&lt;br /&gt;&lt;code&gt;&lt;%= post.answer_count %&gt; &lt;%= post.answer_count==1 ? "answer" : "answers" %&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And then I got thinking how damn &lt;i&gt;painful&lt;/i&gt; it would be to implement this in Lisp and &lt;a href="http://drakma.de/html-template"&gt;HTML-Template&lt;/a&gt;. You'd first have to create a flag for each post indicating whether it had a single or multiple answer. Then you'd have to pass all those flags (or list of flags) down to the template filler function. Then you'd have to put a big TMPL_IF statement in the template to achieve the same thing:&lt;br /&gt;&lt;code&gt;&amp;lt;!-- TMPL_VAR answer-count --&amp;gt; &amp;lt;!-- TMPL_IF single-answer --&amp;gt;answer&amp;lt;!-- TMPL_ELSE --&amp;gt;answers&amp;lt;!-- /TMPL_IF --&amp;gt;&lt;/code&gt;&lt;br /&gt;You could of course, for each post, simply compose the exact string to be displayed ("1 answer", "5 answers") and pass that down to the template. But what's the point of having templates if you can't separate view logic cleanly.&lt;br /&gt;&lt;br /&gt;Lisp is a great language, which will probably help you achieve a lot of intellectual orgasms (Meta-object protocol, macros, reader macros, etc.) But it sure does need a good templating tool. I tried hacking around in &lt;a href="http://common-lisp.net/project/cl-emb/"&gt;CL-EMB&lt;/a&gt;, but it doesn't really cut it.&lt;br /&gt;&lt;br /&gt;[End rant]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-2629940518878299740?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/2629940518878299740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=2629940518878299740&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2629940518878299740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/2629940518878299740'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/07/lazy-programmer-and-why-lisp-templates.html' title='Lazy programmer and why Lisp templates suck'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_r5H3VUoapik/SHUC-ivxhgI/AAAAAAAAAP0/xKZznRC6ETY/s72-c/lazy-programmer-screenshot.png' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-5896974298741828052</id><published>2008-07-02T23:18:00.000+05:30</published><updated>2008-07-02T23:24:41.074+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>IIT Kanpur Suicides - Werther Effect/Copycat Suicides?</title><content type='html'>Yet another suicide rocks IIT Kanpur. Yet another round of introspection. More statement blaming the student-faculty relationship, internet usage, grading system and academic pressure. Media bites with ridiculous statements from, both, the students and the faculty.&lt;br /&gt;&lt;br /&gt;I'm not sure how much the situation has changed from my times - and they're not too far in the past, I'm a 2005 graduate - but, I really don't think that the academic pressure is too high at IIT Kanpur. Any lower, and it'll risk getting lost amongst the gazillions of second and third rung engineering institues in the country. &lt;br /&gt;&lt;br /&gt;Ditto with the grading system. It's not the best, but it's not the pits either. Every system has its pros and cons. And the cons are not that bad that they'd cause students to start committing suicides over them.&lt;br /&gt;&lt;br /&gt;I think the suicides are because of an individual's intrinsic character and the &lt;a href="http://en.wikipedia.org/wiki/Copycat_suicide"&gt;Werther Effect.&lt;/a&gt; I first came across the Werther Effect while reading the chapter on social proof in Robert B. Cialdini's book, "Influence - The Psychology of Persuasion." The Werther Effect talks about how a highly publicized suicide can cause a number of follow up &lt;i&gt;copy-cat&lt;/i&gt; suicides amongst people in the same situation. And suicides in IIT Kanpur (or any other IIT for that matter) are surely highly publicized. You have it splashed on the front pages of all local newspapers, the in-campus newsgroups would be flooded with posts, discussions in the quads &amp; wings, special committees and reports, etc.&lt;br /&gt;&lt;br /&gt;When I first read about the Werther Effect, I scoffed. But, now I've started believing in it. An extract from the Wikipedia article:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The well-known suicide serves as a model, in the absence of protective factors, for the next suicide. This is referred to as suicide contagion. They occasionally spread through a school system, through a community, or in terms of a celebrity suicide wave, nationally. This is called a suicide cluster[1]. Examples of celebrities whose suicides have inspired suicide clusters include the Japanese musician Hide and Yukiko Okada.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;I think some psychology/sociology professor from the IITs should be looking at this angle as well. In my opinion, the grading system and the academic pressure is just fine. Let's not degrade the quality of IITs any further - we've got politicians to do that for us!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-5896974298741828052?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/5896974298741828052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=5896974298741828052&amp;isPopup=true' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5896974298741828052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5896974298741828052'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/07/iit-kanpur-suicides-werther.html' title='IIT Kanpur Suicides - Werther Effect/Copycat Suicides?'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-3043918088546442973</id><published>2008-04-19T19:21:00.004+05:30</published><updated>2008-04-19T19:35:02.870+05:30</updated><title type='text'>[HTML] The under-used &lt;label&gt; tag</title><content type='html'>I've seen so many web sites not using the label HTML tag. It's a very nifty usability tool whenever you're writing captions for form fields - especially checkboxes and radio buttons.&lt;br /&gt;&lt;br /&gt;The problem with checkboxes and radio buttons is that they're small. You have to position your mouse pointer very accurately to be able to turn it on or off. With labels you can associate the form field with its accompanying caption. Clicking on the caption will turn the associated checkbox/radio button on or off. Give it a spin here:&lt;br /&gt;&lt;br /&gt;&lt;input type="checkbox" id="example1" /&gt; Without the label tag&lt;br /&gt;&lt;br /&gt;&lt;input type="checkbox" id="example2" /&gt; &lt;label for="example2"&gt;With the label tag&lt;/label&gt;&lt;br /&gt;&lt;br /&gt;With text boxes clicking on the label will shift the cursor into the associated text box:&lt;br /&gt;&lt;br /&gt;Enter your name (without label): &lt;input type="text" id="example3" /&gt; &lt;br /&gt;&lt;br /&gt;&lt;label for="example4"&gt;Enter your name (with label):&lt;/label&gt; &lt;input type="text" id="example4" /&gt; &lt;br /&gt;&lt;br /&gt;All you need to do is give the form field an id tag and associate the label with it:&lt;br /&gt;&lt;pre&gt;&amp;lt;input type="checkbox" id="&lt;b&gt;example2&lt;/b&gt;" /&amp;gt; &amp;lt;label for="&lt;b&gt;example2&lt;/b&gt;"&amp;gt; With the label tag&amp;lt;/label&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-3043918088546442973?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/3043918088546442973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=3043918088546442973&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/3043918088546442973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/3043918088546442973'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/html-under-used-tag.html' title='[HTML] The under-used &amp;lt;label&amp;gt; tag'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-844994852430583207</id><published>2008-04-19T19:15:00.004+05:30</published><updated>2008-04-19T19:19:50.043+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><title type='text'>Impulse Purchase</title><content type='html'>I've seen people purchase clothes on an impulse. Shoes, deodorants, shades, food, whatever. But I don't think I've seen anyone purchase a domain name on impulse!&lt;br /&gt;&lt;br /&gt;A few days ago I was following a truck on my bike and saw the ubiquitous "Horn OK Please" written on the back. And suddenly out of nowhere I thought of "horny" please. What a cool domain name to have! I came to the office, and purchases it for Rs 599 at Net4Domains.&lt;br /&gt;&lt;br /&gt;What the fuck do I do with it now? Any ideas?&lt;br /&gt;&lt;br /&gt;Saurabh Nanda. Proud (confused?) owner of &lt;a href="http://www.hornyplease.com"&gt;www.hornyplease.com&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-844994852430583207?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/844994852430583207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=844994852430583207&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/844994852430583207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/844994852430583207'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/impulse-purchase.html' title='Impulse Purchase'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-5741484105406821557</id><published>2008-04-09T13:09:00.003+05:30</published><updated>2008-04-09T13:22:48.709+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Composing blog posts in Textile Markup</title><content type='html'>Why can't I compose posts in &lt;a href="http://hobix.com/textile/"&gt;Textile Markup?&lt;/a&gt; It's so damn simple and guarantees conversion to clean HTML. I hate using the rich text editor for composing posts. It's too complicated and I don't like the superfluous markup it generates. Plus I've also gotten addicted to Textile, thanks to the amount of time I spend on Basecamp.&lt;br /&gt;&lt;br /&gt;I've submitted a feature request and also &lt;a href="http://groups.google.com/group/blogger-help-howdoi/browse_thread/thread/78ce6174f1c577d1"&gt;posted about it on the Blogger Help Group.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-5741484105406821557?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/5741484105406821557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=5741484105406821557&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5741484105406821557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5741484105406821557'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/composing-blog-posts-in-textile-markup.html' title='Composing blog posts in Textile Markup'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-5974766249592516271</id><published>2008-04-08T19:11:00.003+05:30</published><updated>2008-04-08T19:42:26.535+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>Clueless with Computers...</title><content type='html'>... that's how non-geeks feel. I'm extremely sure of that now. &lt;br /&gt;&lt;br /&gt;I had been spending some time planning my parents' trip to Kerala. I had every event (flight, car travel, hotel stay, etc.) added neatly to my Evolution calendar. (Given the number of meetings I now have to attend - I've been using Evolution avidly for the past month or so - but that's a different story). Finally, I sent out notifications for each event to my parents.&lt;br /&gt;&lt;br /&gt;I called up my Mom expecting the entire travel-plan communication process to be a breeze. What's the complication, I thought. You get a bunch of meeting invites; you click "Accept" for each one and boom! you have a proper travel calendar right in front of you.&lt;br /&gt;&lt;br /&gt;She got the mails alright, she even clicked "Accept" on each one of them. But I had one hard of a time trying to get her to the calendar.&lt;br /&gt;&lt;br /&gt;Me: Okay, now that you've accepted them, you can see the schedule in the calendar.&lt;br /&gt;Mom: How do I get to the calendar?&lt;br /&gt;Me: Okay, do you use Outlook? [That's what most offices use.]&lt;br /&gt;Mom: Yes.&lt;br /&gt;Me: So, the left pane, sorry column, sorry left side of the screen will have a button for calendar. Click on it. &lt;br /&gt;Mom: It's not there.&lt;br /&gt;Me: Can you see your mail folders?&lt;br /&gt;Mom: Yes. But no calendar.&lt;br /&gt;Me: Okay, I'll call you back in 5 min.&lt;br /&gt;&lt;br /&gt;Then I rushed to a guy with Microsoft Windows on his machine. Fired up Outlook and noted the exact location of the Calendar button. It was pretty visible. But then I realized, probably it's been turned off on her machine. I asked the guy with M$ installed, he showed me how to configure your left pane to show/hide various buttons. I was like, yeah right. "Mom look at the left pane, there's a teeny-weeny arrow there which will lead to a menu, which will have an option called 'configure', which will have various checkboxes...." Not happening!&lt;br /&gt;&lt;br /&gt;I spent the next 10 mins trying to figure out how to get to the calendar in Outlook without clicking on an onscreen button or going through the configuration process. It's bloody un-intuitive. It's "Go &gt; Calendar" if you don't already know. The shortcut for it is Ctrl+2.&lt;br /&gt;&lt;br /&gt;Back to the phone:&lt;br /&gt;&lt;br /&gt;Me: Okay, press Ctrl+2.&lt;br /&gt;Mom: [After 30 sec] I did, nothing happened.&lt;br /&gt;Me: Are you in Outlook? [Damn!]&lt;br /&gt;Mom: Yes.&lt;br /&gt;Me: Do you have a Menu item called "Go"? You know, right at the top where file, edit, etc. are? Can you see a "Go" there?&lt;br /&gt;Mom: No, there's no "Go" option!&lt;br /&gt;Me: Are you sure you're using Outlook?&lt;br /&gt;Mom: Yes.&lt;br /&gt;Me: Are you sure it's not Netscape?&lt;br /&gt;Mom: [getting irritated] yes!&lt;br /&gt;Me: okay, are you using Outlook on your own desktop? Or do you sign in to Outlook using the Internet Explorer? [Ah, probably she was on one of the M$ web mail box thingies]&lt;br /&gt;Mom: No. It's on my desktop. We have two different icons. One for Internet Explorer and the other for Outlook Express. [!!]&lt;br /&gt;&lt;br /&gt;I wanted to pull my hair out! And as it turn out, &lt;a href="http://ask-leo.com/does_outlook_express_have_a_calendar.html"&gt;Outlook Express&lt;/a&gt;, indeed does not have a calendar application.&lt;br /&gt;&lt;br /&gt;I just gave up on the entire cool iCal stuff. Took a screenshot of my Evolution Calendar screen and mailed it to her.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-5974766249592516271?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/5974766249592516271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=5974766249592516271&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5974766249592516271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5974766249592516271'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/clueless-with-computers.html' title='Clueless with Computers...'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-6434692285851226060</id><published>2008-04-06T00:35:00.004+05:30</published><updated>2008-04-07T14:40:30.153+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='good'/><category scheme='http://www.blogger.com/atom/ns#' term='bad'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>[Ruby] A few points about Ruby threading...</title><content type='html'>... it's green threaded.&lt;br /&gt;&lt;br /&gt;That means, the threading is simulated by the Ruby VM and they are not "true OS threads". &lt;br /&gt;&lt;br /&gt;That means, if a thread in your Ruby program makes a call that the VM can't suspend, all threads running in that VM will block. In effect, your Ruby VM will "hang" until the rogue thread returns. &lt;br /&gt;&lt;br /&gt;A few links about how threads in Ruby work:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.rubycentral.com/pickaxe/tut_threads.html"&gt;Thread and Processes from "the Pragmatic Programmers' Guide"&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://spec.ruby-doc.org/wiki/Ruby_Threading"&gt;Ruby Threads from "The RubySpec"&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Basically, the recommended way to achieve concurrency, if each concurrent thread/process is doing even moderately complex I/O tasks, is to fork a new process. (The much-touted "shared nothing" architecture)&lt;br /&gt;&lt;br /&gt;PS: And in case you're wondering, &lt;a href="http://m.onkey.org/2007/8/8/activerecord-is-thread-safe"&gt;ActiveRecord *is* thread-safe.&lt;/a&gt; It's just that most apps don't use it because of the preferred way of achieving concurrency in Ruby (forking processes).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-6434692285851226060?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/6434692285851226060/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=6434692285851226060&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/6434692285851226060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/6434692285851226060'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/ruby-few-points-about-ruby-threading.html' title='[Ruby] A few points about Ruby threading...'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-5597879180417000218</id><published>2008-04-05T18:23:00.001+05:30</published><updated>2008-04-05T18:25:10.437+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='bad'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>[Ruby] Madness with the 'require' command</title><content type='html'>I spent around 30 minutes trying to figure out why a particular Ruby file was being loaded twice, only to be struck in my face with this gotcha.&lt;br /&gt;&lt;br /&gt;Basically, when you use &lt;code&gt;require 'file'&lt;/code&gt; the method Ruby uses to determine whether the file has been loaded earlier is pretty stupid. It looks for the filename passed verbatim in it's internal data structure/hash/whatever. So, if you give &lt;code&gt;require 'file'&lt;/code&gt; and &lt;code&gt;require './file'&lt;/code&gt; the damn file will be loaded twice.&lt;br /&gt;&lt;br /&gt;WTF?! Seriously!&lt;br /&gt;&lt;br /&gt;Anyways, I thought this was undocumented behaviour but I found this in the RDoc entry for 'require' - should have looked there before.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Ruby tries to load the library named string, returning true if successful. If the filename does not resolve to an absolute path, it will be searched for in the directories listed in $:. If the file has the extension ``.rb’’, it is loaded as a source file; if the extension is ``.so’’, ``.o’’, or ``.dll’’, or whatever the default shared library extension is on the current platform, Ruby loads the shared library as a Ruby extension. Otherwise, Ruby tries adding ``.rb’’, ``.so’’, and so on to the name. The name of the loaded feature is added to the array in $". A feature will not be loaded if it‘s name already appears in $". However, the file name is not converted to an absolute path, so that ``require ‘a’;require ’./a‘’’ will load a.rb twice.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-5597879180417000218?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/5597879180417000218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=5597879180417000218&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5597879180417000218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5597879180417000218'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/04/ruby-madness-with-require-command.html' title='[Ruby] Madness with the &apos;require&apos; command'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-5397365572903711897</id><published>2008-03-15T15:02:00.002+05:30</published><updated>2008-03-15T15:10:07.843+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='good'/><category scheme='http://www.blogger.com/atom/ns#' term='random'/><title type='text'>The funniest post I've read in the recent past...</title><content type='html'>... is &lt;a href="http://www.vishalpatel.com/features/anek/anek.htm"&gt;Ek, Anek, aur Ekta&lt;/a&gt;. The &lt;a href="http://www.vishalpatel.com"&gt;Vishal Patel&lt;/a&gt; guy is back. And, how!&lt;br /&gt;&lt;br /&gt;Although his website is full of gems that are going to get you LMAOWOPITOAGMTL [1], this one post about the Ek-Anek national integration cartoon is enough to get you in splits!&lt;br /&gt;&lt;br /&gt;Checkout the next/previous links at the end of the first page... "Anek chidiyon ki kahaani sunoge?" "haan, haan &gt;&gt;" / "&lt;&lt; nahin bas"! Ha ha!&lt;br /&gt;&lt;br /&gt;'Nuff said. (And do click on the "haan, haan &gt;&gt;" link to LMAOWOPITOAGMTL [1]!)&lt;br /&gt;&lt;br /&gt;[1] &lt;b&gt;Note:&lt;/b&gt; Laughing My Ass Off While Other People In The Office Are Giving Me The Looks!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-5397365572903711897?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/5397365572903711897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=5397365572903711897&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5397365572903711897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/5397365572903711897'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/03/funniest-post-ive-read-in-recent-past.html' title='The funniest post I&apos;ve read in the recent past...'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-4523775287479334010</id><published>2008-03-11T00:09:00.002+05:30</published><updated>2008-03-11T00:14:02.562+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='random'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><title type='text'>What if you can't design for yourself?</title><content type='html'>Picking up from &lt;a href="http://www.37signals.com/svn/posts/904-why-we-disagree-with-don-norman"&gt;Jason's post at SvN&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;Apart from the flame war that's going on the comments section there, there is one thing about the "design for yourself" philosophy that has intrigued me. What if you really aren't designing for yourself? What if the software that you are developing/designing is not for your daily use? For example an accounting+finance system that is to be used by hardcore accountants? Do you not concede to how the end user wants the software to function? Don't you lose confidence in your "gut feel" automatically?&lt;br /&gt;&lt;br /&gt;The products that 37signals are working on are general purpose products, as such. A project management tool, todo list, CRM application can be used by any company or department. What about specialized software? Can we apply the same principles there?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-4523775287479334010?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/4523775287479334010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=4523775287479334010&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4523775287479334010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4523775287479334010'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/03/what-if-you-cant-design-for-yourself.html' title='What if you can&apos;t design for yourself?'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6836909.post-4945091557012951624</id><published>2008-03-09T10:21:00.007+05:30</published><updated>2008-03-09T11:37:29.405+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='tech'/><category scheme='http://www.blogger.com/atom/ns#' term='software'/><category scheme='http://www.blogger.com/atom/ns#' term='gyaan'/><title type='text'>How to reset an Oracle sequence at midnight everyday</title><content type='html'>Oracle, unlike MySQL, does not auto-generate values for the primary key column for you. That means, you can't "auto_increment" a column in Oracle. With each INSERT statement you have to provide the value for the primary key column yourself. Oracle has database sequences to help you generate series of numbers for this purpose.&lt;br /&gt;&lt;br /&gt;Sometimes you end up using Oracle sequences for stuff other than as a source of values for your primary key. And sometimes you need to reset the value of the sequence back to 1 at midnight everyday. I ended up with the same problem and I couldn't find a canned solution off the Net for this. I spent a day trying to solve this and ended up learning a lot about Oracle sequences, Oracle packages and PL/SQL, the dbms_lock package, and the dbms_scheduler package. &lt;br /&gt;&lt;br /&gt;The problem would be fairly easy to solve if resetting an Oracle sequence were a single atomic SQL statement. No, it turns out that you have to do a bit of circus involving multiple statements to reset the sequence back to 1. I figured that you basically have two options:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Drop the sequence (statement #1) and recreate the sequence (statement #2)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Change the INCREMENT BY property of the sequence to be negative of the CURRVAL (statement #1). Increment the seqeunce (statment #2). Reset the INCREMENT BY property back to 1 (statement #3).&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;In both the solutions, you run the risk of some other process coming along and doing a seq.nextval on the sequence while the reset is underway. Boom! A bit like getting caught with your pants down.&lt;br /&gt;&lt;br /&gt;So, here's what I did:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Create a PL/SQL package in Oracle which acts as a proxy for the sequence. Make sure that no application module does a seq.nextval directly. All requests to get the nextval have to go through the getNextSeq() function/procedure provided by the PL/SQL pacakge.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The getNextSeq() function first acquires a lock in &lt;b&gt;shared mode&lt;/b&gt; provided by the dbms_lock package in Oracle. Increments the sequence. Releases the lock, and returns the nextval. (Note: The dbms_lock package is a general purpose lock library. It does not mean that you &lt;i&gt;acquired a lock on the sequence&lt;/i&gt; - that's not possible in Oracle, as some gurus told me. You just acquire &lt;i&gt;a lock&lt;/i&gt;. Very much like a mutex lock you acquire in programming languages.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In the same PL/SQL package, you create a function resetSeq() which acquires the same lock in &lt;b&gt;exclusive mode&lt;/b&gt;, resets the sequence using either of the solutions given above, and releases the lock.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Now, you can create a scheduled job in the DB using the dbms_scheduler package to run the resetSeq() function at midnight everyday. In fact, you can execute that at whatever frequency/interval you want.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;In the process I also realised that Oracle has the capability of doing a fair amount of metaprogramming through the EXECUTE IMMEDIATE statement. You can pass it any string and Oracle tries to parse + execute that as an Oracle statement, much like eval in Ruby or Lisp.&lt;br /&gt;&lt;br /&gt;I spent most of my time breaking my head over why dbms_lock.request didn't seem to be working. Then I realized that dmbs_lock.allocate_unique worked on a &lt;i&gt;per session&lt;/i&gt; basis. What that means is, if two separate connections called dmbs_lock.allocate_unique to create a lock with the same lock handle, both of them would end up getting lock objects that would behave &lt;i&gt;independently&lt;/i&gt; of each other. In which case, effectively, both the processes were working on different locks and the whole purpose of using locks would be defeated. This is why, I'm calling allocate_unique just once, and "hard coding" the lock id in the package definition using Oracle "metaprogramming".&lt;br /&gt;&lt;br /&gt;PS: I'm still not sure whether this is the best solution to this problem, but it's a solution that works. Please let me know if you have a better way of solving this.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Here's the script:&lt;/b&gt;&lt;br /&gt;&lt;pre style="overflow: scroll; width: 45em;"&gt;&lt;br /&gt;set serveroutput on;&lt;br /&gt;declare&lt;br /&gt;    lock_handle number;&lt;br /&gt;begin&lt;br /&gt;    dbms_lock.allocate_unique('my_lock', lock_handle, 31536000);&lt;br /&gt;    dbms_output.put_line('Dropping my_seq');&lt;br /&gt;    execute immediate 'drop sequence my_seq';&lt;br /&gt;&lt;br /&gt;    dbms_output.put_line('Creating my_seq');&lt;br /&gt;    execute immediate 'create sequence my_seq minvalue 1 nocache increment by 1';&lt;br /&gt;&lt;br /&gt;    dbms_output.put_line('Creating my_pkg declaration');&lt;br /&gt;    execute immediate 'CREATE OR REPLACE PACKAGE "my_PKG" AS&lt;br /&gt;  procedure reset_my_seq;&lt;br /&gt;  function get_my_next_seq return number;&lt;br /&gt;END;';&lt;br /&gt;&lt;br /&gt;    dbms_output.put_line('Creating my_pkg definition');&lt;br /&gt;    execute immediate 'CREATE OR REPLACE PACKAGE BODY "my_PKG" AS&lt;br /&gt;  my_lock_handle number := ' || lock_handle || ';&lt;br /&gt;  &lt;br /&gt;  procedure reset_my_seq is&lt;br /&gt;    lock_status integer;&lt;br /&gt;    curr_val integer;&lt;br /&gt;  begin&lt;br /&gt;    lock_status := dbms_lock.REQUEST(lockhandle =&gt; my_lock_handle, lockmode =&gt; dbms_lock.x_mode);&lt;br /&gt;&lt;br /&gt;    execute immediate ''alter sequence  my_seq minvalue 0'';&lt;br /&gt;    execute immediate ''select my_seq.nextval from dual'' into curr_val ;&lt;br /&gt;    execute immediate ''alter sequence my_seq increment by -'' || curr_val ;&lt;br /&gt;    execute immediate ''select my_seq.nextval from dual'' into curr_val ;&lt;br /&gt;    execute immediate ''alter sequence my_seq increment by 1'';&lt;br /&gt;&lt;br /&gt;    lock_status := dbms_lock.release(lockhandle =&gt; my_lock_handle);&lt;br /&gt;  end; &lt;br /&gt;  &lt;br /&gt;  &lt;br /&gt;  function get_my_next_seq return number is&lt;br /&gt;    lock_status integer;&lt;br /&gt;    next_seq number;&lt;br /&gt;  begin&lt;br /&gt;    lock_status := dbms_lock.REQUEST(lockhandle =&gt; my_lock_handle, lockmode =&gt; dbms_lock.s_mode);&lt;br /&gt;    select my_seq.nextval into next_seq from dual;&lt;br /&gt;    lock_status := dbms_lock.release(lockhandle =&gt; my_lock_handle);&lt;br /&gt;    return next_seq;&lt;br /&gt;  end;&lt;br /&gt;END;';&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    -- dbms_output.put_line('Dropping scheduler job');&lt;br /&gt;    --  dbms_scheduler.drop_job('reset_my_seq');&lt;br /&gt;&lt;br /&gt;    dbms_output.put_line('Creating scheduler job');&lt;br /&gt;    dbms_scheduler.create_job( job_name=&gt; 'reset_my_seq',&lt;br /&gt;    job_type=&gt;'PLSQL_BLOCK',&lt;br /&gt;    job_action=&gt; 'begin my_pkg.reset_my_seq; end;',&lt;br /&gt;    start_date=&gt; systimestamp,&lt;br /&gt;    repeat_interval=&gt;'frequency=daily;interval=1;byhour=0; byminute=0; bysecond=0;',&lt;br /&gt;    enabled=&gt;true);&lt;br /&gt;    commit;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6836909-4945091557012951624?l=nandz.blogspot.com'/&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://nandz.blogspot.com/feeds/4945091557012951624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=6836909&amp;postID=4945091557012951624&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4945091557012951624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6836909/posts/default/4945091557012951624'/><link rel='alternate' type='text/html' href='http://nandz.blogspot.com/2008/03/how-to-reset-oracle-sequence-at.html' title='How to reset an Oracle sequence at midnight everyday'/><author><name>Saurabh Nanda</name><uri>http://www.blogger.com/profile/00867453089820169282</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='18331976337516182080'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry></feed>