Stowaway!

The Duck

You see, there’s this duck.

It’s a little stuffed Aflac duck. When you squeeze it, it says “Aflac. Aflac. AFLAAAAAAAC!”

Back when Benji and I were roommates, we used to find creative ways to pass it back and forth. For example, one time Benji came back from class to see The Duck sitting on his laptop’s keyboard, looking at duck porn. Another time I found that The Duck had hung himself in my closet, complete with suicide note. (Which eventually led to the infamous Naked Yogurt Time incident, but that’s another story.)

But that was all two years ago, during my final year at Purdue, finishing my Masters’ degree. These days, several hundred miles of separation kind of makes it harder to do that sort of thing.

Anyway, upon returning from a recent business trip, I found that my checked bag had won the TSA lottery. Aside from having the mandatory “yeah, we looked in your bag, deal with it” note (I’m loosely paraphrasing here), everything seemed pretty much how I left it. However, after unloading the clothes, I noticed that the garment bag that I normally leave unused in the bottom look a bit higher than normal. I lifted it up to reposition it, and underneath I discovered…

The Duck.

I can only assume that when I visited Purdue last month, someone snuck The Duck down there when I wasn’t looking. I didn’t notice anything when unpacking from that trip, since the way the bag is shaped, there is a little space beneath where the garment bag goes. Which means The Duck spent several weeks in my luggage, in my closet, with me none the wiser, and if not for TSA it’d still be there.

I can only imagine what the TSA guy rummaging through my bag must have thought when he found The Duck in an otherwise painfully dull bag. (Clothes, shoes, more clothes, toiletries, and wait, something’s hidden down here, aha, it’s… a stuffed duck?!)

Actually, The Duck does have a funny story about that, but I’ll let The Duck tell it for himself.

[And since I couldn’t resist the pun in the filename, you can also listen to The Duck with lossless audio compression, fully capturing the richness of sound provided by the cheap little microphone that came with holly.]

Now The Duck is out of my luggage, and perched atop my backup hard drive. I told him he’s welcome to stay as long as he likes, as long as he stays away from those two pidgeons that hang out on my balcony. They’d be a bad influence on him. I mean, you can’t make a mountain out of a molehill, but you can make a mountain out of the mounds of pidgeon droppings they’ve been leaving. Seriously, it’s three-dimensional, and I can’t have The Duck pulling that sort of thing indoors.

Music Applet 2.3.1 released

A new release of Music Applet, version 2.3.1, is now available. This is primary a brown-paper-bag release, fixing the crasher that, in hindsight, probably affected everyone trying to use 2.3.0. If you were one of them, try upgrading to 2.3.1 and see if that fixes things for you.

For those interested, I’ve done a write-up of what was causing the bug and why it took me so long to figure it out.

There’s also a few other bug fixes, as well as a bunch of new translations for Czech (cs), German (de), Spanish (es), French (fr_FR), and Russian (ru).

Brown paper bag

For those of you who ran into the bug in Music Applet 2.3.0 where the applet would seem to crash as soon as you started it, well, I finally figured out what was going on. It turns out to be a blatant brown-paper-bag bug, and to proper chastise myself for releasing Music Applet with it, I will now detail what its cause was and how I discovered it.

Since I have Debian’s music-applet package installed, during development I install the new code in a separate directory and run it from there. This leaves the problem of actually loading the applet from its nonstandard location. Normally, when you add an applet to a panel, Bonobo checks its database to see what program needs to be run. However, if the program is already running, it will connect to it instead of starting a new instance. So, when testing new code, I start the new applet code from the command line, and then add it to the panel.

This way, I don’t have to touch the system files to run the new code. This method also gives me an opportunity to augment the Python path with the directory where the new code’s modules are, since naturally they’re in a nonstandard location too. It furthermore has the advantage of printing the output on stdout and stderr to the console, whereas if Bonobo started the applet, they’d wind up in /dev/null, which is bad for debugging.

Now, several people reported the crash-on-startup-if-Amarok-support-is-enabled bug, but I was completely unable to reproduce it on my system. None of them had a stacktrace or core file or any other debugging output to offer. However, they were all using Ubuntu and Python 2.5, whereas Debian still uses Python 2.4 by default. It looked like the trouble might lie there.

After jumping through hoops to get the applet running on my system under Python 2.5 (complicated by the fact that Debian for some reason doesn’t have versions of the DCOP modules for Python 2.5), I still wasn’t able to reproduce the problem. Naturally, if I can’t reproduce the problem, and I can’t get any good details from the bug reports, I can’t figure out what’s causing the bug, let alone verify that any fix I come up with works.

I finally decided to go all-out and try to reproduce the exact circumstances of the crash on my machine, without completely wrecking the copy of the applet provided by Debian. I hacked the Bonobo .server file for the applet to point to the local copy of the applet, and then hacked the applet startup code to explicitly run under Python 2.5. Oddly, when the applet started, it would identify its version of 2.2.1 (the version provided in Debian) and not 2.3.0.bzr (the version installed locally), nor would it have any of the features added in 2.3.0, including the Amarok plugin.

After banging my head on this for a while, I realized that even though Bonobo was running the local copy of the applet’s startup code, that startup code was then loading the support modules installed in the system paths — the 2.2.1 code — instead of the local code. When starting the applet from Bonobo, there’s no opportunity to tweak the include path like you get from the command line. I then further hacked the applet to add the right paths to sys.path, and finally it started working, in that it stopped working and crashed like it was supposed to. Or, not supposed to, but you know what I mean.

Finally, I was getting somewhere. To track down the line causing the crash, I started putting lines like this in the code to trace the control flow:

os.system("xmessage 'About to start thread'")

This would pop up a crude dialog box with the message, which I relied on instead of printing to stdout or stderr since, well, those were going to /dev/null now. After playing around with things for a while, I tracked down the offending line of code:

self.__plugin._app = kdecore.KApplication (sys.argv, "music-applet")

Thinking it might be throwing an exception for some reason, I tried wrapping it in a try/except block, but no luck. That was definitely the line, but still no clue why it was failing so spectacularly. Thinking there might be something on stdout or stderr that could help, I realized I could point them at files on applet startup so I could read them after the fact:

sys.stdout = open ("/home/paul/music-applet/debug.stdout")
sys.stderr = open ("/home/paul/music-applet/debug.stderr")

Now I was seeing the normal debugging spew from the applet, but still no messages about the crash. It then hit me that this was only going to affect my Python code; everything else would still be using the “true” stdout and stderr. I’d have to literally dupe the system into redirecting the underlying file descriptors into writing into my debug files:

new_stdout = open ("/home/paul/music-applet/debug.stdout", "w")
new_stderr = open ("/home/paul/music-applet/debug.stderr", "w")
 
os.dup2(new_stdout.fileno(), sys.stdout.fileno())
os.dup2(new_stderr.fileno(), sys.stderr.fileno())

Aha! Now this showed up in the output right before the crash:

music-applet: Unknown option '--oaf-activate-iid=OAFIID:GNOME_Music_Applet_Factory'.
music-applet: Use --help to get a list of available command line options.

That option is one of the things that Bonobo puts on the command line when it starts an applet, and isn’t one of the things I was giving to the applet when launching it manually. Aha? Checking the source code of the KDE libraries for that error message turned up this:

void
KCmdLineArgs::usage(const QString &error)
{
    assert(KGlobal::_locale);
    QCString localError = error.local8Bit();
    if (localError[error.length()-1] == '\n')
  localError = localError.left(error.length()-1);
    fprintf(stderr, "%s: %s\n", argv[0], localError.data());
 
    QString tmp = i18n("Use --help to get a list of available command line options.");
    localError = tmp.local8Bit();
    fprintf(stderr, "%s: %s\n", argv[0], localError.data());
    exit(254);
}

Aha! The KApplication constructor indirectly calls this when it sees something on the command line it doesn’t understand. It prints a message to stderr, and them immediately exits the program! The applet wasn’t crashing; the KDE libraries were terminating it because they didn’t understand the command-line arguments Bonobo uses!

Here’s where that brown paper bag comes in: this bug would affect anyone relying on Bonobo to start the applet. In other words, everyone who isn’t me. By always starting the applet from the command line first, I never tested the applet in the same runtime configuration that everyone else on the planet would be using, and so never encountered a bug that everyone else would suffer. The whole Python version thing was a red herring.

Now that I finally knew what was happening, the fix was trivial: strip out any command-line arguments before calling the KApplication constructor:

fake_argv = sys.argv[0:1]
self.__plugin._app = kdecore.KApplication (fake_argv, "music-applet")

However, I still maintain that if there is a hell, there is a special place in it reserved for people who write libraries that call exit(), and thus do not give the user of the library an opportunity to try to recover from an error.

Needless to say, this bug is fixed in 2.3.1.

Na na na na na na na na na na na na na na

The old 1960s Batman movie would, by any objective measure, be awful, if not for how awesome it is in its sheer, unmitigated ridiculousness.

Properly documenting all the examples of why this is so would end up reproducing the plot in full, so I’ll focus on a few highlights. In the first action sequence, Batman fights off a shark biting his leg while holding on to the Bat-Ladder hanging from the Bat-Copter. (Spoiler alert: Batman ultimately fends it off with Bat-Shark-Repellant, which is stored on the Bat-Copter alongside repellant sprays for other marine life.) What makes the scene great is how not only is the shark obviously made of rubber, but as Batman punches it, it makes exactly the sound you’d expect from someone punching a rubber shark.

Also, when the shark is ultimately dislodged, it falls into the sea and explodes. In case you’re wondering why the United Underworld (i.e., The Joker + The Penguin + The Riddler + Catwoman; see also: greatest team-up ever) didn’t rig the shark to explode when it bit Batman’s leg, well, obviously then the movie would only be a few minues long.

If that doesn’t convince you of my thesis, then consider the fight scene in the Bat-Cave that, in my opinion, reveals the truth behind Batman’s superpowers. To set this up, the villans have obtained an instant dehydration gun that reduces anybody to a pile of powder. The Penguin does this to five henchmen and scoops the powder into separate vials. He then disguises himself as the person the villans stole said dehydration gun from, and introduces himself to Batman and Robin.

The Dynamic Duo immediately see through his ploy — the nose and talking like Jon Stewart impersonating Dick Cheney are dead giveaways — yet for some reason see the need to scientifically prove The Penguin’s identity to The Penguin, so they take him to the Bat-Cave, which apparently has the only retinal scanner on the planet. Once there, The Penguin goes over to the Drinking Water Dispenser — like everything in the Bat-Cave, it is prominently labeled with its function — and hooks the vials up to it, thus rehydrating his henchmen.

However, while doing so, The Penguin accidentally moves the Drinking Water Dispenser’s control lever — let me remind you, this is a machine expressly for dispensing drinking water — from the “light water” setting to the “heavy water” setting. Yes, heavy water, which Batman later points out is also used in the Bat-Cave’s nuclear reactor. Obviously, this error results in the henchmen vanishing into nothingness as soon as anything hits them (something to do with antimatter, I think).

There is only one possible explanation for why anyone would ever connect a source of heavy water to what is, let’s face it, an overgrown drinking fountain. (Wow, all technology really was bigger back then.)

Batman drinks heavy water.

No wonder Batman can breathe in space.

And there’s loads more where that came from. The Joker and The Penguin wear masks across their eyes while pulling off various heists, apparently oblivious to the fact that they’re still dressed as The Joker and The Penguin. The Pentagon sells a fully armed surplus submarine to someone named P. N. Guin, and the admiral Batman talks to is oblivious to how selling something like that to someone who won’t even leave his address is not a good idea. The Riddler accidentally shoots down the Bat-Copter with a Polaris missile, but no one is hurt as the copter crash-lands on a pile of foam rubber. And, as Batman so eloquently observes, “some days you just can’t get rid of a bomb!”

If I somehow still haven’t convinced you as to how awesome this movie is, how about this: Jet Pack Umbrellas.

But if strangely creepy is more your thing, try this on for size. The villans scheme to lure Batman into a fiendish trap (spoiler alert: it involves a jack-in-the-box and an exploding octopus) by kidnapping Bruce Wayne and holding him hostage. They lure him into a trap by dropping a riddle suggesting that “Kitka” (i.e., Catwoman not dressed like Catwoman) is going to be kidnapped, which leads Bruce into asking her out. Suspecting the villans will move against “Kitka” during the date, Bruce has Robin and Alfred-wearing-a-mask shadow them inconspicuously in the Batmobile and watch what’s going on on a monitor, presumably hooked up to an otherwise unmentioned Gotham-wide Bat-survillance-camera-network. (Holy 1984, Batman!)

The date ultimately leads back to Catwoman’s apartment, and it’s not hard to decode 1960s euphemisms for what Bruce is expecting to go on there. He shows no compunction, despite knowing Robin and Alfred are supposed to be watching all of this. That is, outside, in the car, in the dark, his young ward and his old manservant, one of whom is wearing tights and the other is also disguised, are supposed to be watching him “further international relations” with “Kitka”.

Fortunately, the disturbing potential of that setup is stopped by the intervention of, yes, Jet Pack Umbrellas.

In conclusion, I want a Jet Pack Umbrella, in case I ever need to escape from exploding marine life.

Back in black

Last weekend I returned to Purdue for the big annual Ship of Fools / Andy Ober Orchestra show that Saturday.

Getting in to West Lafayette Saturday morning was mostly uneventful. The only thing worth noting is that apparently Indiana has diverted funds from road maintenance to violating the establishment clause on their license plates. Seriously, Indiana, World War I-era France called; they want their crater-pocked wastelands back.

Anyway, Ryan and Tripod graciously let me crash at their apartment as they did last time I had been town over a year prior. As it turned out, it was the very same apartment, a fact I somehow failed to realize until Ryan pointed out where I should park my rental car.

After unloading my bags, Ryan and Tripod set about seeing how many other Fools they could round up for lunch, during which I discovered that Tripod had become Ryan’s wacky sidekick, the Pinky to Ryan’s Brain. The efforts proved largely in vain, but we did manage to pick up Beard for lunch at the local Cracker Barrel.

After lunch, Ryan, Tripod, and I returned to their apartment and played video games for several hours with other roommate Alex and some other people. First up was Brawl, which plays a lot like Melee, especially if you’re using a Gamecube controller. Fun fact: with the exceptions of PK Flash and his physical weapons, none of Ness’s abilities are ones he actually has in EarthBound. Also, why Nintendo made Lucas a playable character when they clearly have no intention of releasing Mother 3 here, I have no idea. But at least Mr. Game & Watch’s Final Smash transformation into a giant octopus only had a characteristic two frames of animation, or things could’ve gotten ugly.

The apartment also had a MAME cabinet in the kitchen, so we started playing random games until starting a two-player game of Tetris, in which I utterly demolished all challengers. The key to victory is having grown up on an old DOS Tetris game that only had one rotate button, so I was unfazed by the arcade version’s inability to rotate in both directions. (Also, back in those days, I’d disable the piece preview, since the game would award more points for that. That’s hardcore.)

Having played video games for several hours, it was time to head on over to Matthews Hall and set up for the show. Apparently, some time after I graduated, the university decided to replace the audio controls for the room with some kind of telepathic interface, not realizing that telepathy is bunk. Or at least, that’s the only explanation I can come up with for the utter lack of any apparent non-fictional audio controls anywhere. Or maybe they took them out to make room for yet another redundant set of light switches.

Eventually it was time for the show to get under way. The Fools’ set went quite well, though the audience was kind of reluctant to volunteer to come up on stage. I ended up getting volunteered to be the audience participant in Chain Murder Mystery when nobody else did, which was fine by me. I mean, the only reason I didn’t volunteer in the first place was so as not to be an obvious ringer, but you’ve got to do what you’ve got to do. Whenever a YouTube-able form of the video becomes available, you’ll be the, let’s say, sixth to know. (Keep in mind how long I waited before putting this up, after all.)

The AOO’s subsequent performance was as good as I anticipated. The audience did continue to seem a bit lethargic, though. I wonder how much overlap these shows have in terms of audience from one year to the next, and if that has something to do with it. I’m not saying that All Of Their Music Sounds The Same, but I did notice that their new songs got a bigger reaction than anything else. (Also, I’m not sayin’ that Scorpion is the new bin Laden, I’m just sayin’.)

Also, for the record, I’m not bitter that AOO broke my old-as-dirt MP3 player, in that I tried to bootleg the performance with its record function, and at some point it locked up hard until the battery ran out, and won’t even recharge any more, let alone turn on. I was kind of looking for a new one anyway, and now I guess I’m all the more motivated to get on with it.

But I’ve still got to give it up to Andy Ober, without whose music I would never had been able to remember that π is about 3.141592653589793238462643383279502884197169399375105820974944. (Getting all the way to the Feynman point is a bit trickier.)

After the show, we formed a throng of people and crammed ourselves into Kyle’s apartment for the afterparty. Therein I learned two critical facts. First, Jamie, possibly the Fools’ biggest fan, is my willing lackey, the The Cheat to my Strong Bad. For those of you without lackeys, they are useful for tasks such as lending you their iPhone for deleting blog spam and explaining complex mathematics in terms of pie. However, they are not so good for remembering to tell you their blog’s new URL, hint hint.

Second, the powers that be have seriously dumbed down Uno by removing any traces of English from the cards, leaving even seasoned Uno players baffled as they try to interpret mysterious glyphs such as how “circle with a slash through it” is supposed to mean “skip”. It’s not as though Uno ever required deep linguistic skill, but is basic literacy really too high a bar to set? What next?

Finally, the Fools’ set at Relay for Life came, despite being delayed from 2 am to 3 am. This time I performed with them as a proper Fool, with adequate results despite not having done any improv since graduation. The show went ok considering the venue (which at least this time was indoors, so shivering was kept to a minimum), and the lack of good acoustics didn’t help much either. But the show is something of a tradition, and besides, it’s not like any of us like cancer. (And don’t think you’re getting off easy, capricorn; once we beat cancer, you’re next.)

By the time it was all over and we got back to Ryan’s and Tripod’s apartment, it was already approaching 4:30 am. Sleep == good.

In the, um, “morning”, John introduced me to Portal, a game which I would be all over right now if not for not having a platform to run it on. I managed to get up through the first (?) level where you face the adorable little gun turrets. In retrospect, my strategy of opening portals above them from which to drop weighted storage cubes was not necessarily the most efficient way to knock them over, but it was the most fun. I learned that dropping corncob pipes on them is not nearly as effective. Also, the little buggers are bulletproof. So much for my brilliant plan to position one between myself and another turret. The force of the gunfire didn’t even knock it over, since it was too close to a window (also bulletproof), keeping it propped up. Sigh.

Early in the afternoon a bunch of us headed en masse across town to the IHOP for lunch, whereat the service took entirely too long, especially given how the area we were seated in empied out shortly after we arrived. In hindsight, having driven over myself would’ve been a much better idea, since the highway was right there but I need to go back to the apartment afterwards to get the car, and time was getting to be a factor. Nevertheless, I did make it to the airport with a little time to spare, despite fate conspiring against me in the end (No paper in the receipt printer at the gas pump! Seeing the shuttle from the car rental to the airport pull away as I parked! Long security line!)

It’s a shame finances and geography prevent me from making the trip out there to see everyone again more frequently, but what little time I did have out there was great. It’s also wonderful to see the Fools still going strong long after all the first-generation members have left.

Huzzah!