Wednesday, January 21, 2009

How to make a PDF from a series of images

I was compiling a supplication extracted from a book of supplications. The problem at hand was to make a PDF out of various A4 images I had i.e. page01.xcf, page02.xcf, .., and so on. (XCF is a GIMP image)

A friend suggested ps2pdf, a command-line tool to convert from PostScript files to PDF.
Since GIMP can save to PS format, I saved all my images into PS format first.
However, the tool would accept only one ps file as input. So, I could get PDF file for each image, separately. Clearly this is not desired.

However, ps2pdf can read input from stdin by using -.
The solution was straightforward now:
$ cat page*.ps | ps2pdf - supplication.pdf

Works out of the box! (though takes some time).

Thursday, December 25, 2008

The day Merb joined Rails

It's a historic day in history of Rails (and Merb). Eyepoppingly shocking, Merb 2 has a new name -- Rails 3. Yes! Merb is being merged into Rails 3!

DHH and Yehuda Katz announced it almost simultaneously. 96% people are positive about the merger. If you belong to 4%, David has an answer for you.

Ezra explains how Merb is undergoing a rebirth. This merger would hopefully break the myth that Rails is a monolith. Interesting to see community putting an end to drama and coming together.

Friday, December 19, 2008

Programming has evolved

When I look at the recent advancements in Behaviour Driven Development in Rails, I tend to think that programming has really evolved. Not in terms of advanced data structures and superior algorithms, but as a focus shift of intention.

Earlier the focus was the machine. Days are gone when we thought so much about saving an extra byte, trading code simplicity for speed. A compromise here, a saving there, ad infinitum.

The focus has definitely shifted to human understandability. Beauty of code now lies in its simplicity (some folks would argue that it always did, and they're right, but its more so apparent now).

First it was Ruby, then Rails, and now BDD frameworks like rSpec and Cucumber prove the point. Just have a look at these executable code examples.

animals = [ "Tiger", "Cow", "Python", "Horse" ]
animals.each do |animal|
puts animal + "is cool!"
#=> Tiger is cool! Cow is cool! ...
Does a C for loop or C++ iterator look more elegant?

class Project
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
Code that you can just read, isn't it?

lambda {
}.should change(employee, :title).from("Mail Clerk").to("CEO")
Yes, that's a real executable example.

And now, Cucumber
Scenario: Search by topic
Given there are 240 courses where neither has the topic "biology"
And there are 3 courses A,B,C that each have "biology" as one of the topics
When I search for "biology"
Then I should see a the following courses:
| title |
| A |
| B |
| C |

More beautiful, more succinct, more concise. That's what programming has evolved to be.

Thursday, December 18, 2008

Git your branch name into your shell

I use git on my Ubuntu for my Rails projects, and very frequently I need to know what branch I'm working on right now.
If I can just get my shell to display the current local branch all the time in the prompt, it'd be a lot easier. I just found I could do so.

You need to modify the environment variable PS1 to show your current local git branch.

For me, it looks like this now.

PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w [$(git branch 2>/dev/null| grep "\*" | cut -f 2 -d " ")]\$ '

And it renders out like

kazim@invincible:~/projects/aprioriate [refactoring]$

In short, you need to append the following to the PS1 string.

[$(git branch 2>/dev/null| grep "\*" | cut -f 2 -d " ")]\$

The redirection of stderr to /dev/null is required since it suppresses git error messages in case you're not inside a git directory.

Ugly though it may be, it works. And to make the PS1 persist, add the line into your ~/.bashrc file.

PS: I use bash. For zsh and others, its even easier to do this.

Monday, October 13, 2008

Finally, a solution to file sharing woes

File sharing was never easy, especially for big files. I don't trust GMail, even when it says it allows attachment size of 20M. I often had my GMail frozen attaching just a 7M file, after some 20 minutes (which is way too much for just a 7M file!).

Enter DropBox. 20GB of free online storage. And a desktop interface which sticks to your Windows Explorer/Mac Finder/GNOME Nautilus seamlessly. I won't say this is a new solution, since we had GMail drive once, and many others kept popping up.

What makes DropBox special is ease of use with friendliness. And you can keep working while it synchronizes your files quietly in the background. You can also set maximum download/upload limits, so that your browsing experience remains okay.

Go ahead. Tour Dropbox. See the screencast. Download it. Link your computer and start sharing. And be thankful to me forever!

Thursday, March 20, 2008

Shortcuts in GNOME

There are more than one ways to set Keyboard Shortcuts in GNOME. In my Ubuntu 7.04, you can either go to System -> Keyboard Shortucts and change/add keybndings there. This way, you can change keybindings for most common operations like "Launch Web Browser" etc.

There's another way, a very versatile one, provided by GTK. In almost any GTK application, you can give shortcuts to menu items. Just open the menu, and point with your mouse on the menu item you want to give a shortcut to, and press the shortcut key. GNOME will automatically assign that shortcut to that menu item, and remember it.

If the procedure outlined above doesn't work for you for some reason, launch gconf-editor from a terminal. Make sure that desktop/gnome/interface/can_change_accels is true. Happy shortcuts!

Saturday, February 23, 2008

Recovering a (Lost) ReiserFS Partition

The partition table on my sister's laptop always seemed fishy to me. It just didn't have the right feel about it. The cylinder numbers and sizes and all, but I never cared. As the laptop went through a series of installations, Ubuntu or Windows, the abnormality showed up.

After installing Windows, I found hard to install GRUB on MBR. The grub-install would refuse, and so would the grub. I was troubled when the output of cfdisk said that 30G is unusable space, out of my 60G disk.

But, I thought its just another routine partition table corruption, and I had a tool in my swiss-army knife - testdisk ( Testdisk analyses your disk for lost partitions and tries to guess the correct partition table. Then it shows the guess to the user, who can then choose to write the table or not.

In my case, though testdisk correctly guessed the partitions (it found more than actual ones), it could not guess a proper partition table. Instead, it asked me to specify which partition is primary, logical or bootable primary. Now that was difficult for me. And I didn't want to take risks.

One good thing about testdisk is that it lets you peek inside partitions and read filenames. I was particularly interested in recovering a ReiserFS partition, which was 20G in size. Fortunately, testdisk was able to see this partition, and the filenames too. It was found lying from cylinders 3856 to 6287.

Anybody who knows a bit about recovery knows that if you know the cylinder numbers, you've solved the problem. Recovering a partition becomes an easy job. I started by dd'ing out from cylinder 3856 about 1MB. But the result was not as expected. It wasn't a superblock. It was just 'data'. Just data? How could it be that testdisk was lying?

$ file mydump
mydump: data

I checked the calculations again, yet to no avail. It was data there. One thing was for sure -- the superblock must begin somewhere near cylinder 3856. I got a weird idea. I quickly made a dummy file of 200M using dd. I made a loop device out of it, and did a reiserfs format over it.

$ dd if=/dev/zero of=check-rfs bs=1M count=200
$ sudo losetup -f check-rfs
$ sudo mkfs.reiserfs /dev/loop0
$ hd check-rfs | less

I intended to find out the pattern with which a reiserfs superblock starts. The output of hexdump showed something like this:

00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00010000 00 32 00 00 ec 11 00 00 13 20 00 00 12 00 00 00 |.2....... ......|
00010010 00 00 00 00 00 20 00 00 00 04 00 00 93 98 2f 43 |..... ......../C|
00010020 84 03 00 00 1e 00 00 00 00 00 00 00 00 10 cc 03 |................|
00010030 02 00 01 00 52 65 49 73 45 72 32 46 73 00 00 00 |....ReIsEr2Fs...|
00010040 03 00 00 00 02 00 01 00 02 00 00 00 00 00 00 00 |................|

Look how smartly the filesystem developers have written ReIsEr2Fs there! The third line, which has 2 and a space, actually contains disk label.

With this amount of information, I tried to find the superblock in the 10MB dump.

$ hd mydump | grep -i reiser2fs

And fortunately, it was there! At an offset of about 1d200h from cylinder 3856.

0001d200 02 00 01 00 52 65 49 73 45 72 32 46 73 00 00 00 |....ReIsEr2Fs...|

Looking a few 100 bytes before this pattern, I found exactly the same fingerprint of ReiserFS superblock! After calculating and adding, I did a dd dump from the correct byes, and here it was -- the superblock!

$ file dump-again
dump-again: ReiserFS V3.6 block size 4096 num blocks 4883760 r5 hash

I took a bigger dump (2G), and tried to mount it. But mount refused, simply because there was not enough space on the loop device than the partition required (20G).
I looked for some IRC help, and enouf on ##linux suggested the offset option of the mount command. It can do just what I wanted -- to mount a range of bytes of a disk as a device.

$ sudo mount /dev/sda recovered/ -o ro,loop,offset=31716679680
$ ls recovered/
bin cdrom etc initrd initrd.img.old lost+found mnt proc sbin sys tools var vmlinuz.old
boot dev home initrd.img lib media opt root srv tmp usr vmlinuz

And there it was! Recovered intact. The next thing I did was to backup the 15G data it had. And I got a treat from my sister, too. :-P

Simplicity is often wonderful. And so is Linux.