blog.rupamsunyata.org

Decklin’s excuse for some blogging software. Est. 2006.

man ascii

I find myself opening a shell and typing "man ascii" more than I would like. More recently, I've found myself looking (with no success) for a equivalent web page that isn't ugly -- sometimes a browser tab is just more convenient.

Yesterday, I decided to stop searching and just write one myself: man ascii. (I was a bit surprised that this domain, and all the variants of it Joker came up with, were available!) I think it gives me everything I got out of ascii(7), but I would love any bug reports.

Artificial Intelligence

After a recent apt-get:

Fetched 1B in 0s (42B/s)

Well. That settles that question! :-)

Inside Out

I've been on Twitter for over a year and a half now. If I had to explain why I like it, and why it's so popular now, I would use an analogy:

Twitter : IRC :: Blogs : Usenet

(This applies equally to other "micro-blogging" services, but I am about to explain why I believe that's not the right metaphor. You may also substitute mailing lists for Usenet.)

With the older media, you have a place -- a newsgroup, or a channel, that people went to, with a distinct culture, and that (mostly) weren't "owned" by anyone, but rather by the community. With the new ones, we are all sole proprietors of our own streams, and we "tune in" to the subset of people we find interesting, rather than topics we invest in. So, instead of bumping into the same person in a couple different groups, or never reading their words at all, you might find that your feeds overlap a bit more than they do with most people. This is how I find people to "follow" and blogs to read, in fact -- as my network expands, more people become loosely joined to it, and as I notice ones worth reading I add them.

Is one model better than the other? Probably not. I could make an analogy to music. In theory, I'd rather read what my favorite critics have to say about a wide variety of new releases -- some of which I'd never know about otherwise -- than keep up with the discussion of bands and genres I really like, even if most people writing about them are terrible (remember, 90% of everything is crap). But I also lose that sense of community of being a "fan" of something; I no longer have a deep connection to what's going on in the fandom or the scene, which I also would never know about otherwise (some of it is just too obscure for my favorite writers to cover).

In practice, it seems the new approach has been more popular, but maybe that's because more people are on the net now, and both kinds of communication are/were shaped by the technology available at the time (destinations make much more sense with limited/centralized computing resources, and aggregation makes much more sense with powerful clients and a wider, less specialized user base).

Anyway. This post is not actually about social media theory or whatever you want to call it; it's about some software I have packaged.

Because of all the above, I have always wished that I could use Twitter from something more like my IRC client. Like, say, my IRC client. One could abuse the concepts of IRC to make an "on the fly" channel of whoever happens to be in my feed. (I once read a blog comment somewhere complaining that Twitter could easily be implemented on any existing IRC server using one +m channel for everyone and some client-side direction of messages from all such channels to a single window. +1 for cleverness, but they did sort of miss the point of why normal people sign up for web sites rather than installing and configuring clients for obscure chat protocols.)

So, I had grand plans to write a Twitter client which was an IRC server, with some clever mapping of IRC concepts and commands to their equivalents over there. I never got around to it, as I barely have enough time for anything I do now. But last month I noticed that someone else had implemented such a thing: tircd. I had seen Twitter/IRC services before, but like the official Twiter XMPP service, they were all implemented as bots, which I detest for this sort of application. Bitlbee, for example, translates various IM protocols to IRC, but only halfway -- for anything else you have to use a bot as a sort of poor man's command line. If I want a command line for Twitter, I already have several; IRC can do better. And tircd really does! It's great. You're not required to edit the config file, and there's no extra layer on top of IRC for things like logging in or adding people.

I've finally packaged the latest release, which is waiting in NEW currently. I got a request for sneak preview packages, so if you want to install some unapproved .debs check this repository.

I may still pick my own project back up, as Twitter itself, being a centralized service, feels like a stopgap solution on the way to to a more generalized 140-character equivalent of the, er, blogosphere as envisioned by open-source projects like Identi.ca. In the future, perhaps, when we use a certain micro-blogging "service" we might be randomly connected to one of any number of servers run by different individuals but all mirroring messages back and forth to each other. Which, now that I think of it, sounds vaguely like some obscure, obsolete chat and news-posting protocols I know.

Another Monopoly Rant

A cautionary tale: Verizon's DSL salespeople are completely incompetent.

Several weeks ago, I ordered residential service. I was unable to get the prequalification app on their web site to work for my address, so I called in. I was told (1) I could get a modem for free, and (2) that I didn't need to do anything for the install except plug it in -- they'd just be turning something on at the CO, perhaps even before the date my service was scheduled to begin.

These were both, of course, pure fiction. On the install date, while at work, I got a call from a tech who had shown up at my house to rewire something. Luckily, I was able to rendezvous with him later in the day. The service worked briefly and then went down. Over the next few days, I called in, was told to wait at home for 8 hours, no one showed up, I called in again, was told "oh, sorry, it's going to be tomorrow", waited all day the next day, no one showed up again... a week and two actual visits later, I finally had connectivity.

I can't really blame them for whatever the line problem was, but to repeatedly treat my time as worthless by making me wait at home for an entire day just in case a tech can get there, even though it's highly unlikely they will, is just offensive.

Then, I received my first bill and... was charged for the modem. Calling in again, I was told that the deal I was offered was for online orders only, and even if I specifically confirmed with the sales person that he could get me the same deal since the web site wouldn't let me complete an order (and I already had an old, power-sucking modem anyway), there was no way I could get a refund. So I got an RMA and planned to go shopping for a replacement (people are selling the same model on Craigslist for $10). The RMA came in an email which also told me that if I did not return the equipment within X days I would be charged $100.

This is all utter bullshit. Do not use Verizon. If your only other option is Comcast, as it is here, just steal your neighbor's wireless or tether your 3G.

They could have left me reasonably happy with the whole botched situation if they had provided a honest estimate of how long it would really take to get someone out (even if it was "days"), or given me access to the same information without having to go through a call center of people only trained to read a script about how to power-cycle your router or whatever. And if they actually apologized for a saleperson convincing me to sign up by lying about what I would be charged. But why would they? What are you going to do, switch to an ISP that treats you like a human being and doesn't fuck with your traffic? Ha. Ha ha ha. Good luck with that.

You're talking about things I haven't done yet

I've been converting all my Mercurial repositories to Git. One of the motivations for this was hg's poor handling of branches and tags: branches are just another metadata field on a commit, and tags are entries in a text file called .hgtags that is tracked in the repository(!). Git has its flaws as well, but I prefer its view that branches and tags are just refs, which are pointers that exist at the repository level and are pushed or pulled around in much the same way as the objects they refer to.

The excellent hg-to-git.py script included in contrib created Git tags corresponding to my old Mercurial tags, but of course didn't modify the actual commits. So I still had a .hgtags file in my Git repository, and a boilerplate commit of the form "Add tag foo for changeset bar" each time I added to it (recall that .hgtags is just another file. Thankfully, I never had to deal with two branches where I added different tags...). I wanted to remove these. Git has a 'filter-branch' command that can totally rewrite or expunge commits; this is of course a horrible idea for already published code, but there's no harm in using while initially preparing a repository.

While I appreciate git's object model and speed, I must agree with its detractors that the user interface is terrible. It took some tinkering to get git-filter-branch to do what I wanted, so I'm writing this to save my notes for next time (and in case someone else is searching for how to do this). Here's the command I arrived at:

git filter-branch \
    --tag-name-filter cat \
    --index-filter 'git update-index --remove .hgtags'
    --commit-filter \
        'if [ $# = 3 ] && git diff-tree --quiet $1 $3; then
             skip_commit "$@"
         else
             git commit-tree "$@"
         fi' \
    HEAD

The tag name filter is always necessary if you want tags to be updated to point to the corresponding commits on the new, rewritten branch. I consider this a UI failure -- when a branch is rewritten, the ref is modified, and the old one moved to refs/original. Tags, on the other hand, stay where they are, without any indication on the new branch that this is where you might want to move that old tag and sign it again or whatever. IMHO they ought to be handled the same as branches.

The index filter is simply an efficient way of removing the unwanted file from all commits. This and the tag filter are both covered in the manual page.

Writing a commit filter is a little more obscure. After .hgtags is removed from the index, we may end up at one of those useless "Added tag foo" commits and have no changes to record in the commit. By default, of course, filter-branch still records these -- the commit message might be useful, or something. But I want to suppress them.

The commit filter is called with a tree -- you're at the point between write-tree and commit-tree (I recommend Git from the bottom up if you're confused here.) It gets that tree ($1), and then "-p PARENT" for each parent, just like commit-tree. So, if this is a normal commit with one parent, there will be 3 arguments. (If there's only one argument, there is no parent, i.e., the first commit, and if there are more, then it's a merge.) This is the only case we want to mess with. If there are no changes between our tree and the parent's tree, then it's one of those no-op commits, and we can skip it (skip_commit, a shell function defined by filter-tree, uses some deep magic to hand us the original parent again next time).

I think diffing the index and the parent would work as well, but this seemed clearer. It still feels like a hack, so I'd love to hear from anyone who can suggest improvements. Since this is a special case, maybe it's better off being implemented in hg-to-git.py itself. There's always more than one way to do it.

Update: Teemu Likonen points out that the next version of Git (1.6.2, not yet in unstable) will have a --prune-empty option which makes this particular problem totally trivial. I am starting to get the feeling that the Git developers are all reading our minds... :-)

Film at 11

Managers are dicks.

(ObBookMeme: "What's hard is sorting the result list so that the good results show up near the top.")

(Something I am working on now that Njiiri has search, but who gives a fuck, right?)

A bit late, but still

Happy Armistice Day.

Generally, "deal with huge amounts of" means "identify the 98% you can ignore"

Hello America, I missed you

As we walked back toward Mass Ave to catch the bus last night, fresh from the euphoria of my friend Josef's election-night party, I thought about how fortunate we are to be here, now.

We cheered, we screamed, we sang the national anthem at the top of our lungs, popped champagne, and danced. I'm on some stranger's facebook somewhere, at the edge of a crowd of people smiling for what felt like the first time in years. I knew I'd remember, but I wanted to write something down. I'd been following along on Twitter all night, but I didn't know what to say when the good news finally came.

I thought about our friends in California, where Prop 8 looked like it was going to win. Despite how far we've come, it's likely three states are about to write discrimination into their laws or constitutions rather than out of them.

So I picked up my phone and just typed in, "charged." Everyone was excited, yes. I haven't felt electrified by the possibility of change like that in a very long time. But we also haven't automatically won change by changing our leaders. We have won a responsibility to make that change happen.

"Yes we did", we joked to each other, and I emailed to my parents in the morning. But no one actually meant, "yes we can win an election". That's just the starting line. Now, we are charged with making America better. We are charged with protecting the liberties of everyone. I wanted to remember that too.

That's why it matters that we won. Eight years from now, this could be a nation where the whole idea of "banning gay marriage" sounds as antiquated and offensive as segregated schools or not letting women vote. We have the ability to change our culture, nothing more. Mandates don't do that; people do. And yes, we can.

Tap that class

And now, something entirely impractical.

I picked up Beginning Ruby by Peter Cooper the other day to look for some teaching material. Flipping through, I came across a basic feature that had heretofore escaped my notice: the Struct class. If you want to use a class for nothing more than bundling together a few values, you can create a Struct instead of writing out initialize and attr_accessor yourself. The idiom is like this:

class Server < Struct.new(:host, :port, :password)
  def to_s
    port == 6600 ? host : "#{host}:#{port}"
  end
end

That particular one's from Njiiri (which may clue you in that it took me several months to get around to writing this post). For educational purposes, it's nice: you can point out how we give a name to a class (I've also tried to explain assignment as "naming" rather than "storing"), that there's an unnamed class (classes are also objects!), and overriding a method (which uses the dynamically defined stuff), without any boilerplate to get in the way.

So it's tempting to use this in a lesson. Unfortunately, Ruby is a little bit weird here, and you run into those distracting "practical" issues about the particular language you're working in. Your classes can't subclass Class, and thus you can't say Foo.new like you can Struct.new. Struct is actually implemented in C (or Java, or whatever's native). So you have to do some handwaving.

This is because the "metaclasses" we have in Ruby are implemented, so to speak, as singleton classes of objects (including class objects). I do not mean this as a criticism of Matz at all, but they seem like more of a serendipitous thing than an intentional design -- "hey, if we implement classes in this particular way, we get this sort of metaclassing automatically [1]." (The clearest explanation of why this is that I've found is in the first chapter of Advanced Rails by Brad Ediger.)

I wanted to be able to just subclass Class, rather than have all that fun power that we normally get to abuse in Ruby, only because I think this is the clearest way to explain the abstraction. Even I still have trouble describing singletons in plain English. Struct is intuitively a class of classes, and factors out similar/boring stuff -- a good practice. It could be an example of how to refactor some simple classes, if only we could follow it.

I decided to give up on the idea for my tutorial, but it kept me up at night. Ruby metaclasses clearly can do anything that the sort of Struct-like metaclasses I have in my mind -- "parametric" classes, if you will -- can do, and I can dynamically define just about anything; why not make it happen? We can instantiate Class itself, but the tool we have to shape that class is singleton methods. This can certainly be abstracted away. So, I whipped something up.

Before getting to it, though, let's visit a new construct in Ruby 1.9 and 1.8.7: Object#tap. Apart from the obvious debugging use described in its documentation, it makes it quite easy to factor out this pattern:

def gimme_a_thing
  thing = Thing.new
  thing.do_stuff_to_it
  thing
end

Into something closer to the style of functional or declarative programming:

def gimme_a_thing
  Thing.new.tap |thing|
    thing.do_stuff_to_it
  end
end

(Well, "do stuff" is obviously still procedural, but A for effort.)

Which one is "better" could probably be the subject of much debate, but: I really prefer the second one; even though it has exactly the same effect, it looks like "what" rather than "how" (something else I try to beat into impressionable young heads. :-)), which is I think easier to write tests for. I'm going to use it here, because it's shorter.

Now, Object#tap passes the object as an argument to the block; in our case, we are going to define a metaclass, so we want to work with self, instead. So we define a new version, class_tap -- by analogy with class_def, I suppose --- which class_evals the block rather than simply evaluating it:

class Class
  def class_tap(&blk)
    tap {|_self| _self.class_eval &blk }
  end
end

And to do the following trickery, we make use of MetAid, written by why the lucky stiff -- it's very small, so we could always just incorporate the bits we want into the code here, but this short file provides a common vocabulary for talking about metaclass stuff which is quite valuable.

Now, we can write a method to create our new classes on the fly. Here's what I came up with:

require 'metaid'

class << Class
  def meta(_super=Object, &blk)
    new.class_tap do                     # 1
      meta_def :new do |*args|           # 2
        Class.new(_super).class_tap do   # 3
          class_exec *args, &blk         # 4
        end
      end
    end
  end
end

(Note the "class << Class", opening the singleton, rather than "class Class", opening Class itself. Also, the distinction between new and Class.new -- they are the same method, but from inside the meta_def we're no longer in the Class class.) The lines of meta itself mean:

  1. The value of this thing is a generated class, which we will describe thusly:
  2. Its singleton class has a new method, which gives you a value that is:
  3. Another generated class, which is defined by:
  4. the original block, which now gets run with new's arguments.

Nary an assignment in sight!

The (embarrassing) caveat is that methods in the block that defines the new class instance cannot use def to create methods as normal. A def is evaluated in a totally fresh scope (I don't think I get the opinion behind this decision, to be honest), so we need to use class_def instead. This is, I must admit, rather hideous. Perhaps someday the language will change.

But, first things first: now we can implement Struct in pure Ruby.

class MyStruct < Class.meta \
  do |*args|
    attr_accessor *args
    class_def :initialize do |*instance_args|
      args.zip(instance_args).each do |attr, val|
        instance_variable_set :"@#{attr}", val
      end
    end
  end
end

The real Struct class does a few other nice things for you, but this is the heart of it; I can go back to that Njiiri example and just swap in MyStruct for Struct (Providing an instant performance gain of -200%... :-)).

Here's a "shapes" example from my abandoned OO lesson:

class Polygon < Struct.new(:sides)
  def perimeter
    @sides.inject(&:+)
  end
end

class RegularPolygonClass < Class.meta(Polygon) \
  do |n_sides|
    class_def :initialize do |side_length|
      @sides = [side_length] * n_sides
    end
    class_def :area do
      @sides.size * @sides.first**2 / Math.tan(Math::PI / @sides.size) / 4
    end
  end
end

class Square < RegularPolygonClass.new(4); end
class Pentagon < RegularPolygonClass.new(5); end

(Note that area has no free variables and thus could actually be defined with def. It would just look funny.)

You only have to change one number here to make new polygon classes, rather than accumulating parameter lint or explicitly subclassing and redefining something implicit just for the derived class [2]. In a way it the exact analogue of the imperative vs. tap style described above. There is quite a bit of aesthetics involved; one way is not "right".

Apart from the syntactical wart, I like being able to do things this way. Ruby is, as they say, optimized for programmer happiness and the principle of least surprise. Still, I'm sure it is quite slow, and I don't particularly need it for any real-world application right now. For an intro to OO it's way too much complexity to have lurking unexplained beneath the surface and still requires getting bogged down in the language you happen to be using. But hey! It's neat.

[1]I basically try to do this whenever possible, anyway. Design decisions are like sex: they're better when they're free.
[2]Of course, if Ruby class variables were not leaked across the entire inheritance hierarchy, something as trivial as this one-variable example would be... trivial. At least, few people would actually miss metaprogramming features. Blub blub blub.

Pumpkins for Obama

http://www.rupamsunyata.org/decklin/photos/2008-10-30/pumpkins-for-obama.jpg

So basically, my girlfriend and I are huge geeks.

A long-overdue explanation

Regarding that last post. I received the list via email from Alan Sondheim earlier in the week, and felt like putting up a link to it. No particular reason; it seemed appropriate for one of those sui-generis enigmatic tumblelog things. I was disappointed to find that none of the mailing lists where I might have been able to find it had public archives. (One way of dealing with people who complain about spammers harvesting their address, I suppose...)

So, I said to myself, I've got 8+ years of this guy's email work, I'd like to share it with the world, and I have Mnemosyne, which I had always thought, in the back of my mind, would be a neat way to archive email written as email rather than written as a "blog". So, a little hacking later... The Alan Sondheim Mail Archive (Warning: some parts are NSFW). It has already given me some ideas for improving the example templates; I'll release 0.12 soon with the changes I had to make to get this running. (Final tally: 4500 messages, 75 seconds from a clean htdocs, 12 to no-op. On whatever the cheapest Linode [1] [2] is. Eh. I can do better.)

[1]Incidentally: Linode has been great. Highly recommended.
[2]Also: yeah, I know my footnotes are broken. Working on it.

Some Events in New York City in 1902

We could customer care less

(And now, a cathartic "I hate this company and I am never patronizing them again, please don't either" post. I should have done ones for at least Speakeasy/Covad and IBM's server division last year. Ah well.)

I went to go register a new domain yesterday (announcement soon! Probably this weekend). I've been using Joker for a while, IIRC on the principle that the cooks were using it so it must be decent enough. While registering, I had a bunch of problems with the horrid, useless "Verified by Visa" popup [1] that you see everywhere these days, and eventually this must have looked like suspicious activity to the bank so my card was declined.

I only actually found this out when I got mail saying my order was canceled. Okay, sure. I wrote back and explained what I thought was going on and that I'd like to resolve it. Another half hour later, I got this response:

Hello,

please use
   https://joker.com/goto/support/
for all support inquiries.

Regards, your Joker.com team

This is complete and utter bullshit [2]. If a company is going to mail me, I expect to be able to mail them. I have a mail client; it manages communication the way I want it to, and runs my preferred editor to compose messages (which is, in fact, how I am writing this very blog post). I am sick of dicking around on JavaScript-requiring web forms that all work differently and typing in postage-stamp-sized little textareas. Anything I do type in them is lost, because unlike my email client, web forms don't save sent messages unless the authors feel like letting you have a Cc:. When a company forces me to do this, I take it as a sign of disrespect. I tolerate a web browser [3] for reading pages; "applications" are universally painful [4].

One of the things I used to like about Joker was the PGP mail interface. AFAIK, they have not killed it (I didn't bother to check), but with automatic "we don't want to listen to you unless you inconvenience yourself" bounces like this, what's the point? I surmise that there is, or was, some smart person there who understood how (and more to the point, why) to hook a pseudo-mailbox up to a software system, and that they have been overridden by someone in management who realized it's much easier to have dime-a-dozen webmonkeys hook a form up to the same system since 90% of users just don't care (and even people who do notice and dislike this, but are not as inflamed as I, have come to expect it because everyone else refuses mail, so, y'know, pick yr battles son, etc.). Not the sort of culture I put faith my in.

The irony of it all was that I was registering this domain to run a service I had decided to create specifically because of another site refusing mail and directing me to an even lamer web form. That would take incoming mail and, you know... process it with software.

Suffice it to say, I am no longer going to be their customer. In deciding who to use instead, I figured I'd do a survey of where the domains in that "Subscription" column [5] on Planet Debian were registered, but... WHOIS is basically useless. Every server just returns free text, formatted differently by (apparently) every implementation under the sun. Cheaply parsing something out from .com/.org/.net is possible, but InterNIC kindly blacklists your IP after making more than a few requests in a few minutes. I guess I'm just gonna go with Gandi (but other suggestions would be welcome).

In somewhat unrelated developments, I went to nic.at to update my nameservers for Where the Bus At? last week. There was no authentication or anything on the request form, so I just filled it in and sent it off. I got some automatic mail saying I need to print out a PDF, sign it, and fax it internationally. Annoying, and hardly as secure as mailing them with PGP, but whatever. But then, also yesterday, I got another mail saying the update was complete (lo and behold, it was). I am now somewhat concerned about the security of my domain: it seems like anyone can come by and put something in the form and if I'm not around to notice the courtesy mail and ask that they stop the request, it'll eventually go through, no questions asked. I have not yet written them to figure out what the deal is, though. Kinda burned out.

I guess I didn't really have high hopes for dealing directly with a ccTLD registrar (this was the first time I've done it... I can't believe I blew €60 on a cutesy domain name) rather than a reseller who competes in a market, but then, I go and google "domain registrar" and look at all the AdWords dollars spent trying to compete with GoDaddy [6] and just kind of want to put my head in my hands. On DJB's DNS pages there's this bit about setting up a domain. It doesn't say "How to (buy|register|whatever) a domain name". It says, "How to receive a delegation from .com". Which is of course, how it works. And what I want to buy. I don't want "parking" or even gratis nameservers. Just a delegation from .com. Please.

No AdWords came up when I googled for that phrase to copy the link. Sometimes I guess markets just sink to the bottom.

Anyway. I feel like there's a free-software angle here. My continuing irrational hatred of using other people's forms, web-based mailing-list substitutes, nameservers, etc. stems not so much from their suckage but from the fact that there is no longer any software there, in front of me, for the four freedoms to possibly apply to. Being able to run your mail reader for any purpose doesn't win you much if no one uses mail. I don't really know what to do about this.

[1]It was only twelve dollars! If I go to hipster market or some other place with brand-new POS systems they don't even make me sign a paper slip for less than $20 or so. But this is the sort of thing dreamed up by people who think good security is setting a cookie to denote that I've answered "what was your first dog's name" or whatever. IF YOU WANT TO BREAK INTO MY BANK ACCOUNTS: I've set the answer to every single one of these questions to "security theater". Easy to remember.
[2]Not to mention a glaringly RESTless URI.
[3]Also, as a rule I normally try not to have anything up on my desktop that I can't close and re-open at any time, thanks to screen, MPD, emacsclient, actually using my browser's bookmark function and resisting the lure of tab-bar.js, etc. Web browsers are supposed to suck at preserving state; HTTP is stateless. See also here (and for further reading on that in the Haskell world, check out Yi. I'm hoping to switch to it someday).
[4]Debbugs, for example, may not have the slickest interface, but if I want to do flags, labels, archiving, threading, or whatever, I can; I'm not at the mercy of some front-end web developer. But we've all heard this litany before.
[5]Thanks, Hpricot!
[6]Even if GoDaddy's customer service were completely hacker-friendly, I would not use them, because their president Hates America.

And yet I swear this oath

There was a lot of political talk last week in the US about this guy "Joe the Plumber". I'm really quite mystified by the (lack of) Democratic response to this one; it seems like a perfect opportunity for the Dems to explain what their ideals actually mean, after years of complete inarticulacy.

The Republican party, and conservatives in general, have somehow successfully sold their platform of, as Robert Reich brilliantly put it on the Daily Show last week, "socialism for the rich and capitalism for everyone else", to poor but socially-conservative citizens for quite some time. They've convinced people to vote against their economic self-interest, and cut taxes on the rich instead of themselves.

Is voting for policies that directly benefit you less necessarily bad? I don't think so. In many cases, selflessness and altruism are better in the long run. Conservative economic policies speak to a sense of right and wrong that give people a feeling of purpose, and so an incentive to create: this is mine, I made it, you can't take it away. In a theoretical sense, leaving more wealth in the hands of the rich should "trickle down" to society in general, by providing more capital, and thus creating jobs, etc.

However, I do not believe that this is why Americans, specifically, tend to support conservative economic policy. The USA has this idea of the "American Dream", pulling yourself up by your bootstraps, if you will, and striking it rich through hard work and character. It's advantageous for conservatives to sell this idea because it makes people think "tax the rich? What if I get rich?", which is a sort of enlightened self-interest, arguably. And it gets poor people to vote for them.

What makes this "plumber" thing interesting to me is that is should demonstrate where this approach ought to fall down, logically and emotionally. But it does not. Here is the problem.

A working stiff who earns "five figures", such as myself, generally makes that money by going to an employer every day, performing some services for them, and then drawing a paycheck. Where this money comes from is abstracted away (this is the marvelous thing we call "business"). Let's say you want to sell the "American Dream" to this person. They get their paycheck every week, and there's a chunk taken out of it by Uncle Sam. Maybe they're saving up to start a business, or go to college, etc. They sure could do it faster if taxes weren't so high. So you remind them this: when you do strike it rich (since this is America, where anyone can strike it rich), do you want those taxes to be even greater?

This story contains a lie of omission, probably the greatest lie ever told in US politics, and one that has almost universally succeeded as far back as I can remember. And that is: when you do make that jump to where our hypothetical Joe is, making just over a quarter-million dollars, that it's not going to look any different. You'll get your paycheck from some abstracted source, just like before, but more will be taken out unless we stop raising taxes on those higher income brackets. There will be some node higher up in the tree for that wealth to "trickle down" from; you could say it's implied, even, that wealth is created at the root and destroyed at the leaves.

What's wrong here? Simple: a self-employed plumber does not have a paycheck, except maybe to him/herself for accounting purposes. They collect their income in the form of payments from customers. They don't have an abstraction: they hire more labor and become the abstraction. If their customers have no money, the abstraction leaks, their employees have to be laid off (and then can no longer afford plumbing services themselves). The success of the plumber depends as much on how many people are able to pay them as it does on his costs (such as taxes). We want to make sure those customers can still pay. This is, in theory terms, the idea of demand-side or Keynesian economics. (Not really exactly. I took about two econ courses. But bear with me for a moment.)

Now, you can argue demand-side vs. what we would call supply-side economics, which is the idea that no, first you have to stop taxing Joe so he can hire people so they have money to go buy things, for ages. People have made whole careers out of it. I am not here to do that. What I am here to wonder out loud is: why is this argument not happening, now, in our public sphere? Even if only as a small plot point in one Presidential campaign? There are very good arguments for both sides (I agree with the Keynesians, myself), and they should be what this debate is about, not digging up dirt on some guy whose real name, horrors, might not be "Joe" or protests about all those you-know-what poor people getting "government giveaways" that are disturbingly close to racism in my opinion.

When I turn on talk radio I hear zombies, unable to string together any thought more complicated than "Democrat == higher taxes on everyone" (which would be depressing even if the claim were true). It begins to get unsettling when you understand your opponent's argument, and yet watch them completely unable to articulate it. When they deal with this by appealing to fear and thought-killing sound bites, it gets alarming.

Obama has backpedaled whenever the whole issue has come up. In the last debate, he was saved by merely shutting up and letting out enough rope for McCain to hang himself. Not very inspiring. As a result I hear repetitions of Obama's phrase "spread the wealth around" constantly met on the airwaves with... silence. He won't touch it, and honestly, I can't blame him for not wanting to fan the flames of class warfare with only two more weeks left to stick it out. But I don't understand why, and why a single person on the left hasn't had the faith that this idea can be discussed in our society. I think that, whichever side you are rooting for (and yeah, I am for the Democrats), the Democrats should have won this point readily. Not to belabor the point, but it really amazes me that they have not. It wouldn't have taken much.

Here's what you do: go to Wherever, OH with your crack PR team and find several of "Joe the Plumber"s customers. Interview them all. A few of them are, in this economy, going to be really hurting. If you're lucky: Remember that Joe owes taxes to the IRS. Very possibly, someone owes Joe money! That would be a coup. You just put them in front of the media and the whole thing sells itself. Mary needs to make these repairs... if only her tax credit were larger... etc. This would not settle the argument, by any means, especially not for political junkies. But it would begin it. We could talk about policy, whether one way of "spreading" things will result in more wealth to spread than another, instead of red-baiting. I feel a bit ripped off that we haven't even gotten that much. The theory part is pretty much irrelevant to most people; that's fine. But they deserve context.

I can only assume that my ("my") party is still either terrified or stupid. I hope winning the Presidency changes that somewhat. That whole right and wrong, purpose, "noble cause" thing, right? Right, guys?

Njiiri 0.2.0

Seems like it's been ages since I've been able to do this (probably because it has!): I've released a brand-new piece of software.

Njiiri is a client for MPD, using GTK+, written in Ruby. I don't see a lot of desktop apps out there using Ruby, so this was a new and fun experience for me. I've tried to make it as "boring" as possible, in the sense of looking vaguely like a proper, HIG-compliant GNOME app, with (appropriately) no pointless configuration knobs. The browser, in particular, is a mostly pixel-for-pixel clone of the standard file-open dialog. And it's accessed by a big toolbar button with a stock "Open" icon.

Basically, if desktop software makes me think ("oh, I'm in iTunes, all the controls work differently, let's adjust our approach"), it's failed. For me, anyway. So, I'm pretty happy with the direction I'm going (even though I'm very much not there yet. I haven't hooked up search, for example).

One of the things I like about MPD is that it gives me the freedom to remove things if I want to. And I like removing things; small is beautiful. For example, I originally had no place to stick a crossfading control in, so I was going to just dump it. If you need it, "mpc crossfade" is a terminal away. (It turned out that it did eventually fit nicely into my layout. I'm a bit obsessive about aesthetics.)

In a similar way, I've avoided duplicating anything I do with homegrown scripts or mpdtoys; there's just no need. What I want out of a GUI frontend is a sort-of tangible way to manipulate things when I feel like looking at them visually for a bit. Then I close it and move on.

MPD certainly isn't the most wonderful implementation of a system which allows that, but the client ecosystem is quite diverse and I'd say it deserves a look if any of this sounds interesting to you.

The cradle rocks above an abyss

In related news: with sup out of the way, I have returned to packaging Mnemosyne, the program that powers this blog. It is also in NEW, so expect to see it soon. (Like sup, which is packaged as sup-mail since sup is the Software Update Protocol, it is mnemosyne-blog since mnemosyne is the program formerly known as PyQt MemAid.)

If you're just joining us, Mnemosyne compiles a Maildir into a static site. You can use it for a blog or just about anything else where a traditional CMS would be overkill. It's all XML and Python-extensible. The documentation kind of sucks, though, so I'm also hoping I get some more users from this to tell me what to fix. It hasn't otherwise seen much action since the beginning of 2006. Drop me a line if you have any feedback!

(If it's not obvious, I think blog "comments" in general are pretty worthless. But with some craftiness, they could certainly be implemented within Mnemosyne as it stands. As could a general mailing list archive, etc...)

What's sup?

After some weeks of final testing, I've just uploaded packages for sup-mail to NEW. I'm pretty excited about this.

Sup is a console-based MUA, like mutt (which I have used for many years). A few things distinguish it from most mail readers targeted at geeks like us:

  • Sup has no folders, a la Gmail. After watching many friends and even fellow hackers switch to Gmail, I have to admit: this literal hierarchical organization thing doesn't scale. I was planning to totally redo my mail folder system Any Day Now for about six months prior to starting on this. It was never going to happen.
  • Sup uses a Ferret full-text index to make this approach plausible. Search is super fast and beats (for me) both any kind of "organization" I could have disciplined myself into and the fine-grained control of something like mutt's search. It's sort of like git: until you do it, you don't realize how much more productive you can be when previously-expensive operations become instantaneous.
  • Sup works with threads, not messages; this is another thing Gmail got right. I used to waste brain cells thinking about which messages in a thread were worthwhile enough to save or not. Given the absurdly cheap price of disk relative to what we can type out in plain text since, like, a decade ago, this is crazy. In the index, I only have to look at whether a thread has new chatter or not, not its size, shape, or where the new messages are relative to it. All that's in the thread-view buffer where I actually read content.
  • Sup is written in Ruby. Back in the dawn of time, I used Gnus, and while I wasn't very good at elisp, the hackability afforded by being written in a high-level language was very nice compared to programs mostly implemented in C (even if they had a tacked-on scripting language). Plus, I love Ruby right now.

Despite all of those wins, sup currently has many drawbacks, and I don't recommend it for everyone. (And I mean everyone who thinks that the above are good ideas and are interested in using it; plenty of people, I'm sure, already think everything about this is idiotic, not new, or inferior to their preferred MUA. That's fine! You can ignore it all.) Here's what's still problematic:

  • At version 0.6, sup is very much not-yet-1.0. While it handles insanely large amounts of email without breaking a sweat, I still keep an additional backup of everything. (If Ferret crashes, the original copies of mail will be untouched, but it never hurts to be paranoid.)
  • The flow of data from your physical mail store to the sup index is currently one-way only. Actually removing deleted/spam messages is a big hack (if it works at all), and labels/flags/etc live entirely in Ferret-land. If you want to manipulate an actual mailbox, mutt is still the tool for the job (and then, you need to re-sync sup). This is probably the deal-breaker for most of us. I jumped in anyway because I feel like it can be solved (or more likely, made irrelevant) later.
  • William (upstream) is currently re-designing the whole thing from scratch, replacing the index library with Sphinx, and decoupling the index from the console frontend. As a result, the previous item is pretty much a non-priority (and bugs in general are not going to get the same amount of love as usual). I am hoping that we end up dumping mail into the index directly, then writing more frontends to write to Maildir backup, serve as webmail/whatever, but this is a long way off. On the plus side, thanks to Thrift, they will not be limited to Ruby.
  • Ruby's ncurses library still doesn't handle Unicode correctly. It can be patched (still doesn't work totally right), but I'm trying to find a more permanent solution for Debian.

So, if you're interested enough that you want to deal with these warts for now, apt-get install sup-mail (as soon as it hits the archive) and join us! Hopefully being in Debian will increase the userbase and get things fixed faster. If you're unsure, stay tuned for the next-generation version later.

(There are screenshots and a few introductory docs over at Rubyforge that illustrate and explain all this in more depth, which I recommend checking out if you're still saying, "...huh." Me, I'm a sucker for any piece of software with a manifesto.)

Mass cynicism

"Obama had the additional skill of criticizing George W. Bush."

Basically: yes. And that's what passes for politics over here, folks. Sorry about your economies and all that.

Your internet access is going to get suspended

So today I recieved another batch of backscatter spam (it comes in waves; my email address will forever be on these lists). Normally there are several rejections from mailing lists where only subscribers can post, etc. But this time:

The following lines in your email message did not appear to be
Lyris ListManager commands and were skipped:

> unsubscribe confirm
>  -> You did not specify a valid mailing list name to unsubscribe from.

Disturbing. Now they're trying to take me off legit mailing lists! Perhaps they think I won't notice and it'll reduce the amount of ham I have for my Bayesian filter. Little do they know I'm still subscribed to -devel :-)

When mayonnaise goes bad

This is is a wonderful metaphor: "looking in the fridge every few minutes and hoping that something tasty will appear".

I may be thick, but Planet does not appear to store any information about how often a feed ought to be polled (my blog seems to be hit every 20 minutes even when I'm AWOL). I use rawdog, which does.

When adding a feed, I make a vague guess at how often I want to poll it, and then periodically adjust the time based on how often updates actually happened. This is done with a terrible, awful, ugly hack that reads the database[1] and spits out the config file with new-and-improved times. Pretty dumb, but good enough "for now" (apparently I haven't touched it in over a year).

rawdog will also automatically update feed locations if given a 301. Since it already rewrites the config for that, I might try to merge time updating into the core someday, but no one has demanded such a feature AFAIK.

[1]And by "database", I mean "pickle", since Adam doesn't want any fancy dependencies. Despite how slow this ought to be, the combination of optimized (such as it is) feed-polling and ever-faster CPUs in my web servers have made it fast enough for me not to care.

Catch 22

$ hg ci
abort: cannot commit over an applied mq patch
$ hg qpop
abort: local changes found, refresh first

Obviously, I just need to RTFM, but I still find this amusing in an existential sort of way.

(If I write a replacement for mq, please shoot me. I have too many things to do already.)

xmonad still makes me feel inadequate

I've seen this before, and I'm sure a million people have blogged it, but it never stops being funny: Lambdacats.

(thanks to Nikolas Coukouma on Twitter)

Cover an ox with a sheet

New Filco keyboard! Do want.

(There is a good explanation of mechanical keyswitches at ErgoCanada. This is a "light tactile" board. Opinions, as they say, will vary.)

I may be just a little too into this. My girlfriend laughed at me when I actually bit my lip upon determining firsthand that the ICA had aquired, for their iMac-populated computer lab, 20 or so of the out-of-production tactile version of another particular keyboard I'd been coveting. But I couldn't help it.

(Don't worry. We laugh at each other a lot.)

Did you see what he was wearing? Oh. My. God.

Debian shall soon have a Conkeror package, thanks to Axel Beckert who takes a minute to break down the current keymap. Naturally, you have to poke fun at vi users here. But wait! I am a vi user!

What can I say, except maybe

  1. Emacs (the rudiments, anyway) is like riding a bicycle
  2. When I say vi, i mean vile, not vim. vim gives me hives. vile is teh awesome.

I am working on a set of vile-ish bindings, and I can't say I feel any pressing need to stick hjkl in. You could start from there, but that's missing the point, I think.

(You know what's also awesome? My email is still down, so I won't even have to delete flames from people who take their choice of editor/browser Very Seriously until sometime tomorrow.)

You keep using that word. I do not think it means what you think it means.

I always feel like tar ought to say:

tar: data.tar.gz: inconceivable time stamp 1969-12-31 19:00:00

But it never does.

Consolation Prize

I spent some time banging my head against SSL certificate stuff this weekend in the hopes of implementing a Really Awesome Solution to this awful Firefox security theater thing everyone was complaining about, but I didn't get anywhere. However, I noticed something interesting: Mozilla does not trust the CAcert root certificate. A number of useful sites, like Freedesktop.org's bug tracker, use a CAcert-signed certificate rather than a self-signed one.

I really know nothing about this organization, but they seem to have their stuff together, and if you run a largish free software project, you could potentially save a lot of people the trouble of checking yet another self-signing CA. Around the lab, or in one of my tiny projects, I don't think I'd bother, but it is free.

Anyway, we ship their root CA thing in Debian, and OpenSSL stuff picks it up fine. Mozilla's process is somewhat more mysterious. There's an apparently hardcoded list of the usual thugs from the Verisign/Thawte/etc protection racket, and then there's a database in each user profile for whack-a-mole stuff. There is not, shockingly enough, somewhere for an operating system to set system certificate policy. (I guess there is not much room for an operating system in the Mozilla world-view at all). So you have to shove it in there once for every user times every single profile.

Here is the command to do it.

  1. apt-get install libnss3-tools
  2. certutil -d $HOME/.mozilla/firefox/$HLAGHLLAGHGAAHLGALHHGHLAGH.default -A -n 'CA Cert Signing Authority - Root CA' -t CT,C,C -i /etc/ssl/certs/root.pem

It's only slight pain relief, but it's something. You can also not install certutil, and click through ten million dialog boxes to import it, but screw that.

UPDATE: A commenter points me to StartSSL, another service that may deserve a look here, and is on Mozilla's good side. It appears to be an unholy mix of things that sound awesome (client-side certs for OpenID, web-of-trust identification) and things that seriously skeeve me out (trademark symbols everywhere, Aladdin dongles). They, uh, also have a Linux distribution. No, really.

UPDATE 2: James Andrewartha points out that we should eventually see Mozilla move this stuff out of libnssckbi.so and into SQLite, which sounds like a big win for us. Hopefully before that time I will figure out how to get sqlite(1) to work on my cookies.

The data are

So I always knew that my ThinkPad's display sucked. But now I have scientific proof! (Long-winded post about my job follows.)

I was running some timing tests at work on the code for a psychology experiment. This involves quickly presenting a stimulus to the subject, then measuring reaction time and synchronizing with EEG readings. Nothing very complicated, but accurate timing is essential; you don't want another variable confounding your results. So I have this photocell device that sends a signal to a Mac through the EEG hardware when there is really actually physical light coming off of the screen, not just when I told the computer to display something.

Now CRTs, of course, are actually scanning (with an electron gun) the display at 75 or 85 Hz or something, not constantly pumping out light to the whole screen. This means 12 or 13 (or whatever) ms between refreshes. So if you want something to appear for 100 ms, you have to fudge a little, and make it so that you get maybe 8 or 9 scans. You can synchronize your presentation to the refresh so this is feasible. But how long the subject really perceives it ultimately depends on how "flickery" the monitor is at a given refresh rate.

LCDs, on the other hand, do not have this problem. They actually do produce light constantly -- their refresh rate is pretty much always only 60 Hz or less, but you get the same(ish) output over the entire cycle, instead of in blips that give the illusion of a constant image (in fact, as Matthew points out, they can continue to hold the same image for even longer periods between refreshes. Can't wait to try out that patch). And luckily for us, 6 cycles are in theory exactly 100 ms (in practice, it's close enough).

Or so I thought. I could not, no matter how many times I banged my head against it, get consistent results between our laptop (also a ThinkPad) and any external display. For reasons I do not entirely understand (probably scheduling issues), on CRTs I was getting one extra cycle, so I had to reduce the time by one to compensate. This was done for published studies years before I arrived at the lab, so (for the sake of not introducing additional variables) there is an extremely large disincentive to go back and fix it the Right Way, whatever that is. Our laptop's internal display was producing results that were skewed like those of a CRT. I thought for a minute I was going nuts from testing all day, but it kept happening.

Curious, I swapped out the lab's T60 for my faster T61 and (to rule anything else out) killed all my other processes and wrote a fresh PyEPL script that did nothing but repeatedly blink some text for 100 ms. Here is, on the external VGA port, a cheap old 15" Dell LCD I pulled from the server room:

http://www.rupamsunyata.org/~decklin/blogfiles/20080626/vga-lcd.png

(These images are from the Mac, which is still using System 9.something. I had to remember Command-Shift-3 to take a screenshot and use StuffIt to get them off of it. Srsly. I can't remember the last time I used StuffIt.)

And here is a CRT, showing the refreshes: (The DIN3 line is the actual signal, and the others are integrated over some number of milliseconds to compensate for scanning and attempt to get a usable number. Of course, this is done in hardware, not synchronized to anything else.)

http://www.rupamsunyata.org/~decklin/blogfiles/20080626/vga-crt.png

Now, this is the one that blew my mind. The ThinkPad's internal LCD:

http://www.rupamsunyata.org/~decklin/blogfiles/20080626/lvds-lcd.png

You can see that 60 Hz is spaced much farther apart, and that there are 6 cycles as intended, but. It's acting like a CRT! On the refresh, it puts out enough light to trigger the photocell, but inbetween, nothing. I ought to be noticing flicker and/or getting headaches all the time, if this is truly the case. (I guess I did get glasses for and because of staring at computer displays all the time. Should update my hackergotchi.) I have to admit I do not understand what is going on here at all. But it seems like making any assumptions about a display is (as the voice in my head was telling me all along) a very bad idea. Perhaps someone can email me some clue. But at least I have some hard data to validate my subjective opinion of the ThinkPad's internal LCD.

Anyway: I still recommend the ThinkPad, even if the display is awful. I have a nice external monitor connected through DVI to the dock at home, and I mainly use a laptop so I can get out of the house and go hack outside or in a coffeeshop (not ideal lighting). The build quality, keyboard/trackpoint, performance, and the fact that Debian (testing or unstable, anyway) Just Works are all higher up on the list for me. I do wish I could afford the new lighter one, though.

Arrogance

Today, like any other day, I started Firefo^WIceweasel. I mapped it at the bottom of my window stack. It promptly raised itself. I closed everything and tried opening a new homepage. Nope, that's fine. I tried again with two tabs saved. It raised itself again.

I have been watching variations of this bug regress for eight years now and I am tired of it. So I installed Conkeror. After a good three-year run of being able to sit down at someone else's random PC and say, "hey, a web browser that nearly works as well as mine" (since it is, you know, the same one), I look forward to being utterly fed up with how primitive the rest of the world is again. And what are we in this for, if not that?

Dealing with it

I had this crazy idea a few months ago which Joey's post about muscle memory reminded me of.

For those not in the US, our keyboards have ` and ~ on the key to the left of 1. I prefer this key to be Esc. Long ago I simply swapped the two keys, but the original "Esc" key is always in some weird and inconsistent place and reaching for ~ became as annoying as reaching for Esc. (I suppose I might not care if I didn't use a unix shell or regular expressions or bit masks or...)

So, noting that I mostly only wanted that key for ~, and not `, I came up with the following (in xmodmap form):

keycode 49 = Escape asciitilde grave Escape

This means: if you just hit the key, it does the Right Thing (Esc, as if I were on a real unixy keyboard). If you hold Shift and press the key, it also does the Right Thing (~, as if I were on a PC). But what to do about `, or Shift-Esc, which are no longer possible? We make them the alternate graphs (just old down AltGr. I think the xkb option to put this on right Alt is "grp:switch"). I honestly use those two infrequently enough that I don't care about having to remember the extra bucky.

(I tend to type $(cmd) in the shell, and not `cmd`, because I use the former in scripts and I always found the latter harder to read. I suppose I would care more if I used Lisp or Haskell or...)

What I like most about this solution is that it lets me use the same muscle memory on all my hardware. Never mind weird Esc positions; laptop vendors still can't agree on the correct order of Fn and Control. But you don't have to care if you put Control on Caps Lock. Same idea. It does feel a bit like cheating, but it has made my wrists far more comfortable.

Oh, and to wean myself off the key way out in the corner:

keycode 9 = NoSymbol

Now the question, of course (getting back to Joey), is what would happen if my "new" Escape key broke. I guess I'd have to keep the laptop at home and plug in my Happy Hacking Keyboard :-)

Section Twelve

Darlings

Today's wiki page: Fighting is boring.

YouChoob

Russel notes a discussion of the problems with embedded media. I've been using a Greasemonkey script for a while to linkify EMBED tags for easier non-embedded downloading, but this doesn't help much on Flash sites such as YouTube. I haven’t installed Flash in years, but I got sick of slinging URLs around and/or giving up and being the unpopular kid, so I took some other Greasemonkey code I was hacking on and mushed it all together:

http://www.red-bean.com/~decklin/userscripts/unembedtube.user.js

(I get a perverse sort of nostalgia out of bringing back the "puzzle piece" for links, and mocking people with it.) YouTube embeds will appear to work like any other, but the URL is changed from the Flash wrapper to the FLV file, which can be opened in MPlayer/Totem/whatever. Since we can figure out this URL, it is also, of course, possible to make such the link back into an embed usable by mplayer-mozilla or a similar plugin.

Unfortunately, I don't have time to look up how to add a configuration menu, but this line of JS does have a certain charm to it:

var evil = 0; // need to make this user-settable

You know what to do. If you want true evil, there are some pointers in the comments. For YouTube videos embedded from other sites, the best I can kludge for now is link to the video's original YouTube page. If someone would like to write a routine to snarf that page with XMLHTTPRequest and yank the necessary arguments out, I would love to add it.

(Insert five-page “think piece” here about the lost dream of MIME and the sad fact that the rise of “Web 2.0” has been driven more by the fact that native installation is irreparably broken and pointless anyway on most PCs than it is by the fact that JavaScript actually works now and the implications of this for the Free Software movement especially in light of the fact that we are still human beings who occasionally do social things like sign up for Twitter even though they're running on some proprietary code base.)

Tangible User Interface

I logged in this morning and noticed that my XFCE weather applet had disappeared. I moved the pointer over to see what was up, or at least open the menu to add a new one...

A tooltip appeared that said, “fog”.

No Installation Required

So, I haven't blogged in almost a year. I am a horrible, horrible, horrible person. But at least I've been on LowThresholdNmu. Barely.

Since I still read a blog or two so that I can pretend to be informed: I really like this post. I would make a comment about the bumper sticker on the Prius normally parked around my part of ye olde Prospect Hill, but then people might think I was actually talking about politics or oil or cars or gentrification or something like that. It's a violent world out here on the interweb. One can only be oblique.

When did I get so old? Did I fit in at some point? I really don't know.

Dear Lazyweb

I just wasted half an hour (mostly finding a dead motherboard and bending wire) making one of these:

http://www.rupamsunyata.org/~decklin/blogfiles/20060622/usbport.jpg

I then threw out the cap to my USB storage device. Why doesn’t anybody sell them? Why are the holes for your keyring always on the part you use (thus weighing it down, particularly if it's sticking out of the front of a tower) and not the part that comes off? It's not easy to unplug by accident (I did squeeze it a bit removing some of the metal).

I think I’m just not looking in the right place. I can’t be the first person to have been annoyed with this. Lazyweb, please tell me where to go.

(Yes, the only thing I use it for is my SSH key.)

Irony Alert

The other day I went back to the West Hartford library for some more DVDs and stopped by the New Non-Fiction shelf. This book caught my eye. It claimed to be a lexicon of euphemisms, “doublespeak”, and other language used in the US to disguise one’s true opinion, assumptions, or political agenda (you know how we love politics over here). An Ambrose Beirce for the talking head set, if you will.

So I flipped through it for a bit, and to be fair, the authors did do a commendable job of pointing out some of the subtle presumptions of many words that I myself think I use completely innocently. Even if I try to directly combat this tendency in my own way, one could certainly argue that ideas like systemic bias or jargon themselves implicate or demonize certain groups.

But that's why we need something like this book, right? Have to keep on our toes. Then I landed on H. The first entry was “hacktivism”.

“...which,” it read, “like hacking, is illegal...”

Brooks’s Law

When Ubuntu said they were going to focus on polishing Dapper because it was the release that was going to go head to head against Vista, I said to myself, “come on, people, you’d easily be safe with 6.10”. And voila.

Besides, everyone knows the summer is the best time for hacking!

I sincerely hope the previous sentence serves as enough of a smiley face for no one to blog an, um, rebuttal.

I have not actually had a chance to test this yet

Dear Lazyweb,

Does anyone know how to remap Caps Lock to Control in Windows for a specific keymap (e.g. Dvorak) only? The standard thing appears to be hardware-level.

I feel the need to pass this on

“The apartment downstairs is free as in malloc, not as in beer.”

Flow Control

Raise your hand if you have ever said, “I wish I could use C-s and C-q in Firefox.”

Whoops

Apropos of my last post here, I am redoing my rawdog config and writing a tag plugin. This involved merging all my state pickles into one file first, which rather strangely brought my server to its knees until the OOM-killer kicked in.

I couldn't figure out what was going on for a second. And then I noticed that ever since I switched it to LVM I wasn't using my swap partition at all. So, a word of warning: never assume your fstab is right just because your filesystems show up.

Pickle still needs to be replaced, but a lot of things need to be replaced.

I got lost

You know it’s bad when writing several screenfuls of recursive fuzzy tree matcher in Python is fun and doing a tiny bit of tree and Makefile maintenance on a C project so you can push out fixes from last year is a chore you’ve been putting off for weeks.

Constants of the universe

One of the few annoying things about free software is simply finding it. You can get a very good idea of what is to your taste or not from people around you, but if you don't know or care (or want to care!) about some particular problem, generally people whose opinions you trust don’t like any of this crack either.

In particular, Web Frameworks(tm). Lots of people love them. I’ll take vanilla. After paging through several manuals last weekend for things which I might be able to use a templater from, and finding that despite all the other features, no one seemed to even care that much about even doing inheritance sanely, I got annoyed and grumbled something about how they all sucked and figured I could just factor that logic out myself and use what I was already using for the boring bit.

However, Erich pointed out that that sucked too. And if you care about being correct (says me who serves all these pages with the XHTML mime type despite it breaking Internet Explorer and Google), you should probably assume that if you give your users (including yourself!) something fragile, they’re inevitably going to break it (and if they’re the sort of users that have been crawling out of the woodwork these days, well...). So I checked out Kid, to which I am giving yet another link here because it’s just that good. I’ve seen attempts to implement the “it’s all valid XHTML” thing before and they were rather blah. This one seems to actually fit with its being hosted on lesscode.org. And I am nothing if not a sucker for less code. And for things being pleasant to read.

So I ported my templates over and added the four lines I alluded to, and now (since I know my output is provably valid), although I have not put them live yet, I have a starting point for making them be a little less crack (really, it’s very bad). Has anyone registered lesscrack.org yet?

XML

OMG! I just remembered I own a copy of the elephant shrew book!

...Somewhere.

I would have had no idea that’s what those were if not for this page. (This is a blog, I have to make a link somewhere. Read the articles; they made me smile at least.)

This is where we do some shameless self-promotion I think

Erich, I’ve been working on one for this blog. No persistent cache to speak of except for the files themselves when their sources haven’t been touched, and I haven’t found any reason to need XML, but I was trying to avoid much of the same nonsense you mention. As such, the templating is as dumb as possible. Perhaps you can do a lot more with XSLT, but I didn’t find it very interesting. Templating systems in general make me itchy.

I am now, however, thinking about making it easy to subclass that part of things as well, which could be interesting. Write something to talk to the big XML library, one import in layout, a few lines to save the cache in a pickle... hmm!

(I always stick a “raw-html” role into reST if I really need it for something, but generally, I try not to think about HTML period.)

I haven’t heard from anyone about it yet so I don’t know which X, Y, and Z are obviously lacking. :)

Entry love

Evan thinks about the nature of the commons.

Hate

I truly, truly hate email. First you have the __getitem__ and __setitem__ that work nothing like a dict (no KeyError ever, just returns None, despite there being a get, silently fails to overwrite an existing value, no update). But of course they're just as stupid as a dict if you change the content, instead of associating the type with that object. And then. decode_header. Does this:

[('Foo', 'utf-8'), ('Bar', None)]

Hint: ('Bar', None) is not a valid list of arguments for creating a unicode object. I don’t even want to create it myself. I just want the thing decoded. Ugh, ugh, ugh. Everything that possibly could have sucked here has sucked. Lots.

One of the reasons I decided to use Maildir is because it takes two lines of code to turn it into a structured list of objects. Except of course both of the standard modules that make that possible are horribly designed. I really don’t want to reimplement this shit. I really don’t want to go to a “real” database backend where suddenly you can't use any standard unix tools to do anything and you have to write them all from scratch.

All software sucks. Down, not across.

Gratuitous Non-discoverability of Interfaces

Actually, what really bothers me about the GTK+ file dialogs is having to click “Browse for other folders” every single time I open the one for saving. (Last I looked this up, the only solution was to patch GTK+.)

My understanding of all this touchy-feely user-interface stuff is that humans are supposed to be oriented spatially (classic Finder) or by breadcrumbs (Netscape). A tiny little dropdown with a text label of just the current directory's name (not even a full path) gives me no idea whatsoever “where” I am. I constantly save things in the wrong directory from Firefox.

While basename $PWD is all the directory information I put in my shell prompt, I can do considerably more from there, and new shells don’t tend to pop up two hours later when you forgot where you cd’d to last time. What is acceptable for me there is not acceptable for a normal user here. I really don’t get what they were thinking.

New blog

Okay, I’m putting this blog on Planet Debian... now. The old one is not gone yet, because I’m tired and I don’t think I’ll do it until tomorrow.

In a fit of hubris, I wrote some software to run this blog (which is just a bunch of generated static files), called Mnemosyne. I was bored of PyBlosxom and it was slow. I believe Erinn said something like, now it’s only a matter of time until I write my own RCS... If I get to that point I will really start worrying. If anyone is looking for something along these lines, please tell me what sucks and/or what is broken.

Anyway, rather than categorizing things (ugh), I’m just putting anything tagged “planet” in the feed that goes here. I think this will work better.

Oh, and I almost forgot: my blog now has automatic flooding-prevention. Nothing older than a day gets in this feed. I don’t know why feeds in general don’t have some sort of time limit.

Generated by Mnemosyne 0.12.