Saturday, April 19, 2008

[HTML] The under-used <label> tag

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.

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:

Without the label tag



With text boxes clicking on the label will shift the cursor into the associated text box:

Enter your name (without label):



All you need to do is give the form field an id tag and associate the label with it:
<input type="checkbox" id="example2" /> <label for="example2"> With the label tag</label>

Impulse Purchase

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!

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.

What the fuck do I do with it now? Any ideas?

Saurabh Nanda. Proud (confused?) owner of www.hornyplease.com!

Wednesday, April 09, 2008

Composing blog posts in Textile Markup

Why can't I compose posts in Textile Markup? 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.

I've submitted a feature request and also posted about it on the Blogger Help Group.

Tuesday, April 08, 2008

Clueless with Computers...

... that's how non-geeks feel. I'm extremely sure of that now.

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.

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.

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.

Me: Okay, now that you've accepted them, you can see the schedule in the calendar.
Mom: How do I get to the calendar?
Me: Okay, do you use Outlook? [That's what most offices use.]
Mom: Yes.
Me: So, the left pane, sorry column, sorry left side of the screen will have a button for calendar. Click on it.
Mom: It's not there.
Me: Can you see your mail folders?
Mom: Yes. But no calendar.
Me: Okay, I'll call you back in 5 min.

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!

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 > Calendar" if you don't already know. The shortcut for it is Ctrl+2.

Back to the phone:

Me: Okay, press Ctrl+2.
Mom: [After 30 sec] I did, nothing happened.
Me: Are you in Outlook? [Damn!]
Mom: Yes.
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?
Mom: No, there's no "Go" option!
Me: Are you sure you're using Outlook?
Mom: Yes.
Me: Are you sure it's not Netscape?
Mom: [getting irritated] yes!
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]
Mom: No. It's on my desktop. We have two different icons. One for Internet Explorer and the other for Outlook Express. [!!]

I wanted to pull my hair out! And as it turn out, Outlook Express, indeed does not have a calendar application.

I just gave up on the entire cool iCal stuff. Took a screenshot of my Evolution Calendar screen and mailed it to her.

Sunday, April 06, 2008

[Ruby] A few points about Ruby threading...

... it's green threaded.

That means, the threading is simulated by the Ruby VM and they are not "true OS threads".

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.

A few links about how threads in Ruby work:

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)

PS: And in case you're wondering, ActiveRecord *is* thread-safe. It's just that most apps don't use it because of the preferred way of achieving concurrency in Ruby (forking processes).

Saturday, April 05, 2008

[Ruby] Madness with the 'require' command

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.

Basically, when you use require 'file' 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 require 'file' and require './file' the damn file will be loaded twice.

WTF?! Seriously!

Anyways, I thought this was undocumented behaviour but I found this in the RDoc entry for 'require' - should have looked there before.

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.

Saturday, March 15, 2008

The funniest post I've read in the recent past...

... is Ek, Anek, aur Ekta. The Vishal Patel guy is back. And, how!

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!

Checkout the next/previous links at the end of the first page... "Anek chidiyon ki kahaani sunoge?" "haan, haan >>" / "<< nahin bas"! Ha ha!

'Nuff said. (And do click on the "haan, haan >>" link to LMAOWOPITOAGMTL [1]!)

[1] Note: Laughing My Ass Off While Other People In The Office Are Giving Me The Looks!

Tuesday, March 11, 2008

What if you can't design for yourself?

Picking up from Jason's post at SvN:

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?

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?

Sunday, March 09, 2008

How to reset an Oracle sequence at midnight everyday

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.

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.

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:

  1. Drop the sequence (statement #1) and recreate the sequence (statement #2)

  2. 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).


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.

So, here's what I did:

  1. 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.

  2. The getNextSeq() function first acquires a lock in shared mode 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 acquired a lock on the sequence - that's not possible in Oracle, as some gurus told me. You just acquire a lock. Very much like a mutex lock you acquire in programming languages.)

  3. In the same PL/SQL package, you create a function resetSeq() which acquires the same lock in exclusive mode, resets the sequence using either of the solutions given above, and releases the lock.

  4. 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.


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.

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 per session 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 independently 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".

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.

Here's the script:

set serveroutput on;
declare
lock_handle number;
begin
dbms_lock.allocate_unique('my_lock', lock_handle, 31536000);
dbms_output.put_line('Dropping my_seq');
execute immediate 'drop sequence my_seq';

dbms_output.put_line('Creating my_seq');
execute immediate 'create sequence my_seq minvalue 1 nocache increment by 1';

dbms_output.put_line('Creating my_pkg declaration');
execute immediate 'CREATE OR REPLACE PACKAGE "my_PKG" AS
procedure reset_my_seq;
function get_my_next_seq return number;
END;';

dbms_output.put_line('Creating my_pkg definition');
execute immediate 'CREATE OR REPLACE PACKAGE BODY "my_PKG" AS
my_lock_handle number := ' || lock_handle || ';

procedure reset_my_seq is
lock_status integer;
curr_val integer;
begin
lock_status := dbms_lock.REQUEST(lockhandle => my_lock_handle, lockmode => dbms_lock.x_mode);

execute immediate ''alter sequence my_seq minvalue 0'';
execute immediate ''select my_seq.nextval from dual'' into curr_val ;
execute immediate ''alter sequence my_seq increment by -'' || curr_val ;
execute immediate ''select my_seq.nextval from dual'' into curr_val ;
execute immediate ''alter sequence my_seq increment by 1'';

lock_status := dbms_lock.release(lockhandle => my_lock_handle);
end;


function get_my_next_seq return number is
lock_status integer;
next_seq number;
begin
lock_status := dbms_lock.REQUEST(lockhandle => my_lock_handle, lockmode => dbms_lock.s_mode);
select my_seq.nextval into next_seq from dual;
lock_status := dbms_lock.release(lockhandle => my_lock_handle);
return next_seq;
end;
END;';


-- dbms_output.put_line('Dropping scheduler job');
-- dbms_scheduler.drop_job('reset_my_seq');

dbms_output.put_line('Creating scheduler job');
dbms_scheduler.create_job( job_name=> 'reset_my_seq',
job_type=>'PLSQL_BLOCK',
job_action=> 'begin my_pkg.reset_my_seq; end;',
start_date=> systimestamp,
repeat_interval=>'frequency=daily;interval=1;byhour=0; byminute=0; bysecond=0;',
enabled=>true);
commit;
end;
/

Thursday, February 07, 2008

FOSSKriti at Techkriti 2008 -- The IIT Kanpur Technical Festival

Cleartrip is supporting FOSSKriti – a 4 day mini-conference about Free/Open Source Software. It'll have technical talks, hands-on workshops, hackfests, and general geek chatter.

In an RoR workshop I'll be creating the OARS (Online Academic Registration System) website in 90 minutes – or something that can at least be called the OARS website. My friend Chaitanya will be giving a talk on Common Lisp.

If you're somewhere around, be there – it'll be fun.

FOSSKriti