repak shawahb
it's like killing and eating a real live angel



Wed, 13 Mar 2013
with regularity

It would appear that my posting frequency has settled down to right around twice every three years. Perfect. In any case, I did a little work revising the appearance of the blog, so I figured I should at least post a small note. You've probably noticed comments are gone: spam was on the rise again, and frankly I don't care enough to do something about it. Hit me up on twitter or; I'm @kwantam both places.

Life's busy again: two tapeouts loom in the near future. On top of that, I'm attending something like four weddings in the next couple months, plus at least one bachelor party and PAX East. Yowza.

Over the last three weeks I've played at being a digital designer; I'm learning my way around the Synopsys tool flow, and I have to admit it's actually kind of fun. I'll be sad when CAD inevitably forces us to switch tools and I have to relearn everything; it would be nice to be able to throw down a quick APR on my own when the need arises. In any case, I'm sure this experience driving a route soup to nuts by myself will help me understand the pain I inflict on all the real digital designers I work with in the future.

If you're left wanting more of the drivel I produce, perhaps this quick writeup, Efficiently Detecting Illegal States in Twisted-Ring FSM State Vectors, will satisfy you. I have to say, Literate Haskell is pretty great!

No mas. Bedtime. It'll be another long one tomorrow.

Mon, 14 Nov 2011
hack the planetvideo subsystem

Well shit, it's been about 18 months since my last post. Here's one that'll bore you!

In Debian Wheezy, xorg is now version 7.6 and xserver-xorg-core is version 1.11. With this update comes an increment to the xorg input ABI and the xorg video ABI.

That's great unless you're using a binary driver that hasn't been updated to work with the ABI (NVidia legacy, I'm looking at you). In my case, I've got a Quadro FX 3000 in one of my boxes, and it still needs the 173.xx driver. What to do?

My solution is a hack, plain and simple: downgrade xserver-xorg-core to 1.10 without downgrading anything else. However, you have to be a little tricky about this because otherwise apt will complain that your X install is broken. Here's what you do:

  • Grab xserver-xorg-core_1.10.4-1ubuntu5 from the Ubuntu pool (amd64, i386) (local copies: amd64, i386).
  • mkdir /tmp/xserver-xorg-core_1.11.4-really1.10
    dpkg-deb -R xserver-xorg-core_1.10.4-1ubuntu5_*.deb /tmp/xserver-xorg-core_1.11.4-really1.10
    cd /tmp/xserver-xorg-core_1.11.4-really1.10/DEBIAN/
    sed 's/Version: 2:1.10.4-1ubuntu5/Version: 2:1.11.4-really1.10/; s/Provides: xorg-input-abi-12, xorg-video-abi-10/Provides: xorg-input-abi-12, xorg-video-abi-10, xorg-input-abi-13, xorg-video-abi-11/;' control >
    mv control
    cd /tmp
    dpkg-deb --build xserver-xorg-core_1.11.4-really1.10
    dpkg -i xserver-xorg-core_1.11.4-really1.10.deb
    echo xserver-xorg-core hold | dpkg --set-selections
  • Install the legacy driver of your choice.
  • Enjoy.

Note that we've held the package at its present version. You will need to manually undo this (or just explicitly apt-get install xserver-xorg-core) if you want to upgrade later.

Mon, 03 May 2010
newsflash: narcissism

I haven't posted anything in a while, so I thought I'd give a little update on what's happening in my life:

  • Some of you might have noticed that proton (this machine) melted itself into slag a couple weeks ago. Strangely, that same weekend I lost a drive from the RAID on positron, and then lost a second one after rebuilding the array! Dylan suggested, quite astutely, that the stress of rebuilding the array probably pushed the second drive over the edge on which it'd been teetering. Once I got positron back up, I was able to restore most of phonon, and some things even work better now than they did before—I hope.

  • After some conversations with some of the gentlemen with whom I ran the T.I.G.E.R. Valley 4-man match, I decided I wanted to build myself an AR-15. My new pretty princess (picture perhaps forthcoming) comprises a Noveske SPR 18-inch upper assembly, a DSA ZM4 blemish lower (blemishes are literally invisible), a CMMG lower parts kit, Magpul MOE stock and grip, an AFG, and ladder rail covers (all in Foliage), a Viking Tactics sling (padded slings are for girly-men), and not one but two optics (omg how hsld): a Trijicon Accupoint 3-9x40mm mounted on top and a Primary Arms Micro Dot on a Daniel Defense offset rail. Despite two more inches of barrel and two optics, this gun is still a pound lighter than my favorite little fattie, my SIG 556 with the Leupold CQ/T.

  • I've taken up kickboxing, studying a kind of fusion of Muay Thai and American-style kickboxing at Randy Palmer's South Austin Gym. The classes are awesome, the instructors are friendly and cool, and it's a good workout. It also comes with use of their full gym facilities, so I'm now able to bike to the gym and work and then bike back for some kickboxing in the evening—a tiring but rewarding day. (Today I'm driving on account of errands...)

  • I'm dating a wonderful lady whom, were I given to aliases in the style of our mutual friend Seano, I would call Knightress. It seems likely that some of you will meet her and her amazingly cute 16-month-old daughter at May's wedding. That's right, I'll be fielding a biological timebomb at May's hymeneals. (I love how dirty that word sounds.)

  • After many years of indecision (mostly with respect to what rather than whether), I got a tattoo last Saturday (pictured at right). It's a conformal mapping of the line segment 0.5+jt, t∈[-14.135,37.586] through the Riemann zeta function. The fill is the result of plotting the data as an SVG path with fill-rule="even-odd". The tattoo resides on my left deltoid. My artist was Ben T. Fiedler at Resurrection Tattoo; it's a great shop, and Ben is fucking awesome. Apparently all the fine circular lines make this a pretty difficult tattoo to do well, and Ben did a beautiful job. (Leave it to me to come up with a hard design, right?)

  • I've been tearing through the Culture novels by Iain M. Banks. They are fucking awesome. Banks has written up a nice essay discussing his ideas about the Culture, a galactic civilization that forms the backdrop for these novels. I also recently read City of Bones by Martha Wells thanks to Ellen's generosity in lending it; it was a good read.
Fri, 02 Apr 2010
whistlin' XP

The Dell mini-10 I got about a year ago came with a ridiculously broken install of Windows XP SP3 on it. By ridiculously broken, I mean it didn't have the Windows Installer component/service/whatever installed—and you can't install Windows Installer without having it already. Great.

Until now, I've completely ignored it, because I have Ubuntu on the thing and couldn't care less about running Windows on it. However, it bothers me that half the hard drive is dedicated to a broken XP install, and I really don't need a 160Gb hard drive fully dedicated to Linux on my netbook, so it's worth having something there on the off-chance I want to dual boot.

No problem, install XP over again. Yeah, except that the thing has no CD-ROM drive, and I seem to remember that it didn't particularly want to boot from a USB CD-ROM last time I tried (though in retrospect I probably could have made this work; the problem was most likely related to the second bullet below). So, it was time to make an XP install USB key.

This thread on GeekPolice details a decent way of doing it, but it leaves a few things out and lacks a couple steps that were specific to my computer. In particular,

  • You have to use a USB key that is <=4Gb (possibly <=2Gb), because PeToUSB will fail on larger drives. Later versions of PeToUSB, which do work on larger drives, are also not usable because they format NTFS instead, which requires a different bootloader setup than the one this method uses.
  • If you are doing this on something like a Mini-10 and using an older Windows XP CD, the setup process will very likely freeze right after loading all the drivers. The solution is to slipstream SP3 into your XP install before creating the USB drive from it.
  • By default, the boot.ini created on the USB key assumes that you will install into the first partition on the hard drive. If you're not, you will need to edit the "Boot Into GUI" line in boot.ini so that it points to the proper one (i.e., if you have a BIOS partition first like most factory installs, you'll want to point it to partition 2 instead of partition 1).
  • Obviously, afterwards you'll need another flash drive ready so you can go back and reinstall grub in the boot sector.
Tue, 23 Mar 2010
texts from last weekend

Last weekend I participated in the Tiger Valley 4 Man Tactical Team Match in Waco along with a bunch of SA Goons comprising three teams. It was, in a word, awesome. Here's my writeup about the stages from the thread.

A bunch of us were talking after the competition and decided that we would do post-mortem analysis of our preparation, strategy, and gear. That post is forthcoming, but first I'm going to paste the text of the stage description sheet, and comment on how they modified it because of the inclement weather.


Before I do that, I want to point out that the posts in the thread from ASSers thus far do not come close to properly illustrating the depths of misery we suffered on Saturday. Several points during that day were, no shit, among the most acutely unpleasant things I've withstood in my life. I'm pretty sure I have minor nerve damage in my fingertips, since they're still numb now two days later.

When we got in the car to head back to the hotel, it had warmed up from the coldest point in the morning, and my car's thermometer was reading 37F. In the morning it was hanging right around freezing with steady 40kt winds and driving rain. I'm pretty sure when the TX team ran the shotgun stage the rain was freezing on the way down. Beyond all of this, while most of us had some kind of rain gear, no one had anticipated sub-freezing temperatures, so we were completely under-dressed. Combine this with the fact that we were pretty much instantly soaked through and the knee-high water we had to plunge through several times while running and while helping reset the shotgun stage and you begin to get the idea.

Diver Dick was suffering from pretty serious hypothermia by the time we got back to the hotel (I hear Arcmage was, too), Ne Cede Malis probably couldn't feel his feet until some time after dinner, and Totally TWISTED was running the competition with a respectable chest cold. What I'm saying is, Team USA was a bunch of fucking troopers. Thanks for the effort, gents.

Saturday night, most of us hit Wal-Mart and picked up some more gear: wind breakers, shirts, pants, footwear, et cetera. Combined with the fact that it was dry and a good ten degrees warmer (but still pretty damn windy), Sunday went much better.

Stage Descriptions

from the handout. The ordering was different for different teams because they had us running some in parallel; I'm just copying the one on the sheet.

Stage #1 - Crazy Indians

Teams will start on the 200 yard line with unloaded long guns and pistols. On the timer, teams will load and engage target of their choice (1) BOBBER 5 points each hit (1) STOP AND GO 10 points each hit (1) WALKER 15 points each hit (1) RUNNER 20 points each hit, with 15 rounds each target [ed: I believe the word "target" here is a misprint; they meant "with 15 rounds each (shooter)"]. Targets will expose for 90 seconds, starting on the timer. Only 15 rounds will be counted on each of the 4 targets.

Pretty much as described, except for my note above. The most abusive thing about this stage is that the walk to it was a bit over half a mile straight into the wind and rain.

I put pretty much all my shots into (well, at, anyway) the walker, since I was confident I could hit it consistently. The runner would actually come to a stop for short periods of time when reversing direction, at which point you could take an easy 20 points; I did this once or twice.

Stage #2 - Shotgun Jungle Run

On the timer teams will start in the start/stop box located by the tower with unloaded shotguns and 16 rounds of shotgun ammunition. On the timer, shooters will move to the pepper popper station and load (4) rounds each (max) and engage 4 pepper poppers from fault line. Once engaged, shooters will show clear to RO's and move down trail stopping at each fault line station and engaging skeet at each of (3) fault lines, showing clear before moving out of position. Once all 4 arrays of targets are hit, time stops on the last shot. Five minutes max time.

"Skeet" in this case just means clays on steel stands. As I mentioned before, the run from line to line involved several dips in knee deep water and some treacherously sharp underbrush. I found that pulling two shells out of my bandoleer while running was a reasonable strategy for speeding up reloads.

The shotgun that failed Dan in the video Foghorn posted above was actually my IAC Hawk with Scattergun Tech follower and extension, and I ran precisely the same gun with no issue on this stage. As Craptacular said, the issue was with the fourth round not getting seated in the mag tube properly. After the RSO handed me the gun, I was able to clear it with a little poking and prodding, and had no further issues.

Sorry my shotgun failed you, Dan...

Stage #3 - Helicopter Assault

All teams begin stage in the start box. Each shooter will have their rifle and one magazine staged at one of the three barricades and one in the tower. Pistols will be holstered. On the timer one shooter will enter the helicopter and engage the pistol target until hit. After hitting the steel pistol target, the shooter will holster down range and exit the same side. Once that shooter has exited the next shooter moves into the helicopter until all four have engaged the pistol target. Upon exiting the helo, the shooters, either individually or as a team, will move through the obstacles (tunnel/window/wall) to their rifle station, where they will engage a steel target with six rounds each. Once the steel is hit, they will clear, safety and ground their weapons, moving to the tower, entering through the scuttle hole. Once all team members are in the tower, one of the shooters will act as a spotter and retrieve the target notebook and call out the steel box target for the tower shooter to engage. When the shooter hits the designated steel target, the spotter will use binoculars to identify the designated colored paper target in each box then call the paper target in the opened box for the shooter to engage with one round and one round only. Once all three boxes are opened and three shots fired time will stop. Five minutes max time.

Aye, there's the rub: five minutes max time. The helo/pistol part was pretty easy, and the tunnel and window obstacles not really hard, but we were having optics/sighting issues, so the steels at 100ish yards tripped us up. I'm proud of Team USA for coming up with a strategy for getting everyone over the (8-foot) wall and then executing it pretty much perfectly (we didn't get Totally TWISTED over because time ran out, but Ne Cede Malis and I were up and pulling him over when they called time).

This was the first stage where it became apparent to me that part of our strategy should include a time limit per section, i.e., "if you can't get your 6 rifle hits in 30 seconds, take the penalty and move on." I believe if we'd done this properly we would have been able to finish the stage. As it turns out, only two or three of the twelve teams did so.

Stage #4 - Tower Scramble

Four shooters will be on the first floor of the tower. On the timer one or all shooters will engage the land mine with fire for a total of 10 seconds or until the mine explodes. Other targets cannot be engaged for 10 seconds or until mine detonates. Once mine or ten seconds have elapsed, shooters will engage other targets at their discretion. Each target must have two hits to neutralize.

The "land mine" was some tannerite.

This was a pretty nifty stage, and we had a sound strategy, but I made a mental error after reloading and left a couple targets for which I was responsible untouched (and a third with only one hole in it). Lesson here: be careful and methodical, and think think think.

Oh, wait, did I mention the 40kt winds? We were facing straight into them from 15 feet off the ground in the tower during this stage. Keeping the rifle steady was hard work.

Stage #5 - Village Assault

Team will start in start box. On timer two shootrs will move to engage steel targets with rifle fire. Simultaneously, two shooters will move to recover stolen stores, first both going upstairs and engaging pistol targets, then moving back downstairs where they will recover stores and return both shooters and stores to start box.

This one didn't run quite as described (pistol shooters shot from downstairs, not upstairs). The rifle shooters had to run about 100yds before engaging their targets, about 20 steel knockdown targets 100 yards out. Totally TWISTED and I did the run, and my first instinct was to run as fast as I could. Problem was, this meant when I got there I was breathing hard for a few seconds before I could start to shoot accurately. Next time, fast jog on the way out and sprint on the way back.

This stage also highlighted a minor structural problem with the competition: the RSOs weren't 100% in sync on the rules for each stage. The RSO at the start box told the pistol shooters that each person had to shoot each pistol target, whereas the RSO inside the house told them one hit apiece. In the end, it didn't matter---the rifle part took much longer anyhow---but it would have been nicer to be clear on this.

Stage #6 - Zombieland

On timer shooters will move from the start box to shooting positions and engage all targets with head shots for a total of one round in each head. Once all head shots are made on paper, shooters will unload and show clear and move into north 1 bay and engage all steel with pistols with one hit in each head from shooting box. All Zombies must be hit before any team member can move into next bay. All steel targets must be shot with pistol and all paper must be hit with rifle. Rifles must be cleared before moving. Pistols must be holstered. Once all Zombies are hit, shooters must move back to start box.

This was a pretty fun stage, and mercifully the last that we ran on Saturday (PA and TX teams ran odd/even pairs in backwards order on Saturday, so they finished on #5). Two bays with pistol targets and two with rifle, with two rounds on each rifle target and one round in the head on each pistol.

Absolut_Zero and Diver Dick can doubtless talk more about this, but the berm setup for these bays was a bit... inadequate. The range was set up so that people walking to the other stage could end up walking behind the berms where this stage was running, and what I'm guessing were ricochets from the pistol steels were going over the berm and whizzing over the heads of passers-by. Fuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuck.

Stage #7 - Rattle Battle

All shooters will have 3 magazines loaded with 15 rounds each. The shooters will have 40 seconds to move from the 500 yard line to the 400 yard line where one shooter will shoot standing, one kneeling, one prone and one sitting. Shooters will have 1 minute to fire 15 rounds in their position. At the end of one minute, shooters will again have 40 seconds to move to the next firing position and repeat drill shooting on the 400, 300 and 200 yard lines.

They changed this one up a bit because of the high winds on the course (and presumably to get through it faster). They ran three teams simultaneously shooting at their own targets; all shooters were prone; advances to each yardline were untimed; and 90 seconds were given instead of 60.

This was the first stage we ran Sunday, and all three ASS teams ran simultaneously. I think one of the OTF guys got some footage of us doing it. Unfortunately, we were the last group to run it and for us the wind strengthened considerably compared to the first teams to shoot.

Stage #8 - Hostage Rescue

Shooters will start in start box at the entrance to the North bays. On timer, shooters will move and engage all targets from shooting boxes. From the shooting positions in each bay, paper will be engaged with rifle and steel with pistol. Rifles must be cleared before moving. Pistols must be holstered. Once shooters arrive at North bay three, team will split in half, two moving to shoot house bay and two engaging targets in bay three. As shooters move to the shoot house, one will breach the door and one will move into house and engage targets. Once he calls that the building is clear, other team members will help remove downed person to stop box located outside building.

They changed this stage completely, and it was really not much like the above. Instead, the teams carried a 300lb dummy throughout the stage, starting with him in the start box and moving forward to each bay, setting him down and engaging targets in that bay. First two bays were pistol steels, second two bays were rifle paper. The trick on the rifle paper targets was that you had to get a head shot, and you could only have one shot on paper. Two shots on paper or a shot not in the head didn't count. After that, carry dummy back to the beginning of the stage.

The hardest part here was coordinating carrying the dummy. Totally TWISTED and I took turns calling out a cadence, which worked well except that by the end I was just too fucking winded to keep yelling. The dummy's weight also shifted left to right, and there were no good handholds. The lesson I learned here was, if you can bring along something generally useful and really light like some nylon webbing and a carabiner, do so. It's worth carrying around for cases like this where you can substantially improve your ability to carry the fucking dummy.

Also of note: as far as I could tell, Team USA really enjoyed the physically taxing stages. Both this one and the helo stage, despite being ass kickers, were a fun challenge. Of course, it might have been that this was the last stage we ran, and were were just thankful it was over...

Stage #9 - Building Assault

Shooters will be located approximately 100 yards from the first building in the start/stop box. On timer all team members will engage one steel target each for a total of four targets in gray building with rifles. Once all targets are hit shooters will unload and show clear with long guns and move to assault two story building, with two moving to the second floor and two moving into the first floor. Shooters will load only when in position. Shooters going up stairs will engage rifle targets, shooters down stairs will engage steel targets with pistol. When all targets are hit all members will unload and show clear then move back to the start/stop box.

Actually, we were done when clear, they didn't make us run back to the start box.

We were nervous about this stage because Diver Dick's rifle was unscoped and the irons weren't particularly well sighted, and both Totally TWISTED's and Ne Cede Malis's rifles' zeros were questionable. Additionally, they told us that shooters were not allowed to assist each other with the first four rifle targets: each shooter must engage his own. We decided that whoever shot the best on the first part would do the rifle on the second, and the other two would do pistol. It ended up being me and Ne Cede Malis on rifle after the 200 yard dash from the start box to the assault house, and there were about 20 steel knockdown targets placed 100 yards beyond the second house. A couple of them took multiple hits to down because the wind was blowing straight into their back.

This was a favorite stage for us, and we completely owed the first part of it: I killed my steel on the first hit (booyah) and none of us took more than three. The RSO was actually really impressed by us here.

I'm going to split out my general thoughts and other individual experiences that are non-stage-related into another post.

Tue, 16 Mar 2010
mixin fixin

"To me, making a tape is like writing a letter—there's a lot of erasing and rethinking and starting again. A good compilation tape, like breaking up, is hard to do. You've got to kick off with a corker, to hold the attention (I started with "Got to Get You Off My Mind", but then realized that she might not get any further than track one, side one if I delivered what she wanted straightaway, so I buried it in the middle of side two), and then you've got to up it a notch, or cool it a notch, and you can't have white music and black music together, unless the white music sounds like black music, and you can't have two tracks by the same artist side by side, unless you've done the whole thing in pairs and...oh, there are loads of rules." - High Fidelity (wr. Nick Hornby)

Here's the problem: no one really uses tapes any more. Hell, no one really wants to use CD-Rs either: you just have to rip them again, or copy MP3s from them to your iPod or whatever. No, today's mixtape medium of choice is a USB stick. The problem with this is that there's just too much freaking room on a USB stick. Giving someone a dozen songs on a USB stick is... flaccid. Be generous, for Chrisake.

For myself, when I run into a problem like this, I just ask: what should any reasonable engineer do? Go up a level in the hierarchy. It's time for a new kind of mixtape: the album mixtape, a mixtape of albums rather than of songs. Now, I'll be the first to admit, the album as an art form seems to be dying: pop artists just aren't good or prolific enough to make an entire album of songs, let alone a cohesive, gestalt kind of thing. At the end of the day, yes, we end up eliminating some good one-hit wonder types from consideration, but hey, if you want that you wouldn't be making an album mixtape anyway.

So I set out to make my first album mixtape. My criteria: around ten albums in length; each album has to be one that I consider a really good album on its own (you don't put crappy songs on mixtapes, so...); has to have some kind of glue to it, be it smooth transitions from album to album or some kind of overarching theme (in the end, I went with the former). Fair game here would be Ari's suggestion from earlier today, viz., an album mixtape of concept albums.

Anyhow, this was my raw list:

  • Polo Club - Greenskeepers
  • Silent Alarm - Bloc Party
  • We Are Not Alone - Breaking Benjamin
  • At War With the Mystics - The Flaming Lips
  • The Soft Bulletin - The Flaming Lips
  • Come to Daddy - Aphex Twin
  • Oracular Spectacular - MGMT
  • Carnavas - Silversun Pickups
  • The Bends - Radiohead
  • Superunknown - Soundgarden
  • Songs for the Deaf - Queens of the Stone Age
  • Surfer Rosa - The Pixies
  • Mer de Noms - A Perfect Circle
  • eMotive - A Perfect Circle
  • Listening Tree - Tim Exile
  • There is Nothing Left to Lose - Foo Fighters
  • Forever Changes - Love
  • Turn on the Bright Lights - Interpol
  • Lateralus - Tool
  • The Mollusk - Ween
  • Close to the Edge - Yes
  • Loveless - My Bloody Valentine

Now, I needed to start striking stuff. First, Carnavas, while decent, isn't by itself an awesome album. Gone. Between AWWTM and Soft Bulletin, there's really no comparison; the former didn't make it. TiNLtL is a fucking great album, but it's kind of been overdone; between that and the QotSA album, I'll take the latter for novelty and musical range. Given the surviving albums, MGMT and Radiohead are starting to stick out as a bit incompatible, so they're out. Breaking Benjamin's a good band, and WANA is their best album easily, but it's also not quite right for this collection. This leaves us with a bit more than a dozen, and then it's just a matter of sorting them. It's at this stage that I ended up eliminating the last to go, viz., Lateralus, Close to the Edge, and Superunknown. All are fucking awesome, they just weren't fitting anywhere in the mix in my mind's ear.

So, the final list—in order! which is important for a mix tape, even of albums:

  • Polo Club - Greenskeepers

    This album starts really strong, and it's quirky and awesome throughout. C'mon, a loungey pop rendition of Slayer's "Raining Blood"?

  • Come to Daddy - Aphex Twin

    Polo Club's bonus track is a kind of creepy song with lyrics including "it puts the lotion on its skin / or it gets the hose again." It segues nicely into "IIIIIIIIIIIIIIIIIIII WANT YOUR SOULLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL".

  • Songs for the Deaf - Queens of the Stone Age

    While CtD starts all crazy, it ends on some pretty chill strains with "IZ-US", which always felt to me like a bus ride through a bombed out city. After that, a car starting and a faux AM radio asshole deej introducing the next song seems like a good flow.

  • Forever Changes - Love

    This album starts with a folksy guitar riff, which transitions nicely from SftD's "Mosquito Song". This album is fucking great.

  • The Soft Bulletin - The Flaming Lips

    After the acid-washed depression of Forever Changes, which is kind of an end-of-the-60s retrospective on what was ultimately Timothy Leary's failure to expand our minds with copious amounts of acid, the Lips' album about depression and madness, starting with the deceptively upbeat "Race for the Prize", slides right into place. The Lips' constant stream of psychedelic rock homage is a fitting coda for Forever Changes.

  • Silent Alarm - Bloc Party

    Scratchy, guitar-driven rock is precisely what you need to get yourself back out of the dumps of "Waiting for a Superman [Remix]". Yeah, it's already too heavy to lift—and now it's like drinking poison and eating glass. Don't worry, though, this album sweeps you right up and takes you through "Positive Tension" and "This Modern Love" to "Compliments", which closes it out nicely and does a pretty good job of putting us in a darkish, synthy mood—just in time for

  • Listening Tree - Tim Exile

    This dude is relatively unknown; I saw him open for Imogen Heap. He has some good IDM/D&B/&c riffs on here, and the mood starts and stays relatively dark throughout. I'd be hard pressed to claim that this is actually one of my favorite standalone albums, but the combination of novelty (c'mon, everyone knows you get points for stumping your listener) and mood propriety saves it.

  • Loveless - My Bloody Valentine

    You might argue that I should've just skipped straight to this and dropped Tim Exile from the mix entirely. If that's your feeling, call Listening Tree the prologue to this gritty, atmospheric masterpiece. These guys were ridiculously exacting in the sound they were after—and it's just what we want here.

  • Surfer Rosa - The Pixies

    Black Francis is like a kid who just kind of bangs shit together, but the result is an awesome sound. This album is probably most popular for "Where Is My Mind," but the whole thing is just freaking great. I'd go with the extended edition with an extra 9 songs on it; they're worth the listen.

  • eMotive - A Perfect Circle

    What? An album of covers? Well, not quite: "Passive" was actually jointly written by Maynard and Reznor, and it shows in how awesome it is. Beyond that, there is a hauntingly awesome cover of "When The Levee Breaks" on here that by itself makes this album worth having. But at the end of the day, I like it for the "mixtape in a mixtape" aspect of it, all touched and poked by Maynard et al. And it's a damn solid album.

  • The Mollusk - Ween

    This is the best album to have been made in the last 30 years. I doubt any of you agree with that statement, but that just means you're wrong. More to the point, this is my mixtape, so fuck you. We start off with a nice little intro that could transition from anywhere—"Dancing in the Show Tonight"—and immediately jump into the nautical concept of the album. "The Blarney Stone" deserves a place at your St. Patty's Day celebration, and "Ocean Man" is both fun and kid-safe. Really, the reason this album belongs last is because "She Wanted To Leave" is—and has—an amazing ending.

    "So go fetch a bottle of rum, dear friend,
    and fill up my glass to the brim,
    for I'm not the man I used to be,
    now I'm one of them."

Welp, that's my album mixtape. Obviously I went for the continuity aspect over the single-concept one, but I'd submit that both are reasonable, as are many other approaches.

Now it's your turn: make me an album mixtape.

Thu, 31 Dec 2009
after week 16

Note that Indy's dive throws things off a little bit in terms of their offensive ranking and the Jets' defensive.

combined                offense                 defense
--------                -------                 -------
IND	100.000        	NO	100.000        	NYJ	100.000        
NO	91.646        	SD	91.830        	BAL	95.749        
SD	86.626        	PHI	91.822        	DAL	93.576        
PHI	79.168        	MIN	91.079        	NE	92.607        
MIN	77.052        	GNB	90.935        	CIN	89.327        
NE	75.478        	IND	89.343        	SF	83.683        
DAL	72.214        	NE	88.670        	DEN	79.886        
CIN	70.993        	NYG	88.260        	IND	78.597        
GNB	70.450        	BAL	83.602        	CAR	72.561        
ARI	69.379        	ARI	82.140        	GNB	71.179        
NYJ	59.995        	HOU	81.507        	ARI	69.409        
BAL	59.619        	ATL	81.006        	ATL	67.241        
ATL	56.848        	MIA	80.614        	PIT	66.943        
HOU	56.649        	PIT	79.647        	WAS	66.417        
DEN	56.223        	TEN	79.430        	SD	66.388        
NYG	55.115        	DAL	78.356        	MIN	65.096        
PIT	54.285        	NYJ	75.029        	PHI	65.050        
SF	49.062        	CIN	74.061        	HOU	65.034        
MIA	47.653        	DEN	73.744        	BUF	63.172        
CAR	46.999        	SF	72.777        	NO	58.624        
TEN	46.016        	CAR	72.133        	CHI	51.396        
JAC	43.203        	CHI	70.997        	MIA	48.238        
CHI	37.677        	JAC	68.853        	CLE	46.066        
SEA	29.773        	SEA	66.965        	OAK	45.890        
BUF	28.588        	KC	65.263        	JAC	45.735        
OAK	25.806        	WAS	63.496        	TB	42.616        
WAS	22.032        	DET	62.662        	SEA	41.756        
CLE	20.077        	TB	62.391        	NYG	41.546        
TB	15.091        	BUF	60.792        	TEN	38.025        
KC	15.030        	CLE	58.612        	STL	31.421        
DET	6.833        	OAK	52.066        	KC	31.306        
STL	0.000        	STL	47.825        	DET	14.704        
Tue, 01 Dec 2009
return to power

In case you're wondering,

Combined                Offense                 Defense
---------------         ---------------         ---------------
IND     100.000         NO      100.000         CIN     100.000        
NO      96.530          MIN     90.914          IND     99.404        
MIN     85.854          SD      87.094          BAL     99.154        
SD      73.787          NE      86.272          DAL     97.433        
CIN     71.224          IND     85.064          DEN     96.653        
DAL     70.499          PHI     83.040          NYJ     94.711        
NE      66.515          GNB     82.737          NE      90.838        
ARI     63.300          ATL     79.940          SF      85.635        
DEN     60.719          NYG     79.766          WAS     85.147        
PHI     60.670          HOU     77.754          PIT     84.737        
GNB     60.126          ARI     77.707          MIN     84.661        
BAL     54.662          BAL     77.599          GNB     79.654        
ATL     52.455          MIA     77.559          ARI     77.114        
PIT     52.065          DAL     75.316          NO      75.706        
NYG     51.601          PIT     75.068          SD      74.312        
JAC     47.213          CIN     71.825          PHI     73.979        
NYJ     45.441          TEN     71.411          BUF     68.004        
HOU     43.562          NYJ     70.387          ATL     66.263        
SF      43.479          SF      70.307          HOU     65.208        
MIA     42.014          SEA     68.625          SEA     63.467        
TEN     38.591          CHI     67.272          CAR     61.805        
SEA     32.860          JAC     64.340          NYG     61.136        
CHI     29.897          DEN     64.291          OAK     59.830        
CAR     27.723          CAR     64.230          CHI     59.151        
BUF     27.607          DET     62.873          JAC     56.308        
KC      18.676          KC      61.394          MIA     53.770        
WAS     17.154          TB      60.568          KC      49.372        
OAK     15.546          BUF     60.357          CLE     48.835        
DET     9.777           WAS     56.923          TEN     45.520        
STL     1.305           STL     46.451          STL     44.678        
TB      1.101           CLE     44.257          TB      37.409        
CLE     0.000           OAK     42.602          DET     25.697        
Tue, 27 Oct 2009

Based on management's favorite catchphrase:

Sat, 19 Sep 2009
now with squid bits!

Your brain cannot repel entertainment of this magnitude!

TriHs r465 adds a major feature: two player mode!

True to my word, I've added in the "asshole button" for each player: swap your opponent's next piece for a random one. I don't know yet whether it's a useful addition or not, but at the very least simple strategies like denying them the I or giving them a neverending stream of S and Z are probably annoying enough to get you punched in the face.

I've also added shadow mode, even though I think it's totally cheese. By default it's off, but you can activate it with <Ctrl>-s.

The other somewhat major change I made was breaking the drawing module out of Main. This is a logical partitioning of functionality, and probably makes it a bit easier to swap out Cairo for, e.g., OpenGL. Not that I have any plans to do this, but perhaps someone else will be adventurous. (Hippo, I'm looking in your direction.)

Update: r466 corrects the previous loss condition to bring it in line with the official rules.

Tue, 15 Sep 2009
damnit Jim

Because Jim is such a nitpicking bastard, and after reading the Wikipedia page, I have an update for you. (Seriously, thanks for the feedback, Jim.)

r460 has the following changes:

  • CW and CCW keybindings (that you might hate, depending on your keyboard; just fix it if you don't like mine)
  • Instant (hard) drop
  • Hard drop on the final "down" press (or just wait for the soft drop as before)
  • Updated scoring system so that it rewards multiples a bit more
  • Changed the color scheme to match The New Tetris.
  • a README file!

As I add minor updates, I'll just post them here. (Major ones will go in their own entry.) Here's a summary of every version I've posted so far:

  • r457 - first release
  • r458 - added Makefile
  • r460 - fix detailed above
  • r461 - fixed an erroneous return value from the keyboard handler that was really harmless
  • r462 - took focus off the Quit button so that space bar doesn't cause the program to exit
  • r465 - see 2009091901
  • r466 - fixed loss condition to bring it in line with the official rules
Mon, 14 Sep 2009
the (not) long awaited... here! You'll need Graphics.UI.Gtk (a.k.a. Gtk2Hs), Graphics.Rendering.Cairo (also part of Gtk2Hs, but sometimes distributed separately), and Control.Concurrent (I use an MVar for game state in case I want to do something crazy later).

For now, this is just a normal tetris game. Ctrl-R restarts, Ctrl-Q (or Alt-Q, or the Quit button) quits.


I don't wanna sound like an Egyptian or nothin'

...but I really like libcairo. Over the weekend I wrote a Tetris-like game using cairo via Haskell's Gtk2Hs bindings.

I have one more obvious bug to fix before I release the source, so I'll probably post tonight once it's fixed. After that, I'm going to implement a bastard function, then scale it out to two players and allow each player to choose the other's next piece if they want.

Obviously we'll need a computer opponent mode as well...

(If you're wondering, I'm hovering around 300 lines of code, but that's a bit on the high side because I went for readability over smallest LoC, and I basically wrote a library of game state transforms and collision predicates and didn't use all of them.)

Wed, 12 Aug 2009
a little diversion

On the road trip I started working on an implementation of Set. To make it slightly easier to play I've given it a shitty CGI UI. It works well enough, I guess.

Here's the source (in Haskell, of course).

Oh yeah, also, here's the latest tarball of the crap I hacked up at DefCon for keyboard acoustic eavesdropping.

Thu, 16 Jul 2009
end of an era; stroker and hoopdisk

The world is a different place.

Last night, after a trip to Fry's, I replaced the last proud vestiges of positron Mk. III, the IBM Ultrastar DNES-318350 U2W SCSI boot drive (a whopping 18.2 Gb!).

Not that it died, or anything; it's still running great, and I'm keeping it as a cold backup of my boot drive. The reason I replaced it is that the SCSI controller was unhappy when I put the computer into ACPI S3 (suspend-to-RAM), or more specifically when the computer resumed operation: it would timeout for almost a minute before doing a bus reset, and I was concerned that this could cause problems with filesystem consistency. Since I'm running XFS, I'm not taking any chances—as far as I can tell, it's somewhat less robust against corruption than EXT3.

The replacement drive is a 500 Gb Hitachi Deskstar, née IBM Deathstar. These days the Hitachis have a better reputation and a 5 year warranty, plus I have my trusty old Ultrastar in case something goes wrong.

Because I don't need much space on the boot partition, I decided to short stroke the drive for a bit better seek performance and thus faster boots. Basically, I made a 30Gb partition at the beginning of the disk, and left the rest to other partitions. Since the partition is small, the average seek time within the partition is much shorter than the average over the whole disk. The rest of the drive I devoted to a swap partition (kind of a waste, but whatever) and—horrors!—a Windows partition.

I haven't run windows on positron since late 1998, which means I broke an even longer standing tradition than my 10 year old SCSI drive by installing it last night. I doubt I'll boot it at all until I start playing some fancy computer game that isn't happy enough on my T61, but it feels really wierd to see Windows booting.

Also, even with a "fully updated" XP SP3 install CD, the install took longer and required more intervention (during and post install when it hadn't gotten my drivers right) than the last Ubuntu install I did (I'm not going to say it was harder than a debian install would be for the average person, but it was certainly more painful for me (in a "guilty conscience" kind of way, really)). I guess most people never install Windows since they just throw away their computer when it becomes too full of viruses, but it's nice to see just how good Ubuntu et al have gotten, especially when reflecting on the computer on whose earliest versions I ran a 1.0.2x kernel. (OK, there is nothing left of that machine but the name, but what's good enough for Theseus is good enough for me.)

Sat, 11 Jul 2009
dude I got a dell

Since I'm going to be doing a bunch of travelling this summer, I decided I wanted a really portable computer. Now, netbooks are all the rage, but I abhor low res screens, and most of them are a paltry 1024x600—utter shit—so I couldn't really get one of those, right? Well...

In the last couple months a new generation of netbooks has become available with higher resolution screens (1366x768) at reasonable prices. (There's also the awesome but stupidly expensive Sony Vaio P with the 1600x768 screen in 9", but I'm not shelling out for that.) At first I dismissed these as lacking, but then I considered that my 14" Thinkpad T30 is ugly but tolerable at 1024x768, so a 1366x768 screen in 10" probably would look pretty nice. Moreover, given that the T30 was previously my best option for travel, I'm going strictly upwards in res, portability, battery life, and modern niceities like USB2. Computing power might be a very small step back from a 1.8 GHz P4-M to a 1.6 GHz Atom Z530, but it's probably not more than 20% or so—plenty for a little travel laptop!

Of the available models, I was most intrigued by the Dell Mini-10 and the Acer AO751h, which are more or less identical. The deciding factor was that I was able to get a refurbished Mini-10 for $330, whereas new both are about $450. Refurbs also have the virtue of shipping really quickly.

The only wart in hardware support is that the Intel GMA-500 video driver is kind of a mess and only readily available under Ubuntu (but it does work for 2d and 3d basically right out of the box). Don't get me wrong, Ubuntu is better than anything RedHat based, but certain pieces of its not-Debianness are annoying as shit. At the end of the day, as long as I can run some combination of fvwm and xmonad (depending on my mood) and apt-get install still works, I'm more or less happy.

Anyhow, for $330 it really can't be beat, and I'm very happy with it so far. Of course, I'll post updates as events warrant.

Fri, 10 Jul 2009
delay this

My Thinkpad T30 had a longtime issue where it would delay for 30 seconds after loading the network card on every boot. I never bothered to debug it until last night, which really makes no sense because I've now got a T61 and (very soon now) a Dell Mini-10 which together obviate the T30 entirely; nevertheless, I'm loyal to this little machine because it's still pretty great.

The issue started after a dist-upgrade several months (or more) ago, so I was thinking it was either the new kernel or maybe udev. After following a couple dead end leads (mostly regarding problems with the Cisco Aironet 802.11 card), I found a couple discussions about udev trying to rename the network cards but getting confused about the dual nature of the Aironet device (i.e., wlan0 and wmaster) and trying to just wait it out. The solution is simple: rm /etc/udev/rules.d/*persistent-net.rules to clear out stale entries from earlier versions of udev.

Note that since I use ifrename I don't care about having persistent network interface names assigned by udev. If you do, your solution may involve deleting this file and then editing the newly created one after a reboot so that your network cards are assigned the right names.

More discussion on this:

Hopefully someone will find this useful.

Mon, 15 Jun 2009
wrap this

rlwrap is awesome. It takes any commandline tool and makes it behave like it uses GNU readline.

Sun, 14 Jun 2009

or, Yet Another Y-Combinator Derivation

In the FAQ one of the questions asks about the Y-combinator; the answer is provided without derivation or explanation of the subtle datatype backflip you need to use. So we'll derive it together here.

We've all seen the standard Y-combinator derivation in Scheme, right? Y is a fixed-point combinator which represents, in effect, the distilled essence of recursion. To sketch Gabriel's argument (in Scheme first), we start with an example recursive function—factorial, of course:

(define fact (lambda (n) (if (= n 0)
                             (* n (fact (- n 1))))))

> (fact 5)

Now, what we want to do is define fact without using fact—so what if we change it so that we can pass the function in that we'll call recursively?

(define f (lambda (fz n) (if (= n 0)
			     (* n (fz fz (- n 1))))))

But what function do we pass in as fz? f itself, of course—it'll happily keep passing itself all the way down to the base case, and what we get out is factorial.

> (f f 5)

Now, for reasons which will become clear in a second here, we will curry this function, i.e., turn one function of two arguments into two nested functions taking one argument each:

(define ff (lambda (fz) (lambda (n) (if (= n 0)
					(* n ((fz fz) (- n 1)))))))
> ((ff ff) 5)

See? Basically the same thing, but now ff takes one argument—another function—and returns a function that takes a number and returns its factorial. But we're not done yet: we started with (fact n) and now we have ((ff ff) 5). Well, let's start by fixing the recursive call, recognizing that we can hide the (fz fz) inside lambda:

(define ff (lambda (fz) (lambda (n) (if (= n 0)
					(* n ((lambda (n) ((fz fz) n)) (- n 1)))))))

Well, that lambda in there is ugly, but we can always just pull it out and then pass it in via a variable:

(define ff (lambda (fz)
                   ((lambda (z)
		            (lambda (n) (if (= n 0)
					    (* n (z (- n 1))))))
		    (lambda (n) ((fz fz) n)))))
> ((ff ff) 5)

It doesn't look like we're getting any better in terms of recovering the original (fact 5) syntax, but I assure you we're getting closer. Recognize that we could recover the original behavior by just defining a new function fff like this:

(define fff (lambda (n) ((ff ff) n)))

Yup, we've seen this trick before. But let's expand out the (ff ff) so we can do just one definition:

(define fff ((lambda (fz)
                     ((lambda (z)
		              (lambda (n) (if (= n 0)
					      (* n (z (- n 1))))))
		      (lambda (n) ((fz fz) n))))
             (lambda (fz)
	             ((lambda (z)
		              (lambda (n) (if (= n 0)
					      (* n (z (- n 1))))))
		      (lambda (n) ((fz fz) n))))))
> (fff 5)

And we've done it. Nothing but arithmetic operations and passed-in function names for defining a recursive operation. But we can generalize this by realizing that we can separate out the "guts" of factorial relatively easily:

(define Fguts (lambda (z)
                      (lambda (n) (if (= n 0)
				      (* n (z (- n 1)))))))

This is a function that requires us to pass in the recursive continuation, so it is not itself recursive, and even better, now that we've defined it we can pull Fguts out of fff and make it somewhat prettier:

(define f3 ((lambda (fz) (Fguts (lambda (n) ((fz fz) n))))
            (lambda (fz) (Fguts (lambda (n) ((fz fz) n))))))

This is identical to fff, but we've folded the mess into Fguts. Note that we are still using (lambda (n) ((fz fz) n)) just as before—because this was really the first glimmer of the prize. Consider adding one more layer of lambda where we completely generalize by passing in Fguts or any other "guts"-style function:

(define Y (lambda (X)
                  ((lambda (fz) (X (lambda (n) ((fz fz) n))))
		   (lambda (fz) (X (lambda (n) ((fz fz) n)))))))

And we've arrived at the applicative-order Y-combinator. Taa daaaaaaa!

> ((Y Fguts) 5)

So could we do the same thing in Standard ML? Well... kind of. The type system gets kind of bitchy if we try to follow exactly the same derivation:

- fun f fz 0 = 1
=   | f fz n = (n * (fz fz (n-1)));
stdIn:3.20-3.31 Error: operator is not a function [circularity]
  operator: 'Z
  in expression:
    fz fz

Many ML programmers are unaware that there is a trick to deriving the Y-combinator in the same wy as above; we simply have to define a recursive datatype so that the type checking unification function doesn't complain about circular substitutions:

datatype 'a t = T of 'a t -> 'a

Now we can start at the top (almost; we'll take advantage of SML's automatic currying for now):

fun ff (T fz) 0 = 1
  | ff (T fz) n = (n * (fz (T fz) (n-1)))

- ff (T ff) 5;
val it = 120 : int

The above step is conceptually the most important and difficult in terms of getting Hindley-Milner on our side. ff has type (int -> int) t -> int -> int, meaning that we will need to keep the same fz (T fz) structure throughout the rest of this derivation. Without it, the type inference system will shun our circular definitions.

Continuing the same argument as before, we wrap the ugly fz (T fz) inside a lambda, then pull it out as an argument (with a little acrobatics because we can't take advantage of automatic currying for this step):

fun ff (T fz) 0 = 1
  | ff (T fz) n = (n * ((fn n => (fz (T fz) n)) (n-1)))

(* now pulling the new "inner function" out *)

fun ff (T fz) = ( ( fn z => ( fn 0 => 1
                               | n => (n * (z (n-1)))
		            ) )
                  ( fn n => (fz (T fz) n) ) )

Now we're ready for fff, and ditching the fun syntactic sugar completely.

(* fun fff n = (ff (T ff) n) *)

val fff = ((fn (T fz) => ((fn z => (fn 0 => 1
                                     | n => (n * (z (n-1)))))
                          (fn n => (fz (T fz) n))))
	   (fn (T fz) => ((fn z => (fn 0 => 1
                                     | n => (n * (z (n-1)))))
                          (fn n => (fz (T fz) n))))))

We're close now! Time for Fguts (returning for the sake of brevity to automatic currying) and then f3:

fun Fguts z 0 = 1
  | Fguts z n = (n * (z (n - 1)))

val f3 = ((fn (T fz) => (Fguts (fn n => (fz (T fz) n))))
	  (fn (T fz) => (Fguts (fn n => (fz (T fz) n))))))

So close we can taste it. Abstracting Fguts gives us the Y combinator once more:

val Y = fn X => ((fn (T fz) => (X (fn n => (fz (T fz) n))))
		 (fn (T fz) => (X (fn n => (fz (T fz) n))))))

Thus sayeth the interpreter:

val Y = fn : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
- (Y Fguts);
val it = fn : int -> int
- (Y Fguts) 5;
val it = 120 : int

By the way, there is a ridiculously simple way to define precisely the same Y-combinator in SML:

fun Y f n = f (Y f) n

(* or, using the built in compose operator "o" *)
fun Y f n = (f o Y) f n

Of course, both of these "cheat" because they're explicitly recursive.

Mon, 08 Jun 2009
formalism paradox

In perusing the veritable cornucopia of languages mentioned in my previous post (and others), I've noticed a curious pattern: languages with formal standards are, strangely enough, the ones most likely to have several competing, somewhat incompatible implementations. Languages like Standard ML, Common Lisp, Haskell, Scheme, and C are all standards-based, and yet their respective compiler/interpreter implementations have various incompatibilities.

Conversely, Perl and OCaml, whose featuresets are basically defined by their implementations, have essentially one version each (OCaml has VM versus native compilation, but with common maintainers).

Now, having multiple competing implementations certainly has its upsides, and I'm in no way arguing that it's bad to have a formal standard. It is really weird to consider, though: having a standard naturally encourages multiple implementations, which are almost certainly going to have at least some inconsistencies. By eschewing formal standards and adopting the perl "descriptive" (versus authoritative) documentation model, you virtually guarantee interoperability.

postpartum bliss

The chip taped out last Thursday; Friday I did some final cleanup stuff, and now I'm off until Friday. So now I'm just hanging out doing nothing.

Not really nothing. I might go out and buy inFAMOUS at some point—the demo is freaking badass and you should stop reading this and play it immediately—but right now I'm busy.

With what, you'll ask? Learning me some new programming languages. Yeah, plural—Standard ML right now, but I also plan to learn some subset of [Haskell, Erlang, OCaml]. In fact, Joe Armstrong's Programming Erlang is sitting right next to me on the couch because the nice mail lady just dropped it off; first impression is that it's a very decent deal at $25. The forthcoming Erlang Programming book from O'Reilly may also be good, but Armstrong seems to be universally loved, so I'm not going to argue.

The SML book I'm reading right now is one available online, Programming in Standard ML by Robert Harper. It's well written and gets you going. I burned through 10 chapters of it in a couple hours yesterday, and I've been playing around with what I've learned so far to help the syntax set in. So far, my impressions are that type inference is an astoundingly cool idea, and while SML/NJ is friendly inasmuch as it has a REPL, MLton produces code that runs substantially faster. Identical implementations of Rabin-Miller (modulo the differences in library calls) yielded a 3500x (yes, ~3.55 orders of magnitude) difference in speed. I'm pretty sure this implies that my implementation is crap and MLton is optimizing away my painful scribblings. Also with regard to SML/NJ versus MLton, the build sequence for the former is more annoying than for the latter—but that's what makefiles are for, so it's hardly worth mentioning (though the documentation on the build process is admittedly somewhat annoying).

Anyway, also on the menu for SML are UNIX System Programming with Standard ML (free online) and ML for the Working Programmer (can be had for like $12 used on Amazon). The wiki's Standard ML page and the SML/NJ literature page also list some more resources, and the SML sourceforge project has good SML basis library documentation.

For OCaml, the official user's manual is free, very complete, and is well regarded. There is also Introduction to Objective Caml by Jason Hickey, which despite being distributed from the Caltech website comes with ominous redistribution warnings. Apparently Practical OCaml by Joshua B. Smith is fucking terrible, so I'm not even bothering to link it. On the other hand, OCaml for Scientists seems well regarded. You can find it in DjVu format from a few pirate websites, but please buy the book if it's any good—or steal it brazenly if it's bad, I guess. Wikipedia lists a few online tutorials in the "External links" section of the OCaml article.

Among Haskell books, the best received seems to be the newish one by O'Reilly, Real World Haskell. You can read the whole thing online and perhaps even get lost in the paragraph-by-paragraph comments. I don't know enough about other resources to make specific recommendations, but the Haskell Wiki's Learning Haskell page has a bunch.

While I'm nerding on programming languages, I gave F# a spin under mono and, impressively, it works. It's pretty trippy to see this pop up in an xterm:

[kwantam@muon ~/Desktop/FSharp-]$ mono ./fsi.exe 

Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version, compiling for .NET Framework Version v2.0.50727

Please send bug reports to
For help type #help;;

> _

Brings me back to my old QBasic days. Speaking of which, apparently the FreeBasic project is pretty badass. I say this just in case you're missing nibbles or gorillas.

Sat, 30 May 2009

My old work mouse, a borrowed-ish MS Intellimouse Explorer 3.0A, had this odd habit of causing X to crash every once in a while. I don't know how this is possible, I only know that it had to do with the scroll wheel and it was very hard to reproduce. (OK, I can't say 100% for sure that it was actually the mouse, but the frequency of crashing with the same usage model dropped to zero abruptly after switching, which is good enough for me until I find a counterexample.) It may be that the thing is dying and somehow exposing a flaw in the xorg evdev driver.

All of that is beside the point. I went out and bought a new mouse, which was a frustratingly difficult task: apparently everyone likes their mouse wheel to feel like rotting fruit, whereas I want positive, LOUD clicks like the nearly unused Logitech bottom-of-the-line optical mouse connected to positron. Aside: I really ought to do something other than VGA mode on a text console considering I spent the $80 on an 8800GT when I rebuilt positron last year, right? Oh well.

So, because I wasn't particularly happy with any of the scroll wheels, but because I did still want a new mouse for work, I bought a $10 GearHead LM6000U laser mouse—if I can't be happy, at least I can be cheap. Laser mice, as far as I can tell, all use much higher resolution imagers than their diode-equipped optical siblings. As a result, when I move my mouse an inch, my optical mouse registers a 400-pixel movement, but the laser sees 1600 pixels go by. This is great, except that my fine motor skills haven't magically improved by 4x just because I spent a Hamilton at Fry's. So just turn down the mouse sensitivity, right? Well, kind of...

X has an interesting way of doing mouse sensitivity. Basically, you say xset m <accel> <thresh>, and when your mouse moves more than thresh pixels in a "short period of time" (probably one or two mouse refresh intervals, but I'm too lazy to find out for sure), the movement rate is multiplied by accel. But what if you want to slow down the pointer instead? Well, accel can be a fraction (yes, you specify a fraction, not a float), and thresh can be set to 1, and then all mouse movements end up slower. But then you lose the whole long distance movement acceleration thing which is really the point of this setting.

Well, now that we know that, we have to look a little more closely at the way X interacts with the mouse driver. In most modern implementations, e.g., default Debian behavior, X gets input device information from hald via the evdev module and sets up your pointers, ignoring any InputDevice sections in xorg.conf. While this is all soft and friendly, evdev is still a bit sparse in terms of configurability.

The other option is to use the traditional mouse module, wherein you can specify mouse resolution and, more importantly, mouse sensitivity. To convince X to do this, however, you first have to tell it to ignore hald-detected devices, like so:

Section "ServerFlags"
        Option          "AllowEmptyInput" "false"
        Option          "AutoAddDevices" "false"
        Option          "AutoEnableDevices" "false"

AllowEmptyInput disables the kbd and mouse drivers; AutoAddDevices is the setting that tells X to talk to hald. You don't actually need the third line; I just put it in there out of spite. You can see more about all of these options in the xorg.conf(5) manpage.

Now that X isn't autoconfiguring your mouse and keyboard, you're going to have to specify them manually... but you can handle that. The point for us is to enable the use of the mouse driver in an InputDevice section pointing to our nifty high-resolution mouse so that we can take advantage of that driver's greater configurability:

Section "InputDevice"
	Identifier	"Mouse1"
	Driver		"mouse"
	Option		"Device" "/dev/input/mice"
	Option		"CorePointer"
	Option		"Resolution" "1600"
	Option		"Sensitivity" "0.25"
	Option		"Protocol" "Auto"
	Option		"Emulate3Buttons" "no"
	Option		"ZAxisMapping" "4 5"

Now our nifty mouse is running at its maximum resolution, but we're scaling down the movements by a factor of four so it feels the same as the old mouse. This means that there are 4x the number of mapped mouse motion pixels in the same distance across the screen, i.e., you have higher precision control over your mouse pointer by a factor of 4 (no claims here about the practical limit of such things... if you don't think you need this, why did you bother buying a laser mouse?). It also means that we can go back to our friend xset and use the long distance accelerator function.

One caveat (this one bit me!): you cannot have two different pointer devices set at two different sensitivities. Don't complain to me, that's how xorg works. If you have multiple pointing devices, the highest (numerically greatest) sensitivity setting provided will be used, meaning if you have another mouse and have forgotten to set the sensitivity option in its InputDevice section, the above snippet will seem not to work because the default sensitivity is 1.0.

Another comment: for various reasons (basically I want firefox to work correctly), I run gnome-settings-daemon even though I use fvwm2 and abhor desktop environments. If you use a desktop environment like gnome or KDE, it will very likely override your xset settings with the settings from whatever crappy mouse config applet you use. If you don't want this to happen, at least in gnome, you can use gconf-editor to set desktop / gnome / peripherals / mouse / motion_acceleration and desktop / gnome / peripherals / mouse / motion_threshold to -1; this will apparently prevent gnome from screwing with your settings. Then, of course, just call xset at login from your .xsession (or whatever you call it) file. Or just use your crapplet to set it up and get off my lawn.

(Lest you point and laugh at my fvwm2 use: come back and talk to me when your windowmanager's configuration file is written in a turing-complete scripting language.)

Sat, 18 Apr 2009
whitespace Nazis must die

How am I the only person who sees how retarded Python is? It is, no lie, the worst programming language ever created.

Seriously. This is a language for which scripts can go from working to completely broken because your text editor converted tabs to spaces or vice-versa. I can email a working script to you and have it arrive broken. Newsflash: no one bothers to preserve whitespace because you can't fucking see it. Differentiating between a tab and seven spaces makes you retarded.

If you program in Python and like it, you are dead to me. If I see you programming in Python, I will kill you. Seriously, if you see me walking down the street while you're programming in Python you best jump right in the nearest coffin, I don't care if it's your birthday and you mama needs the coffin 'cause she's dead.

Thu, 11 Dec 2008
shackleds' revenge

Some of you might have read about this travesty of education. As a concerned resident of Austin, I did my part to help correct this injustice by writing the following letter to the AISD ombudsman:

From: "Riad S. Wahby" 
Subject: Austin teacher versus Free Software

Ms. Reeves,

I'm writing to you today on behalf of "Aaron," the student mentioned in
this article:
To summarize: "Karen," Aaron's teacher, found him discussing and
distributing copies of the Linux computer operating system, and
responded by confiscating said copies and making outlandish and
factually incorrect claims concerning computer software in general,
Linux in particular, and the legality of distributing same.  I urge you
to familiarize yourself not only with the details of the article above,
but with the facts concerning the Linux operating system and Free
Software in general:

Before I continue, I'll inform you of my qualifications and experience
in this matter: I am not at all affiliated with Aaron, Ken Starks, or
HeliOS Solutions; I hold a Master's Degree in Electrical Engineering and
Computer Science from the Massachusetts Institute of Technology; I write
Free Software, both as hobby and at times in the past professionally; I
am an avid Linux user nearly to the exclusion of all Microsoft products,
personally and on behalf of my employer---I am a Senior Integrated
Circuit Designer at Silicon Laboratories here in Austin; and like Aaron
I have experienced oppressive ignorance at the hands of primary-school

I shall not bore you by fully deconstructing Karen's claims concerning
computer software.  However, please note the following:
        - Dissemination of Linux and related software at no cost is
          completely legal.  There are many organizations whose purpose
          is to package Linux in a user-friendly way and distribute it
          for free:
                et alia
        - Most Linux-related software is distributed at no cost under a
          software license called the GNU General Public License, which
          requires distribution of human readable source code along with
          the software. For students who are learning about computers
          and programming, being able to examine and experiment upon the
          code underlying a piece of software is of paramount
          importance; thus, Linux and Free Software in general are
          superlative learning aids.
        - The claim that "no software is free" is so incorrect as to
          verge on frightening.  Linux and related software have become
          pervasive to the point where they are used in everything from
          cellular telephones and computer networking infrastructure to
          video game systems and vending machines---precisely because
          the software and source code are available at no cost.
        - Karen's claim that she "tried Linux during college" is
          dubious; more to the point, it's apparent that if she did so,
          she certainly didn't learn anything from the experience!  As a
          seasoned Linux user, the notion that Linux conveys a
          disadvantage is amusingly parochial (especially in light of
          the wide variety of applications in which it is being used).
          That Karen believes this is the case is evidence that she has
          already been surpassed in computer knowledge by her student---
          and doubtless this gap will only grow as Aaron continues to
          use Linux.

In light of the above, I strongly urge you to intervene on Aaron's
behalf; moreover, if necessary I will happily testify in this matter.
That your teachers are misinformed about matters beyond their ken is
hardly surprising; that they would overstep so far as to discipline a
student, confiscate his property, and engage in calumny as a result is

Thank you for your time,


Bets on whether I get a response?

Tue, 25 Nov 2008
heavy irony

Today I stole a book on ethics.