Sunday, December 23, 2007

getting the memo

Last night, we went to a friend's wedding reception. About 30 minutes before when we had to leave, I started rummaging around looking for a suit, tie, and nice shirt - all those pieces of clothing that rarely get used. I tried to get some advice on tie/shirt matching over IM from a friend. Finally, frustrated, I decided that I was just going to wear a Kurta instead. I have some Kurtas from the various ceremonies surrounding our wedding - and they never see the light of day anyway. I picked a nice white one with a bit of embroidery on it.

We showed up at the hotel and proceeded to grab a drink and appetizers. I didn't see anyone else wearing a kurta. About 45 minutes into the event, I was pretty distraught; whereas the women were decked out in their finest Indian clothes, I stood alone, in bright white, in a sea of black suits.

It's as if everyone else there got the memo, but they forgot to cc me.

You'd think more people would wear Indian clothes at an Indian wedding, huh? But maybe evening events call for a suit.

So what does one do in a situation like that? I did what any self respecting male does. I downed my wine, took a few gulps of scotch, and used all that liquid confidence to pretend like *they* hadn't received the memo.

I'm penning this for posterity, lest all the liquid confidence makes me forget to wear a suit next time.

Thursday, December 13, 2007

Socio-adjusting

Babies have this comfort zone of how many people they want to be around. If they grow up with lots of people around, they suddenly feel at a loss when they are alone. If they are used to just having their parents around, they feel overwhelmed when they are around many people for a long time.

I've noticed it with many 2nd generation indian kids who go back to India on vacation. They flip out when they first get there, because they're suddenly being doted on by grandparents, uncles, aunts, and cousins. Three or four weeks later, they head back home and are suddenly antsy when only their parents (and maybe siblings) are around.

I think that happened to me this month. I've been working alone for the past nine months and was suddenly thrust into three weeks of meeting people (though I actually didn't do the normal amount of socializing because I was pretty busy working).

Now I'm back in Berkeley, and working from an empty, quiet home again seems awfully difficult.

Thursday, December 06, 2007

not another rails post

It has come to my attention that many of my readers couldn't care less about rails. I apologize. Since this past february, my life has been consumed by reporterist. I eat, breathe, and dream about it. Bed-talk with my wife often involves reporterist brainstorming.

And yet, life does tend to have a way of going on. I'm currently spending a few weeks in Pune, and am fortunate to be able to attend the famous Sawai Gandharva Mahotsav - a four-day indian classical music festival. It's my first ever, and the first day was great!

I'm happy to report that eighteen months of living in Bangalore seems to have solidified my India-driving skills. I'm now pretty comfortable driving here even after not doing so for a year.

I got a wisdom tooth removed, and have been in pain for over a week. Earlier this week I decided to stop taking painkillers, and start drinking instead. A bit of cognac from Dad's bar seems to have eased the pain (and pleased the palette) this evening.

Saturday, November 24, 2007

testing mailers in rails

AFAIK, the only way to test mailers is to create a mail object directly, and then look for textual matches within the mail body.
That's lame. I wanted something more akin to the 'template_objects' method that you can call on a response when writing functional tests.

Turns out that ActionMailer::Base does some funky stuff that makes it really hard to do this. Here's what I resorted to in the mean time:

Let's say that my NotificationMailer looks something like:

class NotificationMailer < ActionMailer::Base
def my_notification_method
@body['name'] = "bob"
end
end


add the following code in test_helper.rb:

ActionMailer::Base.class_eval {
alias initialize_which_results_in_auto_create initialize
def initialize( method_name = nil, *params )
return if( :test == method_name )
initialize_which_results_in_auto_create( method_name, *params )
end

class << ActionMailer::Base
def grab_vars( method, *params )
obj = new(:test)
obj.send( :initialize_defaults, method )
obj.send( method, *params )
return {:body => obj.body, :subject => obj.subject, :recipients => obj.recipients}
end
end # class
}


I can now check for 'assigns' as follows:

nm = NotificationMailer.grab_vars( :my_notification_method )
assert_equal( "bob", nm[:body]['name'] )


That's still fugly, but it lets me test the @body hash at least. If you have a better way of doing this, or a way to make that look prettier, please let me know!

Friday, September 28, 2007

Rails Integration Testing

I found this to be a pretty good (well, there's not really much info out there) intro to writing integration tests.

But if you look in the comments, people are sort of stumped on how to deal with logging in users when you don't have passwords stored in the clear.

Here's my solution, which injects the user object directly into the request session, meaning that you don't need any other ugly hacks (such as letting your user controller accept hashed passwords.. ugh).



# http://weblog.jamisbuck.org/2006/3/9/integration-testing-in-rails-1-1
# describes some cool integration testing, but there's no
# solution for how to 'inject' a user into the system when all
# you have is hashed passwords.
# The code below lets you inject a user object directly into your
# 'session' object.

# So you can add the following methods to your integration test (see the above blog
# for more explanation):
#
# def new_session_as( user )
# new_session do | sess | # new_session is defined per the blog post above
# sess.user_object = user # aha this is where we inject the user object
# yield sess if block_given?
# end
# end


# allow a user_object to be injected via the HTTP headers
ActionController::Integration::Session.class_eval {
attr_accessor :user_object
alias process_without_user_headers process
def process( method, path, parameters=nil, headers=nil )
unless self.user_object.nil?
headers = (headers || {}).merge( {'X_USER_HACK' => self.user_object } )
end
process_without_user_headers( method, path, parameters, headers )
end
}

# extract the user object from the headers, and store it as an attribute
ActionController::Integration::Session::MockCGI.class_eval {
alias initialize_for_real initialize
attr_accessor :user_object
def initialize( env, input )
user = env.delete( 'HTTP_X_USER_HACK' )
self.user_object = user
initialize_for_real( env, input )
end
}

# extract the user object from the mock cgi class, and
# set it up in our session
ActionController::CgiRequest.class_eval {
alias initialize_for_real initialize
def initialize( cgi, options )
initialize_for_real( cgi,options )
# The following line may be different for you:
self.session['user'] = cgi.user_object
end
}

Wednesday, August 29, 2007

reporterist.com private beta

So we just officially launched a private beta of reporterist to 60 professional journalists.
We just launched a very, very small subset of our functionality - just to get some initial feedback from our users.

I'm super excited (and nervous).

You can follow the reporterist blog for more updates.

In other, more personal, news; we found an nice apartment in Berkeley (not the easiest of things to do) and have begun to settle in. Our neighbours are awesome - three of the wife's classmates actually stay next door.

That's all for now.

Friday, August 03, 2007

amazon fps launched!

This is very exciting! The Amazon Flexible Payments Service has finally launched!

I say finally, because I had the honor to be a small part of the development of this service when I moved to Bangalore. Amazon FPS was built almost entirely out of India by a really awesome team.

I left that team in February 2006, so I can't claim that much of my code lives on (which may be a good thing!) but I'm definitely proud to have played a part.

Awesome job guys!

update: here's the aws blog post.

Wednesday, July 25, 2007

figuring out the gmail spam filters

So I'm working on a web application, and today I was trying to send invites out to some users. Turns out that they were going into the gmail spam filter.

I made sure that my RDNS (Reverse DNS) was set up correctly, and then I checked the email headers to ensure that gmail didn't suspect my ISP's IP address as a spammer IP.

A friend suggested that it might have something to do with the content of my emails, and not the body.

So I started playing around and, sure enough, that was it. After several emails I realized that it had to do with the link I was sending in the email. At first I thought that it might have to do with the length of the link (and an MD5-encoded token in the params).

After several tests I figured out exactly what trips it: If I send email from a foo.com server (hostname = foo.com, DNS and RDNS consistent with foo.com) with a signup link for foo.com, then that sends the mail to spam. If, on the other hand, I send email from a bar.com server with a link to foo.com, then the email makes it through the spam filter.

That seems so non-intuitive to me. It seems more shady for an email from bar.com to have a link to foo.com in it.

Anyways, I've got a temporary work-around (I think?), but I still don't know the 'right' way do this.

Monday, July 02, 2007

music for the soul

At most points in my life, I've listened to, sang, played, and loved music that 'spoke' to me. I think most people know what I'm talking about.

Sadly, there have been some points (more so recently) when I just haven't been able to find music that speaks to me. Much of my music collection just doesn't do it for me anymore. Even classic evergreens like U2 and Bob Dylan - which usually always have something to say to me - just fall on my ears but don't penetrate any deeper.

Those who know my general music taste; feel free to recommend me some new music.

Wednesday, June 13, 2007

The quest for quarters

It's been a while since I needed quarters to do laundry.
In Seattle, we had an in-unit washer/dryer, and in Berkeley we could send money from a student account directly to the machines.

In Baltimore, I we need quarters for laundry and, having just moved here, I don't have a jar full of them lying around. Of course, I waited until the last possible minute to do laundry. So yesterday I rolled out of bed and decided to go in search of quarters. The wife had the car, so I was limited to walking distance.

I started with the local mini-mart; he agreed to give me 4 quarters but no more. Next I went to the laundromat. The lady there was exceptionally rude and gave me a "yeah right" when I asked if she had quarters. She wasn't very helpful telling me about banks in the area either. My next stop was a few blocks away at a laundromat with a change machine; turns out that it had been broken for years. I went into another minimart, and the desi owner refused me quarters even if I were to buy something.

I finally gave up and came home. On rummaging through my suitcases, I was able to find one hiding undergarment, thus allowing me to shower.

In the evening when the wife got home, we went to the gym and decided to stop by a grocery store afterwards. We happened upon a small stripmall with a laundromat and pharmacy, so we stopped there.

As I was about to put my $20 bill into the change machine at the laundromat, I simultaneously heard a raspy voice and read the hand-scrwaled notice in front of me: "No change unless you're doing your laundry here!" I apologized and walked out, frustrated.

At the RiteAid, we purchased our wares, and politely (maybe desperately?) asked for a roll of quarters. She didn't have a roll, but gave us a few dollars and suggested that we ask the other cashier.

As we were about to ask the other cashier for change, the lady in front of us says to her daughter as she's walking away "ok. well, I think not we shold have enough for one more load."
The cashier was out of quarters.

I feel like we've entered the quarter-free twilight zone. Maybe this weekend we'll drive down to DC or Virgina and smuggle a few rolls of quarters over the border. Who knows, maybe we could sell them for a premiuim.

Thursday, May 17, 2007

roller coaster

Wow.

I had heard about how starting a company can be an emotional roller coaster. But it's been interesting to experience it first hand over the past 3 months. Every good customer response makes me feel on top of the world, and every time I think about all of the things that could go wrong, I start a downward spiral.

And I've barely just started! I'm sure it will become even more challenging once the stakes get higher.

I'm glad I'm not in it alone. Having someone else working on it is great - not only to get things done, but to smooth out the roller coaster, and to help in making judgment calls.

Sunday, April 29, 2007

emacs love

I was working on some ruby code just now. I had a hash with keys that were capitalized words, such as:

comp << l['Address'] unless l['Address'].empty?
comp << l['City'] unless l['City'].empty?
comp << l['State'] unless l['State'].empty?
comp << l['Zip'] unless l['Zip'].empty?
comp << l['Country'] unless l['Country'].empty?

but I made some changes so that all of the keys would now be lowercase and turned into symbols. Basically I wanted the output to look like this:

comp << l[:address] unless l[:address].empty?
comp << l[:city] unless l[:city].empty?
comp << l[:state] unless l[:state].empty?
comp << l[:zip] unless l[:zip].empty?
comp << l[:country] unless l[:country].empty?

With a little help from an ex coworker's blog, I was able to achieve this using the following regular expression:

M-x replace-regexp
l\['\([A-Z]\)\([^']*\)'\]
l[:\,(downcase \1)\2]

Note that the '\,' (backslash-comma) combination escapes the lisp command that is part of the replacement text.
I never ceased to be amazed by the power of emacs. I'm still decades away from being able to develop a webservice in lisp. :)

Tuesday, April 17, 2007

juice

I just received a juicer - the Breville JE95XL Two-Speed Juice Fountain Plus - from amazon. It's pretty sweet. I just made some carrot/celery/ginger juice. The leftover pulp is moist but not soggy - so it seems to have done a good job extracting. I'm going to see if we can bake the pulp into something though instead of wasting it.


Monday, April 16, 2007

The fire is burning.

Several people have asked me if I have a hard time motivating myself now that I'm starting something of my own. In fact, that's a question I asked my friend (and bluedot founder) a few months ago.

The answer is an emphatic no. I have this hot fire burning under my rear end that makes me do all sorts of odd things. Like wake up at 4:15am to start coding because I just dreamed up (literally) a line of code. Or pass on the wonderful california sun and sit inside and code all day.

I realized today that my first code-complete deadline is in about 15 weeks. And that just turned up the temperature a notch. The only redeeming thought is that what I have so far is only 6 weeks worth of actual coding.

Tuesday, April 10, 2007

eating whole and cheap

The wife is doing a story (possibly series of stories) on eating whole/ natural/ organic/ healthy on a low budget and without devoting your entire day to cooking (I'm busy coding all day, and she's busy with classes and assignments). We also live in a tiny studio with two hotplates, one bowl, two pans - you get the point - a minimalist kitchen.

This week we are on a $60/week food budget for the both of us.

My breakfast today was fig-bran muffins that she made (basic recipe courtesy our buddy guidoism) and a big strawberry/banana milkshake. For lunch I had a sandwich with guacamole (home-made), hummus (store-bought), yogurt (store-bought), cheese, tomatoes, and bread (store-bought). Dinner was lentil soup, asparagus, and bread. I want to try making my own hummus next.

I think we still have a few bucks left on our $60 budget, surprisingly, and a lot of ingredients with which to cook the rest of the week.

She hasn't yet decided how long this experiment will last. Part of me wants to continue with it for a while - just so I eat healthier and more creatively. The rest of me is hoping the budget will increase a little :)

Thursday, April 05, 2007

Magnifying mirrors

I've had this hunch for a while about people that really get on my nerves. The hunch is that the people that irritate me are the people in whom I see my bad qualities qualities reflected or, more often, magnified.

I wasn't sure about it but a few weeks ago the wife and I sat down and talked about all of the people that annoy each of us (both of us are pretty chill, if I may so say so myself, so the list was quite short - but both of us have a few people that drive us up the wall). We realized that, in each case, the thing that gets on our nerves about the person is some trait that we both are very conscious of in ourselves and try to change or improve.

So all of a sudden getting irritated by someone has a silver lining - it's just a little reminder about the things that we need to work harder on improving about ourselves.

I'm curious - have you found the same to be true in your experience?

Update: The wife claims that she came up with the idea long ago and I have just misappropriated it from her. The wife is always right.

Thursday, March 29, 2007

road trip

All of our belongings are now in a 17' U Haul, and we will be hitting the proverbial road shortly, to head for sunny California. Goodbye, Seattle. We'll miss you.

Wednesday, March 21, 2007

functional tests

The first time I played with rails (two years ago), I was super sloppy about writing unit tests for my models - I wasn't working on a very complex product.

This time, I've been very diligent about writing unit tests - and it has definitely paid off.

Since my application structure is still in flux, though, I haven't written a single functional test. SO far, so good. But now it's getting to the point where things are just starting to blow up a little at a time. Which goes to show that any shortcuts you take in life will come bite you in the ass sooner or later.

So now I need to temporarily stop working on refining the product and go back and get myself up to speed on how to write functional tests, and start writing tests for all of the stuff I've done so far. Once I get over the initial inertia, adding new tests, and refactoring them as the application changes should be actually quite easy.

Better now than after I have customers, I suppose :)

Thursday, March 15, 2007

Good old music

A few years ago when I got my iPod, I decided not to import all of the random mp3s that I had from college - mainly because they came from various sources and didn't have all the ID3 tags in a consistent format.

So I started by importing the CDs that I owned, and slowly grew my collection.

Eventually, I moved all those mp3s off onto a backup drive and forgot about them.

Then, the other night, I remember that I had a live recording of a U2 song - and I hadn't heard it in ages. So I found that stash of mp3s and started importing a lot of that music into iTunes; fixing up the ID3 tags as I went.

And now I have all this great music from when I was in college and high school and it's bringing back wonderful memories. What a gift.

Monday, March 12, 2007

startup lesson 1 of 496,324

Keeping quiet about my business idea has been very difficult for me. Anyone who knows me knows that you can't get me to shut up on something I'm excited about. But I've been trying hard to be pretty hush hush about what I'm working on.

Why?

For one I've found that, for some inexplicable reason, whenever I talk about something, my effectiveness at actually executing on it dwindles. I dunno why, but it's as if the energy expended in talking about it takes away from the energy required to do it.

Second, I really want to get a first customer on board so that I can hone in on the idea and also develop some comfort that I'm barking up the right tree.

Well this morning I had breakfast with a friend, who's also starting a company. He's a little further along than me, though, and has funding and a formal company structure. After some conversation where I was being my usual evasive self when talking about the idea, he offerd to sign a mutual NDA so we could talk more freely. That threw me off - it's the first time someone has offered that. So I accepted and we spent the hour talking about our respective ideas and challenges and stuff.

After leaving, though, I felt like a bit of a dumbass. Why? Because the reason I wasn't talking about the idea wasn't/isn't lack of trust. It was for the reasons above. And yet, by agreeing to talk after signing an NDA, I basically affirmed that I don't trust him enough to tell him about my idea without signing some stupid piece of paper.

Obviously I don't regret the conversation itself - I learnt a lot from it. And hopefully you (I'm assuming he'll read this at some point) didn't walk away thinking that I don't trust you unless I have a signed piece of paper saying so. I think I just have to be a little more aware in the future.

Maybe I'm being naiive, but I think friendships are much stronger than any signed document.

What are your thoughts?

Specifically: 1) would you sign an NDA with friends? 2) are NDA's even effective at all when talking to peopled you don't know that well?

(NDA = Non Disclosure Agreement)

Friday, March 09, 2007

table conformity in rails

I want all my tables to have certain characteristics. E.g. I want them all to be UTF-8, and all have a field called 'created_at'.

Instead of duplicating that code everywhere, here's what I'm doing:


class MyTables < ActiveRecord::Migration
  def self.create_table( table_name, options={}, &table_definition )
options[:options] = "" unless( options.has_key?( :options ) )
options[:options] += " DEFAULT CHARSET=UTF8 "
super( table_name, options ) do |t|
t.column :created_at, :timestamp, :null => false
table_definition.call(t)
end
end
end

class Foo < MyTables
# use this like a regular migration
end



So now every migration Foo that inherits from MyTables automatically gets some default goodness.

Thursday, March 08, 2007

browser plugin idea...

There are a lot of books that people recommend to me that sound awesome but I don't quite want to own or read right away.

Imagine if you could select an ISBN number, or just visit the amazon.com page for a book, and click on a button in your browser. The plugin would automatically add it to your list of holds at the Seattle Public Library. You'd have to store your library number and PIN, and preferred pickup location with the plugin.

But after that, SPL will just send a notification when the book is available. Takes the hassle out of borrowing.

Also cool would be a wishlist importer that takes books (and maybe even cds and dvds) off your amazon wishlists and adds them to your list of library holds...

If such a thing exists, or if you write one as a result of this post, please let me know as I'd like to use it :)

insight

I recently attended a 10 day meditation retreat in Onalaska.

The course teaches Vipassana (loose English translation: 'insight'), and comes with quite a rigorous code of discipline (including no talking/reading/writing) for the duration of the course - which makes it a bit of a daunting endeavor to undertake. Nevertheless, at the recommendation of a few friends, I decided to go for it.

In line with what I had heard from friends, it was probably one of the most difficult things I've done in my life. Also in line with what others experienced, neither the 'noble silence' (see code of discipline) nor the limited meals and early wake up time (scroll to the bottom of the page) were as difficult as I thought.

While I was preparing myself for days of peaceful introspection followed by tumultuous emotions, this was quite the opposite. It ended up being a harrowing mental and physical experience (lots of thoughts, and pain respectively) that made it exceptionally difficult for the first few days.

The course was really an introduction to a theory of consciousness as espoused by Gautama Buddha, along with a technique that allows you to validate portions of that theory for yourself through direct experience. Obviously one cannot hope to completely understand consciousness within 10 days - no matter how rigorous the experience - but I feel as though the things I experienced first-hand allowed me to validate enough small pieces of the theory that I'm willing to not disbelieve the rest and trust that continued meditation will allow me to validate it for myself.

It's a little hard to attempt to lay the theory out here. But from mentioning it to a few people, it seems that it has enough in common with modern neuroscience, that it doesn't sound completely implausible. Specifically, I was recommended the book On Intelligence and told that some of the theories laid out there are very in line with the parts of the theory that I learnt.

In addition to that, I had a really cool conversation with someone who knows a lot about bipolar and the framework provided some interesting and different (no comments yet on whether they are useful) insights on what bipolar may mean.

Anyways, I know 10 days is a long time to take out of one's schedule, especially to sit quietly in one spot all day. But I think it was a fantastic experience. If you are a neuroscientist especially, I think you'd absolutely love going through this experience.

On a very very different note, A thought occurred to me today which I had to share. There are people that say that you make your own destiny and yet there are those that claim to be able to predict your future. I think I have an analogy that helps reconcile these into something that makes sense to me.

I've read many times that time is like a river. Always flowing, but always 'there'. In a whitewater course, one learns the very very basics of reading a river. Diagrams like these (scroll down) help tell you how bends, rocks, and changes in width of a river can affect its flow. Presumably if you know enough about the topology of a river, you can make a pretty educated guess about the strength and qualities of the currents at various points along it. And yet, nothing is preventing a big rock from rolling down the cliff and into the river and completely changing its flow. Or from erosion increasing the width and thus decreasing the strength of the current in a given place.

So if time, and life, are really like a river; then maybe there are people able to see the entire river at once and make fairly accurate predictions about downstream currents, given its current topology. But nothing prevents you from throwing a big old rock at the point of the river that we call 'now', and completely changing the downstream currents.

On that note, back to coding and attempting to start a successful business...

Tuesday, March 06, 2007

breakfast instead

I recently set up several breakfast appointments with friends instead of dinner. I really like the idea and think I'm going to do more of this if possible:
  • People generally have stuff planned in the evenings but not early in the morning
  • it's much healthier to eat a big breakfast instead of a big dinner (and I usually overeat when I eat out)
  • breakfast places are usually packed on the weekends (esp the good ones) - I'm guessing (hoping?) they're not as bad on the weekdays


So let's get together for breakfast sometime. There are a bunch of places that I haven't been to in a while, and a bunch that I haven't ever tried.

Wednesday, February 14, 2007

part of the seattle coffee shop scene

I guess one common way to get over the loneliness of working for yourself is to work out of a coffeeshop.

But, given my recent ergonomic adventures, I have been a little reluctant to do that for fear of my hands hurting from prolonged laptop typing.

Plus, it just seems superdorky to walk into a coffeeshop with your own keyboard.

Well, I'm a dork.

I'm at a cofeeshop right now with my keyboard sitting comfortably on my lap and mostly out of sight under the table. You'll have to ask the other people here how dorky they think I look.

For the most part I've been pretty productive, minus the distraction of listening to some startup deals taking place (that was very informative)

Tuesday, February 13, 2007

an unbalanced life

I remember when I was in college, more so in grad school, I had to try really really hard to take time out of my day to go running or to work out.

Whenever I actually got myself into the discipline of doing so, I'd usually be more productive and creative, but deciding to take that time out of my day was very hard.

A few weeks ago I was thinking that, now that I can choose my own hours, I'll be very good about going to the gym or at least going for a run. But somehow it's been ridiculously hard to pull myself away from the computer; I've been spending most of my waking hours getting up to speed on ruby on rails, and getting started on building my application. It sucks; I can even feel my energy levels dropping.

I think the commonality between grad school and now is that I own my own time. Maybe subconsciously in undergrad and at work I was able to say "you know if you're going to make me work this hard, I'm going to damn well make sure I have 'Hemant-time' to go be healthy". Whereas now (and to a large part in grad school) the entire day is 'Hemant-time' so it's harderer to justify taking time out of that.

Either way; I'm at the point today where my productivity is going to suffer if I don't get in some solid exercise. Hopefully, having written this, I'll make it out to the gym today.

Thursday, February 08, 2007

dvorak, anyone?

this is probably an incredibly stupid idea, but i'm thinking of trying to use a dvorak keyboard layout. has anyone tried that? anyone using one right now?

Wednesday, February 07, 2007

a simple tcp server

In the past, I've found it really useful to have a simple server that is able to listen on a TCP socket and print out everything it receives. It's a great debugging tool.


The following ruby snippet (adapter from an example in 'Programming Ruby') does just that:


require 'socket'
port = ARGV[0] || 80
server = TCPServer.new('localhost', port )
while( session = server.accept)
while !session.eof?
puts session.gets
end
end

Probably cooler would be if it took everything on STDIN and echo-ed it back to the socket as well.


Update: Thanks pooja. I couldn't think of netcat at the time but that does exactly what I want. I'm such an idiot for not remembering.

open source and deployment

I apologize in advance for those of you who don't particularly care to read any code.

But one of the things I'm going to try to do while working on my startup is to post as many code snippets as possible.

Why? Because I'm a believer in open source. My startup is not focussed around building great deployment tools. By posting my code, I'm helping other people who also need to solve similar issues. At the same time, there's a good chance that someone smarter than me will read this and tell me a much simpler or more elegant way of achieving the same result.

If it starts taking up too much of my time, I might post less stuff. If I start to see value in posting code, I might try to do more of it. Either way, I'm running as fast as I can to build an amazing product.

The following script should help me to write common config files and test them out on my mac first and then deploy them with no changes. See the usage function for more info.

Oh - and I'm still a newbie ruby programmer. So if you have code suggestions, or if there's a tool that already does what this does, then let me know. I have no qualms about throwing away my code and using someone else's. Less code = less bugs.


#!/usr/bin/env ruby
require 'yaml'

def usage( msg )
STDERR.puts msg
STDERR.puts <<EOF

USAGE
generate <config_file> <stage> files..

DESCRIPTION
Given the following config.yml:
--
test:
base: path1
user: name1
prod:
base: path2
user: name2
--
and a lighttpd.conf:

--
server.username = "$user$"
server.document-root = "$base$/public_html"
--

% generate config.yml test lighttpd.conf
will create the file lighttpd.conf.generated which looks like:

--
server.username = "name1"
server.document-root = "path1/public_html"
--

EOF
exit
end

usage() if( ARGV.size < 3 )

config_file = ARGV.shift
stage = ARGV.shift

usage( "config file #{config_file} not found. " ) unless File.exists?( config_file )

all_config = YAML.load_file( config_file )

unless( all_config.has_key?( stage ) )
usage("config file #{config_file} doesn't specify stage '#{stage}'.")
end

config = all_config[stage]

# build up the regexp to match all identifiers:
regexp_string = '('
config.each_key { |id|
regexp_string += '\$' + id + '\$|'
}
regexp_string.chop!
regexp_string += ')'
matcher = Regexp.new( regexp_string )


# Iterate through each file
ARGV.each { |filename|
unless( File.exists?( filename ) )
STDERR.puts "file '#{filename}' not found. continuing"
next
end
g_filename = filename + '.generated'
if( File.exists?( g_filename ) )
# TODO: move old file out of the way instead..
STDERR.puts "file '#{g_filename}' exists. OVERWRITING!"
end

generated = File.new( g_filename, "w" )
# check each line
File.open(filename).each_line{ |line|
# replace each instance of a token
line.gsub!( matcher ) { |match|
id = match[1..(match.size - 2)]
# with the value specified in the config file
config[id]
}
generated.puts( line )
}
}

Monday, February 05, 2007

Stepping over the edge.

After five years (well, technically about four years, eleven months, and change), I'm leaving amazon.com. It's been a pretty awesome time, and I've learnt a lot from some really smart and passionate people.

But sometimes, it's just time to move on. In my case, I'm stepping off the cliff of getting a paycheck to living on my savings and attempting to create something meaningful and with monetary value. I'm starting a company.

It's scary thinking about it.

Stay tuned here for more info, if you so desire.

-Hemant.

Update: I suppose, technically, the title should read stepped over the edge. I can feel the wind rushing by.

Thursday, February 01, 2007

Growing Up!

A few weeks ago I got the first DVD in the Up series, 7 Up!

The series is a set of documentaries, filmed every 7 years starting 1964, chronicling a bunch of British children from different backgrounds.

7-Up was funny, interesting, and boring at the same time. The kids were super cute, and their differences (most notably along socio-economic lines) were stark. At the same time, it was a little boring to watch the whole thing.

Yesterday I watched 21-Up (they skipped 14 apparently) and that was a whole lot of fun. It was amazing to see how the 7-year-olds had turned out 14 years later. And 21 wasn't so long ago that I don't remember what it's like! :)

The wonderful thing is to be able to see myself in many of the kids chronicled; and to try to remember back to when I was seven and fourteen and twenty-one and what my views were on life, politics, society, sex, class, opportunities, marriage, family, ... (the list is long).

I'm really excited to see the rest of the DVDs in the series. It goes all the way up to 49 Up, which was released in 2005.

Highly recommended viewing.

Sunday, January 21, 2007

playing with ruby

It's been a while since I played with ruby.

I have a Subversion repository that contains stupid stuff like my .emacs file, and then I have some personal wiki's and blogs that use files or mysql dbs under the covers.

I haven't been very diligent about setting up a backup process for all that crap, so I've been playing a bit with some scripts to automate all of that stuff using Ruby. My ruby skills are quite rudimentary and based entirely on some playing around I did with rails two years ago. But it's been exciting (and tedious) learning about stuff.

First off, the AWS S3 ruby libraries look cool, but don't work unless you have a ruby version > 1.8.4. I had 1.8.3 and it took me forever to find the root cause of an obscure error.

I also never knew about ri - the perldoc for ruby. Check out RI for emacs which lets you run ri from within emacs.

Also loading inf-ruby.el allows you to do M-x run-ruby and get an interactive ruby shell within emacs. This is great for a ruby beginner like me, because I can experiment with stuff from within emacs while I'm coding.

The S3 Rake file is a great starting point for backing up mysql databases and svn repositories, but is specific to a rails setup. I'm not working on a rails app; just trying to backup wiki databases and an arbitrary svn repository; so I'm rewriting it as a class that should be callable either as a command (from cron, which is what I want), or from rake. If I get it looking decent, I'll put it up somewhere.