Music Nerd Joke
I’m going to tag all my Cocteau Twins MP3s and, in the TLAN frame, set the language code to zxx.
I’m going to tag all my Cocteau Twins MP3s and, in the TLAN frame, set the language code to zxx.
This was definitely a “D’oh!” type of problem.
One thing I’d been meaning to figure out for a while was how to send gzip-compressed files to a browser. That is, if I have a large HTML file, it’d be nice if the server could compress it to save bandwith and transmission time. Yes, Apache has mod_deflate which takes foo.html and gzips it on the fly, setting all the appropriate HTTP headers. But for static content, I should just be able to compress the file in advance. If the browser asked for foo.html, I wanted Apache to see that there’s a foo.html.gz and send that instead, with headers saying that it’s a text/html file that happens to be compressed.
mod_mime seemed like just the thing: just add
AddEncoding x-gzip .gz
to .htaccess. But every time I did that, Apache sent back “Content-Type: application/x-gzip“, so my browser treated it as a random file of unknown type that happened to be compressed.
Then I noticed that my vanilla-ish site-wide Apache config had
AddType application/x-gzip .gz .tgz
so that when Apache saw foo.html.gz, it ignored the .html extension, and saw only the .gz one.
The fix was to add RemoveType to my .htaccess:
RemoveType .gz AddEncoding x-gzip .gz
And voilà! .gz stops being a file type and becomes an encoding, allowing .html to shine through.
I’ll add that this plays nice with AddLanguage as well. In my test setup, I have foo.html.en.gz, for which Apache returns the headers
Content-Type: text/html Content-Encoding: x-gzip Content-Language: en
I.e., it’s an HTML file, it’s gzip-encoded, and it’s in English.
Just as importantly, this works with other file types (e.g., CSS files and JavaScript scripts), and XMLHttpRequest does the Right Thing with them on all of the browsers I care about.
MacOS plist XML files are evil; even more so than regular XML. For instance, my iTunes library file consists mostly of entries like:
<key>5436</key> <dict> <key>Track ID</key><integer>5436</integer> <key>Name</key><string>Getting Better</string> <key>Artist</key><string>The Beatles</string> <key>Composer</key><string>Paul McCartney/John Lennon</string> <key>Album</key><string>Sgt. Pepper's Lonely Hearts Club Band</string> … </dict>
You’ll notice that there’s no connection between a key and its value, other than proximity. There’s no real indication that these are fields in a data record, and unlike most XML files, you have to consider the position of each element compared to its neighbors. It’s almost as if someone took a file of the form
Track_ID = 5436 Name = "Getting Better" Artist = "The Beatles" Coposer = "Paul McCartney/John Lennon"
and, when told to convert it to XML in the name of buzzword-compliance, did a simple and quarter-assed search and replace.
But of course, what was fucked up by (lossless) text substitution can be unfucked by text substitution. And what’s the buzzword-compliant tool for doing text substitution on XML, even crappy XML? XSLT, of course. The template language that combines the power of sed with the terseness of COBOL.
So I hacked up an XSLT template to convert my iTunes library into a file that can be required in a Perl script. Feel free to use it in good or ill health. If you spring it on unsuspecting developers, please send me a photo of their reaction.
I’ve been using dirvish to do backups at home. One problem I’ve always had is how to back up MySQL databases, since the backup takes a snapshot of the binary files, so if it happens at the wrong time (e.g., in the middle of a transaction), the backup might wind up being in an unusable, inconsistent state. Much better to use mysqldump to export the database to a file (one which, by the way, can also be manipulated with standard tools like perl and emacs, in case I need to repair anything).
The obvious way to do this was to use the pre-client dirvish directive to export to a file, then let that file be backed up. But I could never get it to work.
Cut to the chase: It turns out that for this to work, the pre-client directive (and post-client, if you want to clean up afterward) needs an extra semicolon:
pre-client: ; /usr/local/bin/mysqldump -a -A -e > $DIRVISH_SRC/mysqldump.%Y-%m-%d.sql post-client: ; /bin/rm $DIRVISH_SRC/mysqldump.%Y-%m-%d.sql
Without those semicolons, things don’t run correctly. My guess is that the semicolon tricks dirvish into thinking that the command consists of multiple commands, which must therefore be run inside a shell, rather than a single command to be executed with fork()/exec().
I just found out that the mutt mailreader accepts ~Lexpr in searches. This matches messages where expr appears either as a sender or as a recipient.
Every so often, I need to look for a mail exchange I’ve had with a particular person, or where two people have corresponded and Cc-ed me. So I’d limit to
~farensb ~C(pat|chris) || ~f(pat|chris) ~Carensb
(messages (from arensb and (to or cc-ed) to (pat or chris)) or from (pat or chris) and (to or cc-ed) to arensb, for those who don’t speak mutt-regex).
Now that I know about ~L, the above can be simplified down to
~Larensb ~L(pat|chris)
(messages (from or to or cc-ed to) arensb and (from or to or cc-ed to) (pat or chris)).
My tunnelled carpals thank you, Mutt developers!
Since M. didn’t know about this the other day, I thought I’d mention it, in case it helps someone else: Firefox has a massively-useful feature I’ve been using all the time: reopen the last tab that was closed.
You can find it under History → Recently closed tabs. There’s a Recently closed windows list to go with it.
Reopen last tab is bound to Alt-Shift-T for me, though your mileage may vary, since I’ve adjusted Firefox’s bindings to suit my modifier keys (what’s a Meta for?).
I should also add that Alt-1 is bound to “Go to 1st tab”, Alt-2 to “Go to 2nd tab”, and so forth. I sometimes find this to be quicker than moving my hand off of the keyboard to click on a tab.
Like a lot of people, I have to submit a monthly “bullet” report, listing the things I’ve done in the previous month.
Since I use Org-Mode for planning, scheduling, and organizing tool (or rather: I tend to throw a bunch of notes into a file and tell this love child of a day planner and a wiki to tell me what I should do next), I figured I should use that.
I could use the timeline feature (C-c a L), but that only works for the current buffer, and I want a report that covers all buffers, just like the agenda.
What I’ve done in the past is to use C-c a a to get the agenda view, go back a month, toggle displaying completed/archived/whatever items, and go through that to make my bullet list.
But I finally got around to encapsulating that into a single M-x bullet command:
; Make it easier to generate bullets for $BOSS (defvar bullet-entry-types '(:closed) "Org-mode agenda types that we want to see in the monthly bullet report See `org-agenda-entry-types'." ) (defun bullets () "Show a list of achievements for the past month, for monthly reports. Uses `org-agenda'. " (interactive) (require 'org-agenda) ; All we're doing here, really, is calling `org-agenda' with ; arguments giving a start date and a number of days. But to do ; that, we need to figure out ; - the date of the first of last month ; - the number of days in last month (let* ((now (current-time)) ; Figure out when last month was. Assuming that I run this ; close to the beginning of a month, then `now' minus two ; weeks was some time in the previous month. We can use that ; to extract the year and month that we're interested in. (2weeks-ago (time-subtract now (days-to-time 14))) ; We'll also need to know when the first of this month was, ; to find out how long last month was. If today is the 12th ; of the month, then the first of the month was `now' minus ; 11 days. (1st-of-this-month (time-subtract now (days-to-time (- (nth 3 (decode-time now)) 1)))) ; Ditto to find the first of last month. (1st-of-last-month (time-subtract 2weeks-ago (days-to-time (- (nth 3 (decode-time 2weeks-ago)) 1)))) ; The length of last month is the difference (in days) ; between the first of last month, and the first of this ; month. (len-last-month (time-to-number-of-days (time-subtract 1st-of-this-month 1st-of-last-month))) (start-date (decode-time 1st-of-last-month)) (start-year (nth 5 start-date)) ; Year number (start-mon (nth 4 start-date)) ; Month number ; Restrict the agenda to only those types of entries we're ; interested in. I think this takes advantage of dynamic ; scoping, which is normally an abomination unto the lord, ; but is useful here. (org-agenda-entry-types bullet-entry-types) ) ; Create an agenda with the stuff we've prepared above (org-agenda-list nil (format "%04d-%02d-01" start-year start-mon) len-last-month) ))
I hope this proves useful to someone.
Since the 1940s, computer scientists have been seeking to make machines perform the same kinds of tasks as humans. This pursuit of artificial intelligence (AI) has yielded a lot of impressive results, such as Deep Blue beating a chess grand master, but it has fallen short of people’s expectations: computer translation, for instance, is still a long way away.
And so computer scientists started emulating evolution by natural selection, a process about as far removed from intelligence as possible: try everything and see what works. A process so amazingly stupid that even inert, nonliving material cam perform it. This research seems to have succeeded much better than anyone expected.
Which just goes to show that artificial intelligence is no match for artificial stupidity.
I’d noticed a while back that if you hold down a key on the iPhone keyboard, such as the ‘E’, for a second or two, you get a pop-up menu with variations on the ‘E’ theme, like ‘é’, ‘è’, ‘ê’, and so on.
But what I hadn’t noticed until just now is that the “.com” key, which appears when you’re expected to type in a URL, exhibits the same behavior: if you hold it down, you get a popup menu with “.net”, “.edu”, “.org”, and “.com”.
In addition, since I have the French keyboard installed, the popup contains “.fr”.
In the email application, when you’re entering an address, there’s no “.com” button, just a “.” (period) button. However, it also has the domain popup, with the same TLDs as the “.com” button.
I’ve gotta say: it’s little touches like this that help the interface get the hell out of the way of whatever it is you’re trying to do.
I just noticed something odd in the price of different Playstation 3 models: Amazon.com’s PS3 page has:
Playstation 3, 120 Gb: $299.99
Playstation 3, 250 Gb: $414.99
From this, we can work out the price per gigabyte: ($414.99 – $299.99) / (250 – 120) = $0.8846 $/Gb.
That’s not the odd part. Since I have some old Playstation 2 games, ideally I’d like a PS3 that’s backward-compatible with the PS2. According to Wikipedia (which can be relied on, here, since it’s a nerd topic), those are the 20 and 60 Gb models, as well as some 80 Gb ones.
Again from Amazon, we have:
Playstation 3, 20 Gb: $229.99
Since this has 100 Gb less than the 120 Gb model, we would expect it to cost 100 × $0.8846 less, or $211.53. But it costs $229.99, or $18.46 more. So that $18.46 must be the price of PS2 compatibility.
Now we get to the odd part:
Playstation 3, 60 Gb: $849.99
We would expect this to cost $299.99 (the price of a 120 Gb model), minus 60 × $0.8846 = $53.08 because it has 60 Gb less storage, plus $18.46 for PS2 copmatibility, for a total of $265.37. So why is the real cost over $500 higher?
All I can figure is that the 60 Gb disk is a lot bigger than a 20 Gb disk, leaving less free space inside the case. So the PS2 compatibility has to be built out of smaller components, which are vastly more expensive.