Unity? How about no?

So...Unity. I gave it a serious try. I really did. I used it for several weeks, starting during the tail end of the Ubuntu 11.10 development cycle. I liked it at first. It was shiny and new (to me at least). Unfortunately, a number of relatively small but incredibly irritating annoyances began to nibble at my shins.

For one thing, it can't seem to get focus changes right. With the new global menu bar, this is a recipe for disaster. On a few occasions, I have ended up quitting the wrong application because I thought one window had focus when really a different one did. They both had a "Quit" entry in their "File" menus, though, so I didn't notice my mistake until the wrong application closed.

Probably more annoying, though, is that Unity and virtual desktops get along like Germany and France. Alt-Tab takes you back to the last window that had focus, regardless of which desktop is currently active. That makes switching between a few windows on desktop A and a few windows on desktop B an exercise in frustration.

Alt-Tab also handles multiple windows for one application in an incredibly obnoxious manner. Essentially, Alt-Tab switches at the level of applications. If you simply Alt-Tab to the application you want, you get the last window from that application that had focus. If you want a different window from that same application, you have to wait a bit. It takes a second or less, but then I want to do something with a different window, I don't want to wait. It's especially annoying if you keep switching back and forth between application A and application B, and application B has more than one window, and sometimes you want one window and sometimes you want the other.

For example, application A might be an IDE, and application B might be a web browser. You are writing code in the IDE and have some documentation for API X open one window of the web browser and documentation for API Y in another window of the web browser. You can't just put them in the same window, because you often have several tabs open for various pages in the documentation, and putting the two together in the same window would mean navigating a horrible mess of tabs. As long as you only work with one API at a time, this is fine. That is rarely the case. Thus, looking something up often takes an extra second. This gets very annoying very quickly.

I suppose these issues would not be as problematic for people who don't use virtual desktops or multiple application windows. I can see it being relatively painless on a netbook that is primarily used for web browsing. Of course, on that machine, you switch between tabs in the browser more often than between applications or windows, so Unity wouldn't have much opportunity to impress or annoy you...

I've always preferred KDE over GNOME, and Unity has completely failed to change my mind. The machine that ran Unity now runs KDE instead.

sudo aptitude purge unity
sudo aptitude install kubuntu-desktop

loops and anonymous methods in C#

Time for another C# post. I won't call this one a WTF, but it doesn't really sit well with me, either.

List<SomeHandler> handlers = new List<SomeHandler>();

for (int i = 0; i < 10; i++)
{
    handlers.Add(new SomeHandler(delegate()
    {
        Console.WriteLine(i);
    }));
}

foreach (SomeHandler h in handlers) {
    h();
}

What would you expect the output of the above code to be? Something like the following, right?

0
1
2
3
4
5
6
7
8
9

WRONG! What you actually get is this:

10
10
10
10
10
10
10
10
10
10

Huh? Why is that? To understand why this happens, you need to understand how anonymous methods work in C#. You see, these "anonymous methods" in C# are actually more than that; they are closures. The body of an anonymous method can reference any variable in the scope in which it is defined, even if that variable is not defined in the scope in which the anonymous method is executed. That's why the anonymous methods we created above can reference the variable i. See that word? "Reference"? The anonymous methods contain references to i. Thus, each anonymous method has a reference to the same memory location, which the termination of the loop left at 10.

Why references? In short, it's the difference between a simple anonymous method and a closure. We need references in order for the following code to work.

class SomeForm : Form
{
    private int numberOfClicks = 0;
    private Button button;
    private Button otherButton;

    public SomeForm()
    {
        //Blah blah setup controls blah blah

        button.Click += delegate(object sender, EventArgs e)
        {
            numberOfClicks++;
        };
    }

    public int NumberOfClicks
    {
        get { return numberOfClicks; }
    }
}

The intent is that the numberOfClicks variable be incremented whenever the button is clicked so that we can keep track of how many times the button has been clicked over the course of the program's execution. If the anonymous method didn't have a reference to the same memory location referenced by numberOfClicks everywhere else in the class, then the NumberOfClicks property would always return 0. Clearly, though, there are times when you don't really want that. How would you change the code at the top so that it outputs 0 through 9? Like this:

List<SomeHandler> handlers = new List<SomeHandler>();

for (int i = 0; i < 10; i++)
{
    int value = i;
    handlers.Add(new SomeHandler(delegate()
    {
        Console.WriteLine(value);
    }));
}

foreach (SomeHandler h in handlers) {
    h();
}

Why does this work when the original version didn't? The variable value is defined inside the loop. That means that it is effectively a new variable in each loop iteration, so each anonymous method has a reference to a different memory location.

This is not a WTF because it makes sense if you think about it, and the argument against it isn't obvious (at least an informed argument; an uninformed argument is always easy to make). I still don't like it, though, since it violates the principle of least surprise. In the case of a for loop, it probably doesn't make sense to have the compiler automatically slip that int value = i in there, since in some cases, that's not what the user wants. However, I would argue that it does make sense in a foreach loop. In a for loop, you can define the variable being operated on completely outside of the loop construct. Heck, you don't even need to operate on a variable! for(;;) is a perfectly valid for loop. foreach is different, though. You must declare the variable in the foreach loop construct. There is no way to reference that variable outside of the loop except through anonymous methods. In fact, one can simulate the following foreach loop

foreach (double value in list)
{
    DoSomething(value);
}

like this:

for (int i = 0; i < list.Count; i++)
{
    double value = list[i];
    DoSomething(value);
}

The first construct will exhibit the problem; the second will not. Thus, it can come as a surprise when all of the anonymous methods have a reference to the same memory location. Yet another case where C# (like Java) neglecting to properly distinguish between values and references ends up confusing people.

That said, I only got burned by this once (arguably twice, but the real problem the second time was lack of comments to explain the seemingly useless variable creation), and I only ended up using anonymous methods because I was abusing an API. In the new version of the code now under development, I avoid using anonymous methods at all because I don't abuse the API.

TL;DR: don't use an anonymous method if it doesn't make the code significantly cleaner, and if you do use one, be careful with it.

A Pearl of Wisdom From snoofle

It's the tools in the chairs, not the ones on the disk, that cause the problems.

Courtesy of snoofle, a regular in the Side Bar WTF forum of The Daily WTF. A nice, punchy description of an uncomfortable truth: the human part of a system is often its weakest link.

Virtual Machine Routing

Suppose you have some virtual machines hosted by Linux KVM that you want to be able to access from other computers. For example, you want to be able to type "http://vmname/" in your web browser and access the web site hosted on that virtual machine. How do you do this?

Note: if you configure the virtual network to use DHCP, you might be able to avoid setting up separate DNS and DHCP servers, but I don't know for sure because I didn't try it. I wanted the extra control available when running separate servers.

First of all, you need to set up a DNS server to map the names to the IP addresses. A good resource for this is the Ubuntu Community Documentation on BIND9. You may need to configure the DNS server to forward requests for hostnames it doesn't know about to upstream DNS servers. The documentation refers to this as a hybrid primary master and caching configuration. Note that this DNS server will need a static IP address. If your router runs DD-WRT, this is quite easy to do in the "Services" tab.

Next, you will need to either manually set the IP address on the virtual machine or set up a DHCP server to assign the IP address. If you do the latter, you will need to assign the virtual machine a static IP address. Some good resources for this are the Ubuntu Community Documentation on dhcp3-server and the man page for dhcpd.conf. Make sure to configure the DHCP server to specify the new DNS server as the one for clients to use.

Now all you need to do is configure the host machine's kernel to route packets. You know how to use iptables, right? No? Have no fear! All you need to do is fire up virt-manager, right-click the host machine, click "Details", go to the "Virtual Networks" tab, and configure a routed network! If you replace the default network and give the new one the same name, you won't have to reconfigure any of your virtual machines. I was very impressed by how easy this was.

Lastly, if you have an existing router, you will need to add a static route for the host machine. I use DD-WRT for my router, and this was quite easy to do (Setup->Advanced Routing). I was also able to configure DNSMasq to forward specific DNS requests to the new DNS server by adding "server=/<subdomain name>/<DNS server IP address>" to the "Additional DNSMasq Options" box in the "Services" tab, so I didn't have to recofigure DNS on all of my other machines.

Configuration files for dhcp3-server and BIND9 are available here. Please take the time to understand what they do before using them.

Once the above is set up, adding support for a new virtual machine is as simple as adding entries for it to the DHCP and DNS servers. This is quite convenient for testing web applications, as you can simply set up a new virtual machine, install the web app's dependencies, and test it, all without cluttering up a real machine with a special version of Ruby, a handful of Ruby Gems, or whatever it is that the web app needs. Once you're done, just delete the VM!

Mass Effect 2

I've been playing Mass Effect and Mass Effect 2 a lot lately, so I felt I might as well post a review of them. I guess it's more of a retrospective, but whatever. For reference, I played both games on the PC, like God intended.

I played Mass Effect 2 first, so I'll start with that one. I will try to get through this review without comparing it to the previous game, since that discussion warrants its own post.

Mass Effect 2 is a shooter-RPG that follows the exploits of Commander Shepard, a human soldier who lives just a few decades after humanity makes first contact with aliens. His actions in the first game have made him a hero (possibly a widely-hated hero, but a hero nonetheless). Of course, a new enemy soon rears its ugly head, and Shepard must again lead a team of humans and aliens against impossible odds in order to save the galaxy.

As tends to be the case with BioWare games, the story is quite well-written, as is the dialogue. The climax of the story really feels like the climax of a story should. No disappointing ending here. The characters are fairly compelling, if somewhat formulaic. It seems all but two have some sort of tragic past, which is about as common in BioWare games as lutefisk in Minnesota (which is to say, enough to be cause for concern). One of the most memorable characters is the ship's pilot, Joker. He's an arrogant jerk, but he expresses his arrogance and general abrasiveness in a very entertaining way. He offers commentary on the other characters after you recruit them and will offer further commentary after you take them out on missions.

The characters in the player's party have well-defined personalities and well-written dialog, along with interesting and varied costumes. The strange part, though, is that these characters wear the same costumes when out on a mission. It's a little strange to have a woman in a catsuit going toe-to-toe with fully-armored mercenaries. What's even stranger is the downright bizarre choices of environmental protection that they wear in areas with no atmosphere or a hostile atmosphere. I don't care how genetically-modified that lady is; don't tell me her eyes can withstand total vacuum or concentrated chlorine gas. That's just bullshit. Oddly enough, the krogan character (a member of a legendarily tough race) wears a full helmet in such environments.

As for gameplay, it's solid. The combat and NPC interaction systems generally work smoothly. The space bar is a tad overworked, though. Off the top of my head, I can think of four things it does: 1. Take cover 2. Activate object 3. Vault over low wall 4. Sprint Oddly, the shift key (used for sprinting in most shooter games) is used to pause the game and bring up a menu for switching weapons, using powers, and giving orders to your team.

Combat is fairly standard cover-based shooting. The tech and biotic (aka space magic) powers help it rise above simple "knucklehead A taking potshots at knucklehead B from behind a chest-high wall." The heavy weapons are satisfying, and it's fairly obvious which enemies warrant their use. Ammunition for such weapons is rare enough to dissuade their use against dime-a-dozen mercenary idiots, but common enough that you probably won't ever find yourself up against a powerful enemy without enough ammo. The M-920 Cain does throw this off a bit, since a weapon that only has enough ammunition for one shot (maybe two if you get enough of the right upgrades) necessarily changes the economics of its use.

Interacting with NPCs is a step above the ordinary. You still have a standard dialog tree, but the options are arranged on a wheel, with three on the left and three on the right. Generally speaking, the options on top are the "nice guy" options, the options on the bottom are the "jerk" options, the middle option on the left is for more information, and the middle option on the right is a neutral response. The options on the top left and bottom left typically require Shepard to have a certain number of paragon or renegade points. Paragon and renegade points are obtained by choosing the "nice guy" or "jerk" options (most of the time; sometimes you don't get points either way). Extra paragon and renegade points can be obtained via paragon and renegade interrupts. These are indicated by blue or red icons that appear on the screen at certain points during certain interactions. Paragon interrupts often take the form of assisting someone, while renegade interrupts tend to involve gratuitous violence. Paragon and renegade points form a sort of morality system, but not quite like what you find in, say, Knights of the Old Republic. It's a given that Commander Shepard will save the galaxy; it's just a question of what the price will be. As the inimitable Ben "Yahtzee" Croshaw put it, the paragon vs renegade choice determines whether Shepard takes after Captain Picard or Dirty Harry. That said, going pure renegade results in a Shepard who is an utterly heartless asshole.

In terms of environments, there are really only two types: a few twisty hallways without enemies (i.e. the settled areas you can visit) and a single really long twisty hall with an offshoot here and there and enemies all over the place (i.e. the actual mission areas). It feels somewhat constrained, but it does help maintain focus. Free roaming is only possible in space, where you can fly your starship more or less anywhere. Flying around inside a star system costs nothing, and going from one star cluster to another is done via mass relay, which also costs nothing. Flying between stars in a cluster, on the other hand, burns fuel, which costs money to replenish. While this isn't a deal-breaker, it is a bit annoying, and it does kill a bit of the fun of exploring.

The circuit bypass and hacking minigames are enough of a challenge to be exciting without being a burden. That said, the fact that a pure soldier is just as effective at these tasks as an engineer detracts a bit from the sense of difference between the character classes. It's not to the point that choosing a character class feels irrelevant, but it does rub me the wrong way.

Upgrades to weapons and armor are (mainly) obtained via research. Research uses minerals. How do you obtain minerals? Well, you will sometimes find refined minerals lying around when you are on a mission. These minerals will get you one or two weapon upgrades over the course of the entire game. If you want some serious upgrades (some of which are needed in order to obtain the best ending), you will need to mine them. This is done by rubbing a scanner all over a planet and firing probes when the clicky sound gets loud and rapid enough, and it's about as fun as it sounds. If I wanted to rub something all over something and poke at it, I'd go detail my car. On the plus side, you tend to get a fairly large amount of minerals back with every probe (if you aim properly, which isn't hard), so it's not /that/ obnoxious. It's still annoying enough that I don't do it unless I have to (either because I need an upgrade or because my completionist OCD finally gets the better of me and I feel compelled to strip-mine a planet in the most boring way possible). This is a case where character class can make a big difference: the Engineer class can get a discount on research. Having to do 25% less planet scanning is rather nice. Some upgrades can be purchased. They tend to be fairly expensive.

Character levelling is fairly rewarding, if somewhat disappointingly rare. Each skill has four levels, with the first costing 1 point, the second costing 2 points, the third costing 3 points, and the fourth costing 4 points. Since you get two points every time you gain a level, you can boost your skills fairly quickly. However, the infrequent levelling means that you may very well enter the endgame two points away from a level 4 skill, which is particularly disappointing, since reaching level 4 in a skill lets you choose between two substantially improved versions. Even more aggravating is that you may have completed several missions without obtaining those last two skill points. Going to the trouble of playing through a mission to storm a mercenary base or something only to receive a mere 7500 credits (only 10% of the biotic power upgrade you're saving up for), 2000 units of palladium (the most common mineral), and a downright miserly 156 experience points is a bit disappointing. Sure, playing the mission was fun, but this is an RPG. You're supposed to get stuff after a mission. At least missions directly related to the story reliably provide level-ups.

Stock Mass Effect 2 is fairly stable (installing DLC seems to change this, unfortunately). However, the physics engine is an evil bastard that will glitch out in the worst way at the worst time. Stepped in the wrong place? Now Shepard is hovering in the air, able to move only a few feet in any direction. If you're really, really lucky, you can reach some sort of elevated ground and regain your footing. More likely, though, you will simply have to load your most recent save. To make matters worse, this happens most reliably during a mission in which there are ZERO opportunities to save. The Cerberus Network DLC (stuff you get for free if you bought the game in a physical store at the right time) seems to be fairly safe, but after installing Arrival, Stolen Memory, and Lair of the Shadow Broker, the game has become far more unstable, frequently crashing at inopportune times. To add insult to...um...insult, Arrival includes a dumpster (something you might want to take cover behind) that can cause the floating-in-midair bug if touched. FAIL.

There is one aspect of one DLC that I particularly feel the need to call out: the star system added by Stolen Memory. There are two things wrong with it. First of all, the system is identified as being one of the first settled by humanity, but it's right by the Citadel. You don't even have to go through a mass relay to get to it. Don't tell me the other races who have been on the Citadel for millenia never noticed it. Furthermore, the fact that you don't have to go through a mass relay to get to it stands in stark contrast to an established fact about the Citadel: it is surrounded by a nebula of abrasive dust that ensures that the mass relay is the ONLY way to reach it. These things don't detract from gameplay, but they give the game's universe a slightly schizophrenic feel.

You'll notice that I haven't mentioned the graphics yet. That's because graphics are generally not worth mentioning these days unless there's a problem. Mass Effect 2 looks nice, largely avoiding the "brown, brown, and more brown with a bit of grey" color scheme that plagues modern shooters. The fact that many enemies are mercenaries wearing brightly-colored uniforms helps in this regard.

All in all, Mass Effect 2 is a good game. I would recommend buying it (not enthusiastically, mind you) unless you are boycotting EA (I don't blame you if you are). If you liked Mass Effect, at least give Mass Effect 2 a try.

ncd extractor announcement

I recently encountered a music album from OverClocked Remix that contained cover art in Nero CoverDesigner files (file extension .ncd). I couldn't find an open-source Linux program to open these files, so I took a look in a hex editor. Much to my surprise, I found that the contained several sets of plain old PNG data. Thus, I present ncd-extractor. It's a very stupid simple program that extracts all PNG images from a NCD file, saving them as <name of NCD file>.X.png, where X is the number of the image. I provide it with no warranties or guarantees (in fact, I'm pretty sure there are bugs in it; my C is a bit rusty). It is licensed under the GNU GPL v3. Patches are welcome. Where to send them? Well, my name is Alex, and you can see my domain name in your browser's address bar...figure it out. I'll probably put it up on Gitorious at some point; that will make contributing easier.

Windows: Whether You Want it or Not

Originally posted: 2010-05-27

Suppose you want a computer. Suppose you don't want Microsoft Windows. Here are your choices among the major vendors: Apple and Dell. Of course, Dell won't tell you that you have a choice. Among the minor vendors, there are only really two choices: System76 and Zareason. Sure, there are others, but they either seem cater to scientific institutions or they have bad websites (some won't even let you order online).

Why am I so pissed off about this? I don't want Windows. I find Microsoft's business practices disgusting and morally offensive. Apple isn't much better (one could argue, in fact, that they are worse). I would rather like to have a Thinkpad, as the hardware seems to be quite nice, but I don't want to buy Windows and I don't want to jump through hoops to get a refund for it. I just want the damn hardware. A blank hard disk suits me just fine.

Why, then is the computer market in such a deplorable condition? There are a couple reasons. One is that Microsoft gives OEMs better prices if they only sell machines with Windows or if they sell no more than a certain quantity of computers without Windows. Because so many people are stuck with Microsoft products, getting a lower price for Windows confers substantial market advantage, especially as hardware prices continue to drop. One of the excuses Microsoft gives for this behavior is that it supposedly discourages unauthorized copying of Windows. According to Microsoft, if Lenovo and Dell offered computers with blank hard disks and no Windows licenses, multitudes of customers would then purchase those machines and install unauthorized copies of Windows on them. They then state that the Windows product activation system prevents people from using unauthorized copies. Which of those statements is true, Microsoft? Really, this is all about not giving the customer a choice.

Another reason is crapware. Crapware is software (usually trial versions or software that requires a subscription-based service) that the OEMs are paid to install. The hope is that people will try the trial versions (or trial subscription) and then buy the full version. Because the OEM is paid to install this software, the effective cost of Windows is substantially lower than it otherwise would be. Unfortunately, many customers do not like crapware (hence the name). For them, it does not have any value, so in effect, the price of Windows is higher for the customer than for the vendor. So, when the customer exercises his rights as guaranteed by the Windows EULA and common anti-bundling laws, he often receives very little money in exchange for Windows.

It then stands to reason that the OEMs should offer computers with a crapware-laden Linux distribution preinstalled. After all, they can get Linux for free, so they should come out ahead in the end. However, this will not work for a number of reasons. First of all, many (perhaps even most) of the people who would purchase these machines initially do not like crapware. Many of them would probably replace the OEM's installation of Linux with a clean one. Since putting crapware on a Linux machine is unlikely to lead to increased sales, the tactic would fail. Furthermore, most crapware only runs on Windows, and the OEMs would have a hard time convincing its producers to port it to Linux. Lastly, it is very easy to install lots of open-source software on Linux machines, so Linux users tend to try open-source alternatives before purchasing closed-source software, and open-source alternatives are frequently good enough for the user's needs or superior to the closed-source software. Hence, the OEMs stick with Windows.

What can we do about this? I think this is a case in which the government legitimately needs to step in. There should be a law stating that any computer sold with software must also be available without software. That is, Lenovo should be legally obligated to offer me a Thinkpad with a blank hard disk and no Windows license. That would make it substantially easier to vote with one's wallet on operating systems. Microsoft likes to point to their huge market share as evidence of their superiority, but it's easy to be number one when you ram your product down the public's throat.