Why ATM’s are totally awesome machines

ATMs are awesome.  Not only do they make money out of thin air, but they can make thin air out of a plastic card, at the most opportune moment.

Let’s say, hypothetically, that when I arrived in Bangkok Airport last night, that I decided to get some cash from an ATM.  And, in this hypothetical story, I was so exhausted from 20 hours on planes that I wasn’t really paying attention, and got distracted by the fact that it gave me really large bills.  And so, hypothetically, I forgot to grab my card.

Which, in this hypothetical story, I realized in a panic 5 minutes later, an escalator and a security barrier away.

So, when I left my bag with Katelyn, and hopped a security fence, I wasn’t overly optimistic that my card would still be there.  And sure enough, it wasn’t, and that hypothetically really sucked.  And I was hypothetically really bummed, having my card stolen after being in the country less than an hour.

Figuring I had nothing to lose, I told the guy at the adjoining money changing booth what had happened, and he told me to wait 5 minutes, that someone would come.  When he got there, he had a key and a book.

I hypothetically tried to explain that the machine didn’t eat my card, but that hypothetically someone had stolen it because I had forgotten it.  He smiled, ignored me, and opened up the machine with his key.

This is the part in which I tell you about why ATM’s are awesome.  Apparently, if you don’t remove your card from the slot after getting your cash, they eat your card.  And they stick it in a little bin of eaten cards.  Which, hypothetically, if you have a key that opens a machine, you can get cards out of.

Whoever designed this feature is awesome.  And the guy with the key must have the best job ever - he just walks around all day with a key and performs magic tricks that save people’s trips. How awesome is that?

A couple initial photos are up on Picasa.

Behind the scenes developing a Google App Engine demo

Finally, I can talk about one of the cooler things to come out of Google in a while: Google App Engine. App Engine is an application hosting service at Google, where you can write apps in python using a very simple but powerful framework, and run them on Google’s scalable infrastructure.My hipster PDA

I got the chance to develop a demo application which was included in the initial launch, called ToDone. ToDone is a simple todo list application modeled after the hipster PDA I’ve used for the past couple years to manage my GTD lists. The two things I really like about my hipster PDA are that it’s super simple(it doesn’t have unneeded features like priorities or due dates or colors), and that I can view as many lists as I want at a time by spreading my cards out on the table. I wanted to capture these qualities in ToDone.

Implementing ToDone using the App Engine APIs turned out to be really fun. First and foremost, I love development environments that have a short iteration cycle. App Engine’s cycle is as simple as reloading the browser - the development server that runs on your local machine picks up changes to your python instantly. A huge change from my normal development environment, which often involves multi-minute compiles and restarts (don’t ask).

Additionally, the datastore api is a dead simple object relational mapper, which you query using GQL (a restricted version of SQL), getting back objects with properties that are defined in your python code. I only had two objects for ToDone - TaskLists and Tasks, so setting up the persistence layer took maybe a grand total of an hour, including reading the documentation and understanding how it all fit together. The development server even automatically figured out what indexes needed to be created to optimize my queries.

The rest of the framework was pretty standard - I used wsgiref handlers for dispatching and django templates for presentation, which, while apparently standard in the Python community, were new to me. I found both pretty similar to other comparable technologies, and generally pleasant to use.

I think the best part of the whole experience was pushing my code into production. Pushing my code out is really as simple as:

appcfg.py update todone/

That’s it. That single command bundles up all my code, pushes it into production, and updates the database schema and indexes, all in a matter of seconds. Nothing more. So much better than uploading code to servers by hand, massaging database schemas, migrating data, and trying not to break anything.

There’s still some areas that are rough around the edges. For instance, there’s currently no way to run cron jobs. While I believe this is on the todo list for the team, the current recommendation is to run a cron job on your own machine which hits a private url to kick off whatever work needs to be done for your app.

Be sure to check out the other demo applications that other Googlers wrote in the Application Gallery. There’s some far more awesome applications than ToDone in there.

Apartment hunting, aka fun with Yahoo Pipes and Google Maps

So, I’m looking for a new place to live. My current place is ok, other than the fact that I have to wear earplugs in order not to be woken up by the guy upstairs talking on the phone or walking around, due to extremely thin floors.

The process of looking for a new place usually means lots of saved searches on craigslist with are imported as rss feeds into google reader. However, this time around, I thought I’d get fancy, and see what I could with Yahoo Pipes and Google Maps. Here’s the fruit of my labors: Scotty’s Custom Apartment Search
.

It involves a couple pipes:

The last of these uses the new Fetch Page module in Pipes to fetch maps.google.com driving directions, extracting the driving distance. Thus, it’s not actually an “as the crow flies” radius - it’s something even better: it’s a driving distance radius. It would be just as easy to do driving time as well, which would be interesting.

I integrated the pipe with maps using the GeoXml rss overlay api for maps.

Overall, I’m really impressed impressed with Pipes. Above all else, it’s a really fun system to use. My only frustration is that it’s a bit too simple in places. For instance, it only allows simple math, which prevented me from calculating “as the crow flies” distance between two points, due to a lack of trig functions.

Amazon launches new grid storage service - TOS says “all your content is belong to us”

I read about the new Amazon S3 grid based storage web service today. Very cool stuff. The general gist is that they give you access to store and serve files from a large computing grid, at pennies on the dollar ($0.15/gig storage per month and $0.20/gig transfer). In a small players world, those are rock bottom prices. I suspect when you start dealing in serious bandwidth, the numbers don’t look quite as good, but hopefully, at that point, you’re making enough cash to have other options.

As someone who’s in the process of starting a web based startup, service like this look particularly attractive. What would be even more attractive here would be to have a web service that looked much more like an RDMS. Granted, Amazon claims they’ll allow you to store really small files (as small as 1 byte), I question how you could index that in an efficient manner, particularly if your data is typically quite small and piecemeal.

Another, much more sinister thing to consider, is the terms of service. Accoring to the terms of service:

You may provide text, images, reviews and other informational content (”Content” about a product to Amazon. If you do so, you hereby grant to Amazon a perpetual, paid-up royalty-free, nonexclusive, worldwide, irrevocable right and license to: (i) use, reproduce, perform, display and distribute the Content in any manner; (ii) adapt, modify, re-format and create derivative works of the Content for any purpose;(iii) use and publish your name in the form of a credit in conjunction with the Content; and (iv) sublicense the foregoing rights to its affiliates or any third parties.

That’s pretty darn evil, IMO. What business would agree to those terms? I wonder if perhaps this is a blanket policy for all Amazon services, and thus got tacked on to S3. However, the way I read it, it still applies. Definitely a deal breaker, if you ask me.

Causing a page reload on the back button in IE

So, I’ve spent the better part of today trying to figure out how to get IE to always reload a particular page, even if the user gets there via the back button. There is some discrepancy between various browser vendors over seemingly conflicting portions of the HTTP 1.1 spec, namely 13.13:

History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.

and 14.9.2 about the no-store:

If sent in a response, a cache MUST NOT store any part of either this response or the request that elicited it. This directive applies to both non-shared and shared caches.

(the above pulled from the very helpful posting by Chris Shiflett ).

The requisite magic is apparently the following apace config:

Header set Cache-Control no-store
KeepAlive On
KeepAliveTimeout 15

I have NO idea why you have to have keepalive turned on for this to work. But you do. Man, developing for IE is a pain.

On down time and web services

Note to self: When running a web service that people depend on as part of their daily lives, being down for 8 hours at a stretch is not acceptable. Even if it’s free. And if you do have a catastrophe, let your customers know as much information as possible, as quickly as possible.

Currently being displayed on del.icio.us:

del.icio.us is down for emergency maintenance. we’ll be back as soon possible.

JSDBI 0.01-beta

I’m finally finished packaging up JSDBI for public consumption. It’s not too fancy yet, but the basic functionality is there. Download the code here

JSDBI provides an easy to setup CRUD interface for REST web services. With a few lines of javascript, you can build a class which provides full fledged accessor code, very similar to Class::DBI. Only this is on the browser, in javascript.

Here’s how it looks from an end user perspective:

// Basic class setup
Music.Artist = Class.create();
Music.Artist.extend(JSDBI);
Music.Artist.prototype = (new JSDBI()).extend( {
initialize: function () {
},
});

Music.Artist.fields(['artistid', 'name']);
Music.Artist.url('http://someserver/rest/artist');
Music.Artist.elementTag('artist'); //optional

// In the calling code

var artist = Music.Artist.insert({name: 'Billy'});
var artistid = artist.id();

artist = Music.Artist.retrieve(artistid);
document.write("name: "+artist.name());

artist.name('Fred');
artist.update();

artist.destroy();

Feel free to download it, beat it up, tell me what’s missing, whatever.

Catalyst::Helper::Controller::Scaffold::REST

So, my automatic REST interface generator for Catalyst is ready to go. It’s pretty spiffy. You just run:

script/myapp_create.pl controller REST::SomeTable Scaffold::Compiled CDBI::SomeTable

and Bang! you have a REST interface for your model CDBI::SomeTable. Give it a shot. Download here. Feedback is more than welcome.

JSDBI is on the way shortly (hopefully tonight), which dovetails with this module nicely.

Revelations of the evening

I spent most of this evening banging my head against the wall, shaving one yak after another, trying to make headway on JSDBI. A full fledged yak shaving expedition.

How to get Venkman to run on Firefox on Gentoo

First off, I spent a fair amount of time trying to get Venkman, the javascript debugger for Firefox, to work on my Gentoo box. I kept getting the error:

An exception occurred while initializing, please file a bug.
BadMojo 4: JS Debugger Service is not installed. @
line 122 (initDebugger)

Turns out I needed to recompile Firefox with the mozdevelop flag set, which sets –enable-jsd in the configure for firefox. If only the error message was more helpful. There’s a growing thread on bug 288777 about it.

How Javascript Object.prototype works

Javascript only barely supports inhertance, by way of the Object.prototype property. If an object gets a method called on it that it doesn’t have, it looks at it’s own prototype. If it doesn’t find it there, then it looks at the prototype’s prototype, and so on recursively, until it either bottoms out, or finds a method to satisfy it. There’s a really good writeup on javascript inheritance by Kevin Lindsey.

How to use prototype.js to get both object method inheritance and class method inheritance

Do the following:

ChildClass = Class.create();
ChildClass.extend(ParentClass);
ChildClass.prototype = (new ParentClass()).extend( {
initialize: function (){
}
});

Then both methods and properties in the prototype of ParentClass get carried over, as well as things like ParentClass.myStaticMethod.

Some sample code for JSDBI

I’ve decided to temporarily name this Class::DBI meets ajax idea JSDBI, for lack of a better name (subject to change when I find something better). I’ve also sat down and translated the synposis example for Class::DBI into an equivalent JSDBI version. Code is after the jump.

Also, crw pointed me at json and json-rpc. These seem to be in the same ballpark, but json is just a data format (like XML), albeit, an easier format to parse than XML, and json-rpc looks purely procedural, rather than object based like Class::DBI, so it looks like there’s still room for improvement in this area. However, both could possibly be implemented as the transport portion of this overall solution, instead of using xml/rest.


// ***** Setup ******
var Music.DBI = Class.create();
Music.DBI.prototype = (new JSDBI()).extend( {
});

var Music.Artist = Class.create();
Music.Artist.prototype = (new Music.DBI()).extend( {
});// basic class setup
Music.Artist.table(’artist’);
Music.Artist.columns([’artistid’, ‘name’]);
Music.Artist.has_many(’cds’, ‘Music::CD’});

var Music.CD = Class.create();
Music.CD.prototype = (new Music.DBI()).extend( {
});

// basic class setup
Music.CD.table(’cd’);
Music.CD.columns([’cdid’, ‘artist’, ‘title’]);

// relationships ?
Music.CD.has_many(’tracks’, ‘Music::Track’});
Music.CD.has_a(’artist’, ‘Music::Artist’});

var Music.Track = Class.create();
Music.Track.prototype = (new Music.DBI()).extend( {
});
// basic class setup
Music.Track.table(’track’);
Music.Track.columns([’trackid’, ‘cd’, ‘position’, ‘title’]);

// ***** Usage ******

// create
var artist = Music.Artist.insert({artistid: 1, name: ‘U2′});
var cd = artist.add_to_cds({cdid: 1, title: ‘October’, year: 1980});

// update
cd.year(1981);
cd.update();

for (var i=0; i
var track = (cd.tracks)[i];
document.write(track.position+’ ‘+track.title);
}

cd = Music::CD.retrieve(1);

cd.delete();