Wherever you go, there you are.

Rotation Tribulation


I love spending hours tracking down obscure API issues that turn my carefully crafted code into a crap machine. It's always exciting, and in the end I feel a healthy sense of accomplishment for having exhausted hours of intense study in order to make something work. The way it was supposed to work in the first place. If you can't guess already, I just had another one of those wonderful sessions with PIL -- the Python Imaging Library.

Now, in it's defence, this is pretty much the first issue I've run into with PIL. Both functionally and documentation-wise, it has been exceptional all around. So I can't really complain TOO much. That won't stop me from complaining just a little, though.

All I wanted to do was rotate an image. And while PIL happily obliged with a handy "rotate" function all rearing to go, the result was... well, it was crap. It looked like something you might expect from a CS student who had just learnt matrices and was busy rotating pixels gleefully, completely oblivious to the swath of destructive artifacting in their wake.

Here are the important bits of the rotate API documentation in the PIL handbook:

im.rotate(angle, filter=NEAREST, expand=0) => image

Returns a copy of an image rotated the given number of degrees counter clockwise around its centre.

The filter argument can be one of NEAREST (use nearest neighbour), BILINEAR (linear interpolation in a 2x2 environment), or BICUBIC (cubic spline interpolation in a 4x4 environment). If omitted, or if the image has mode "1" or "P", it is set to NEAREST.

The expand argument, if true, indicates that the output image should be made large enough to hold the rotated image. If omitted or false, the output image has the same size as the input image.

Here's the tricky part it doesn't mention: if you actually use the expand option, it will completely ignore any filter you provide, and simply use the NEAREST method. Which might as well be named UGLY, because that's what you get. Oh, and nevermind the fact that the actual argument isn't even filter at all, but resample (and yes, that matters when trying to pass a named argument in Python).

The fix? Trivial, once you've spent a few hours wondering why none of the filters make any difference and poked your way through the code to find out it's happily ignoring your settings entirely (no... I'm not bitter... why do you ask?). Simply pretend the "expand" option doesn't exist, and instead manually expand the image size prior to rotating so that it can hold the rotated image. A little bit of trig and you're good as rain. Then you can happily rotate away with expand turned off, using the BICUBIC filter, which looks oh so pretty.

Running Max Media Manager With nginx


So I've been mucking around with a variety of webservers due to a number of performance concerns with Apache. I first landed on lighttpd, but it had some ambiguous 404 handling that confused Google. From there I decided to try out nginx, which seems to be a popular webserver among, um... Russian spam and porn sites. That does seem a little sketchy at first, but its hard to imagine a site with higher traffic loads than a Russian porn site. For that matter, its hard to imagine a webmaster with less tolerance for crappy software than the kind of Russian mafia lord that might be running said site. So, really, this all seems to be a good sign for nginx!

While getting Drupal to run in a FastCGI environment is well documented, I also need to be able to run my Openads server (AKA Max Media Manager), a setup which proved to be a little trickier. Ultimately, it boiled down to figuring out and providing all of the necessary headers that MMM uses to setup its web environment. It makes a number of unusual decisions based on obscure things like, for example, the SERVER_PORT being set -- if it's not, you won't get a default http:// protocol. So here's my sample nginx server config which, at the moment, seems to work great with MMM running as a standalone FastCGI process.

server {
    listen       80;
    server_name  ads.example.com;
    access_log   logs/adserver-access.log  combined;
    location / {
        root  /root/to/adserver/www;
        index index.php;

    location ~ .php$ {
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  /root/to/adserver/www$fastcgi_script_name;
        fastcgi_param  DOCUMENT_ROOT    /root/to/adserver/www;
        fastcgi_param  PHP_SELF         $fastcgi_script_name;
        fastcgi_param  REQUEST_URI      $request_uri;
        fastcgi_param  QUERY_STRING     $query_string;
        fastcgi_param  REQUEST_METHOD   $request_method;
        fastcgi_param  CONTENT_TYPE     $content_type;
        fastcgi_param  CONTENT_LENGTH   $content_length;
        fastcgi_param  SERVER_NAME      ads.example.com;
        fastcgi_param  HTTP_HOST        ads.example.com;
        fastcgi_param  SERVER_PORT      80;
        fastcgi_param  REMOTE_ADDR      $remote_addr;

How Not to Upgrade


I love doing stupid things. No, really, I mean that with all my heart. Every time I do something stupid and manage to recover from it without too much pain, I feel as if some part of my mandatory universal stupidity quota has just been filled. My normal sense of complacency is repealed, I pay better attention to all the buttons I normally push without thinking, and I become hyper-vigilant to avoid doing anything glaringly dumb. For a while.

The latest stupid thing I did happened while upgrading to Ubuntu Feisty. Actually, I upgraded several hosts without a hitch, so really, power to the people at Ubuntu for making such clean upgrade paths (and, I suppose, to the Debian folks for the underlying package manager on which it all depends). Unfortunately, when I pulled the big handle on my primary server and X11 platform, I wasn't paying enough attention. The upgrade rolled around just fine, updating old packages and removing obsolete ones, while I blindly agreed to every prompt that popped up.

The time to restart comes along and... oh, what's this? What do you mean you can't find a kernel?

It's not fair to say that it couldn't find the kernel, exactly. The kernel loaded just fine. Unfortunately the kernel is a Xen Hypervisor, which points to another kernel to use for the Dom0 machine instance which runs my actual server. And that kernel was nowhere to be found. After a bit of digging it became painfully obvious that one of the obsolete packages I had blindly thrown out was, in fact, my precompiled Xen generic x86 kernel.


Thankfully I have lots of other internet connected machines at my disposal, and it was a quick matter to grab an Ubuntu Live-CD and boot into a root shell on my server from there. Another few minutes of fiddling and I had apt-get'ted myself the latest Xen generic x86 kernel package. One last smidgen of editing in the GRUB list, and all was well once again.

So other than my heart skipping a beat or ten, this was happily a very painless act of stupidity. At my current quota-filling rate, I expect I'll be posting something eerily similar to this in, oh, another 5 months or so. I can only hope it'll be as easy to fix as this one was.



Meez is a large part of what we planned to do with Avatude. One less thing to worry about there, frees me up for the rest of our projects! :) Maybe I'll just start from that as a base and do the other Avatude parts on top of it, without worrying about custom avatars at this point. Here's my Meez:

nezroy's Meez avatar

How to Procrastinate Effectively


I am a procrastinator. There, I said it. I am willing to embrace my true nature!

Four years ago I wrote a novel in what amounts to about three weekends. Three years ago I finished several major edits of that novel in what amounted to a few more weekends. And then... I sat on it. For three years. Blocked, in theory, on the process of writing a ten page synopsis. The kind of school assignment you got every week or two, and were happy about because they told you to use 1" margins and double-space everything, making it that much easier.

Was I truly unable to write a ten page book report after having already written 100,000 words and plowing through three major edits? What in the world was going on?

I've read several articles recently that talk about procrastination as a manifestation of a deep-rooted fear of failure. At least for me, that's pretty accurate. Oh, sure, I can be obsessive and perfectionist at times, but that's not my real problem. Unfortunately, this fear of failure gives me not just one, but two modes of procrastination. The first is that I have a hard time getting started on anything, for fear that it's going to turn out like crap. The second is that I have a hard time finishing anything, for fear that I'll then have to reveal it to someone else and they will see that it turned out like crap.

In the middle ground, between starting and finishing, I tend to putter along quite well. Actually, I can get downright obsessive, what with the classic all-nighters and marathon sessions -- be it writing, coding, or what have you. It's just around the edges where I tend to need that extra motivation. And if I don't get it, well... I end up sitting on a finished novel for three years.

Luckily, I have found a cure -- or at least, a viable cure for me. I quit my job and started living off my dwindling savings account. This has been surprisingly effective at getting me motivated, for a couple of reasons. First, the ever-running calculation in my head of time left to live on remaining money is pretty inspirational all by itself. But just as relevant, for me, is that deep-down, a large part of me thinks that what I should be doing is going out and looking for a new job, post-haste! Get off my lazy butt and start submitting resumes!

Of course, that sounds like a lot of effort, not to mention the crushing possibility of being turned down and unable to find decent employment. Heck, stress like that, it's enough to make me want to procrastinate on it, and do pretty much anything *except* look for a job. And suddenly, writing a ten page synopsis starts to look pretty appealing by comparison. The worst outcome there is an impersonal rejection letter in six months or so. That's far easier than an in-your-face rejection at a job interview. For that matter, even starting a whole new company and working on all kinds of projects that have piled up over the years sounds more appealing than that kind of gross employment failure.

So I embrace my nature as a procrastinator. Maybe a better person could change outright, conquering their procrastination demons once and for all! Me? I'll just settle for outwitting myself -- especially since I know that's not hard to do.

The Oracle is mocking me!


Stupid uppity Oracle making me do more work... *grumble*...

I asked the I Ching Oracle: Should I fix questions with apostrophes? '
Symbol Image59. Huan - Dispersion You can succeed in dispersing even the greatest obstacle, provided you sort through chaos to find the source and clear the blockage.
What does the Oracle hold for you? http://luckyhonu.com/iching/oracle

Service Providers


Recently moved the majority of our hosting to slicehost. Xen based virtual servers; very nice stuff and quite happy with them so far.

Control Your Domain

Similarly, we moved (or are in the process of moving :) all of our DNS services over to EasyDNS. Also quite pleased with their services to date.

Torque Engine Demo


For no particular reason I took a Fraps capture of the Torque Game Engine demo application and put it on Google Video. And here it is.