New tool: sednames

 

2008-06-20 21:21:10 UTC

What if you could use sed to rename files?

Well, now you can.

sednames is a utility that lets you specify a program for sed on the command-line, which it then uses to rename the files that you also specify on the command-line.

The twist is that, unlike other batch-renamers, sednames also supports your VCS. For the most common cases (svn, hg, bzr, and git), there's a --vcs option:

% sednames -e 's/Replace/Mix/' --vcs=hg *

This command-line will use Mercurial (hg mv) to rename every file by replacing “Replace” with “Mix”. Of course, if a name doesn't contain “Replace”, then that name will be unchanged and sednames is smart enough to not try to rename that file.

Not only that, but just in case you're using some oddball VCS (or you want to copy instead of rename, or something), sednames supports using any program to rename your files, as long as it accepts both the before and after names in its arguments. The --help output is more specific, but to put it simply, it works similarly to find's -exec option.

You can download the current revision directly, or use the Mercurial repository to follow or contribute to its development.

Free stuff on iTunes: Cable TV

 

2008-06-17 13:06:47 UTC

From the podcast directory, some free cable TV talk shows. All of these carry (what appear to be) full episodes:

Note: I don't endorse any of these shows, and purposefully listed them in alphabetical order.

So you're using the unicode class's translate method, and it says:

TypeError: character mapping must return integer, None or unicode

You may be wondering what causes this. After all, you're duly using the string.maketrans function. Surely this should be valid?

Well, no: You can only use string.maketrans with str.translate. For unicode.translate, you must use a different kind of translation table:

… a mapping of Unicode ordinals to Unicode ordinals [int], Unicode strings [unicode] or None.

3.6.1 String Methods

In Localization Helper, I had to replace my string.maketrans call with this code:

dict(zip(map(ord, u'\a\b\t\n\v\f\r'), u'abtnvfr'))

Note that I need to call ord on each key character, because keys must be ints.

New tool: Localization Helper

 

2008-06-16 08:48:05 UTC

One thing that I noticed a few days ago while working on Growl 1.1.4 is that some strings aren't translated in a couple of the localizations. I reported this on our localization mailing list, but it got me thinking: I could really use a program that would scan a tree of source code and tell me of problems like this.

So I wrote one.

Localization Helper is a command-line tool to walk a tree of source code looking for .strings files, and compare different localizations of them. It reports duplicate (not-translated) strings, and will soon (maybe by the time you read this) report strings that are missing altogether.

Currently, it only compares all other languages to one primary language, which defaults to English. I didn't feel like making it compare every language to every other language. ☺

The program scans every directory you specify on the command-line. If you don't give it any arguments, it scans the current working directory. Also, it has some options, which you can see with the --help option.

Here are some excerpts of its output for the Growl 1.1.3 source code:

*** Found problems in Core/Resources/*.lproj/Localizable.strings
Duplicate strings in Localizable.strings between English.lproj and cs.lproj:
"User went idle" = "User went idle";
"You are now considered idle by Growl" = "You are now considered idle by Growl";
"No activity for more than %d seconds." = "No activity for more than %d seconds.";
"Growl was unable to create the socket for Network notifications." = "Growl was unable to create the socket for Network notifications.";
"You are no longer considered idle by Growl" = "You are no longer considered idle by Growl";
⋮
!!! Warning: Localized file Extras/GrowlSafari/de.lproj/InfoPlist.strings is missing
!!! Warning: Localized file Extras/GrowlSafari/ja.lproj/InfoPlist.strings is missing

*** Could not read plist file at path Extras/GrowlSafari/de.lproj/Localizable.strings
*** Could not read plist file at path Extras/GrowlSafari/ja.lproj/Localizable.strings
*** Could not read plist file at path Extras/GrowlSafari/pt_BR.lproj/Localizable.strings
*** Could not read plist file at path Extras/GrowlSafari/sv.lproj/Localizable.strings

You'll need to have either Leopard or Python 2.5 + PyObjC (Leopard comes with both) to use the program. (BTW: PyObjC rocks.)

Until I release it sometime later this week (hopefully), I provide two ways to get the program:

  1. You can download it directly.
  2. You can clone my repository: hg clone http://boredzo.org/localization-helper/hg/

Of course, if you clone your repository, then you can easily get updates by running hg pull.

Also, there's a commits feed, in case you want to stay on top of localization_helper's development using your feed reader.

Growl 1.1.3

 

2008-06-06 14:30:10 UTC

I just released version 1.1.3 of Growl. Some highlights from the version history:

  • Worked around conflict with Logitech Control Center 2.4, and implemented countermeasures in case another input-manager hack in the future has the same bug
  • Show notifications on every Space (Leopard)
  • Rewrote GrowlMail to fix conflict between it and Leopard, and make it much more robust for the future
  • Updated GrowlSafari to work with Safari 3.0 and later (thanks to Ben Willmore)
  • Fixed growlnotify to actually send the notification on Leopard
  • Fixed a hang on changing the default display
  • Fixed displaying a close widget on mouse-over

Those aren't the only improvements, but they're the most major. Growl and its extras are finally completely Leopard-ready.

You can download 1.1.3 either from the About tab in the Growl preference pane, or from the website.

In other news, this is my first release as the Lead Developer of Growl. I'm replacing Brian Ganninger, who was (IIRC) Lead Developer for the entire 1.1 series. Let us all thank him for his excellent work, and wish him well for the future.

WWDC Survival Guide

 

2008-06-05 18:46:58 UTC

I'm not attending WWDC this year (sorry!), but I did attend last year, so I have some advice for those of you attending for the first time (and I hear there are a lot of you).

  1. Walk.

    San Francisco isn't designed to handle car traffic—it's optimized for pedestrians, in several ways:

    • Most streets are one-way, meaning that a car must take a longer route than a pedestrian can.
    • The walk/don't walk signals don't have buttons, because you don't need them. When drivers get the green light, pedestrians get the walk signal—every time.
    • Almost all parking costs money per hour. Walking is free.
    • Parking is so sparse that you'll walk one or more blocks anyway. So, if you can walk from your hotel to Moscone and back, do so. You'll get there faster and more cheaply.
  2. Don't eat the lunch.

    The objects that Moscone serves as lunch are not food. Food, by definition, is edible. Eat out.

    Note that I'm only talking about lunch. Moscone serves food at other times of day: a mid-afternoon snack, and dinner. These are OK, and sometimes even pretty good. Only the lunch is inedible.

  3. Attend parties, or make your own.

    If you're at WWDC with some friends or colleagues, you may be able to work on some code with them at the conference. This is a lot of fun, especially if you can get together around a power strip.

    Either way, you may want to attend other parties. Some parties are listed on Upcoming. Additionally, there's CocoaHeads meeting at the Apple Store on Stockton St on Tuesday. If you know any others, please post a comment here and I'll link to them. (However, I'd stay away from the Thirsty Bear pub. The acoustics in that place are terrible. Forget conversation.)

  4. Bring your (US) AC adapter.

    They have charging stations at the conference, but the week I was there, the MBP chargers were broken. They never did get them fixed. I ended up buying a second AC adapter at the Apple Store.

    Additionally, Tim Burks recommends bringing a power strip—a good idea if you and your friends/colleagues intend to hack code together at the conference. More specifically, Mark Boszko recommends Monster Cable's (yes, them) Outlets to Go. He also notes the existence of 3- and 6-outlet versions, which you may prefer, depending on how much space you have in your bag.

  5. Grab a copy of The Onion.

    You may or may not know this, but The Onion is not just a website and series of books—it really does exist as a newspaper. It's available for free in newspaper racks in select cities, including San Francisco. I'm sorry, but I don't remember where the rack I got mine from was—I think it was on Market Street, but I don't remember the cross-street.

Some good eating places:

Enjoy the WWDC!

Also, be sure to read the comments on this post! Already, Jonathan Wight has made two very wise suggestions. You may also want to check back periodically so you don't miss any.

Things your ReadMe must include

 

2008-05-20 00:23:27 UTC

  • The name of your application
  • What it does
  • How to configure the application, if necessary (note: does not include installation)
  • Simple overview of how to use the software, once it's configured (detailed manual should be in the Help menu)
  • How to uninstall the software, if necessary (i.e., if it isn't an application)
  • FAQ
  • What it costs, if it's not free
  • How to register it
  • A link to your website (in case a magazine distributes your app on its CD)
  • Contact information for support questions
  • Contact information for sales (registration/pricing/currency) questions

Things that you may want to include, but aren't necessary

  • Screenshots
  • Troubleshooting information

Things that you shouldn't include

  • Installation instructions: If it's a plain app, you don't need an installer; otherwise, make an Installer .pkg. In either case, you shouldn't need instructions.

Formats I approve

  • RTF or RTFd
  • HTML or webarchive
  • Plain text

You may also want to provide a trampoline application to open a localized version of your ReadMe (for example, see the ReadMe on the Mac OS X DVD). Bonus points if you create a kit to make these, for the benefit of other developers.

Formats I disapprove

  • Word or OOXML format: Many people don't have Word, and everything else handles these documents imperfectly. Use RTF instead.
  • OpenOffice format: Many (probably most) people don't have OpenOffice. Use RTF instead.
  • PDF: Use PDF either for vector graphics (inside your app) or for documents you expect someone to print. If the user is going to have to print your ReadMe, you need an interface overhaul.

As usual, I invite suggestions, rebuttals, and amendments.

UPDATE 2008-05-24: Recommended including contact information, as suggested by ssp.

What I want: A “best of” plug-in

 

2008-05-18 21:36:00 UTC

I want a plug-in for WordPress that will do two, or maybe three, things:

  1. Put a “flag as best of” button on any post that I've authored. (I would have to be logged in.)
  2. Provide a function to insert a div containing n=10 random best-of posts. I could then call this function from the sidebar.
  3. (Optional) Provide a single public page containing a link to every best-of post.

Does a plug-in like this exist already? If not, I'm not afraid to write it.

Last week, John Gruber and Dan Benjamin released episode 20 of their podcast, The Talk Show. It was devoted to the Apple Extended Keyboard (the Saratoga) and Apple Extended Keyboard II (the Nimitz). This renewed my interest in bringing my own Nimitz back into service using a Griffin iMate.

The Nimitz is the greatest keyboard ever made for the Macintosh. It has the best keys, the best height adjustment, the best Caps Lock key (it physically locks down!)—everything.

One of its distinctive features is a couple of pegs near the top of the keyboard—one near the Escape key, and another near the Power key.

The Saratoga had, printed under the F1 through F4 keys, the words “undo”, “cut”, “copy”, and “paste”. Because these definitions were useless (not to say confusing) to most Mac users, the Nimitz moved these labels to a plastic overlay that came with the keyboard. Those who actually needed it could put it on, which they did by hanging it on those two pegs, and everyone else could simply leave it in the box.

This is a photo by Flickr user penmachine (Derek K. Miller) of an Apple Extended Keyboard II with Apple's overlay, cropped to show the corner of the overlay hanging around the Power key.

That overlay is even more useless today. But I think the idea of an overlay defining the function keys is a good one, especially as Mac OS X has made the function keys actually useful.

So I decided to make a new overlay.

This one does not have the seldom-useful F1–F4 labels. What is <em>does</em> have is labels under F9–F12, listing their default Mac OS X actions (the three kinds of Exposé, plus Eject).

My original plan was to distribute the EPS file for this overlay, and provide instructions on how to customize it.

After writing that it's easy to edit the file, followed by an entire page of instructions on how to do that properly, I decided it would be better to write an application to do it for you. I call this application the Apple Extended Keyboard II Overlay Generator.

I've included with the application two ready-made overlays: a replica of the classic Apple overlay; and my Mac OS X overlay. You also have the option of editing them or creating your own from scratch.

Assembly instructions (among other information) and the download are on the webpage.

Blog spam count: 2008-04

 

2008-05-01 19:57:34 UTC

Spam comments blocked by Negative Turing Test in April 2008:

44,573

Blog spam count: 2007-11 through 2008-03

 

2008-04-01 12:10:51 UTC

Average number of spam comments blocked by Negative Turing Test in per month from the start of November 2007 through the end of March 2008:

6,529.8

Total number of spam comments blocked by Negative Turing Test in the same time period:

32,649

Note that this is only on my blog, not any other blogs that use NTT.

Under my MacBook Pro, I use a Targus Laptop Chill Mat. The Chill Mat is an active-cooling pad: it contains two fans that suck in air at the top (i.e., between the laptop and the mat) and thrust it out the back.

And it is a piece of crap.

I'm currently on my second Chill Mat. The first one died when the connector in the mat went loose, so that the cable's connector no longer made a good connection with it. I sent that one in for warranty service, and got back the one I was using up until a few days ago. The way this one died is that the inline power switch on the cable is now permanently off, and just flops around; I cannot turn it on.

Looking at the website in preparation for this post, I noticed that the Chill Mat shown on the website looks different from mine. Maybe they've redesigned it, and the hardware is more reliable now. I intend to investigate this.

But, if that fails, I have three choices:

  1. Send this thing in for warranty service again.
  2. Surgically remove the inline switch, and hope the connector doesn't flake out.
  3. Get a different active-cooling pad.

I'm seriously considering #3, but I'm not sure of my options. (I am definitely not open to passive-cooling solutions such as Targus' coat rack.) Having made one bad choice before, I now turn the decision over to you.

Can you recommend a good USB-powered active-cooling pad for a 15″ MacBook Pro?

“Photoshop sucks” updated

 

2008-03-23 17:33:51 UTC

Upon inspiration by a comment, I've just updated my rant from a couple years ago, “Photoshop sucks”, to include a list of alternatives. Topping the list, of course, is Acorn; also included are Core Image Fun House, Pixelmator, DrawIt, and Iris.

I'm very glad that there are now solutions to the problem that is Photoshop. I dislike bitching about something without a solution to offer; now I have six to offer, so that rant is now complete.

Apple Bug Friday! 75

 

2008-03-21 19:44:43 UTC

This bug is TN2083 doesn't document all known Session types. It was filed on 2008-01-19 at 16:44 PST.

Read the rest of this entry »

UTI Property List Helper 1.0

 

2008-03-21 10:33:15 UTC

For a forthcoming blog post, I was recently writing a test app that displays images. This had me once again slogging through the list of System-Declared Uniform Type Identifiers and assembling type declarations for the image types by hand.

I'm tired of doing that. So I wrote a new application called UTI Property List Helper.

The main window consists of a table view, in which you enter UTIs, and two text views displaying chunks of Info.plist XML data.

This application automatically updates the CFBundleDocumentTypes and UTImportedTypeDeclarations arrays in its window with information on the types you enter, obtained from Launch Services' database of all types registered by any app on your system.

No more searching for that OSType, or leaving it out because it's too much work—this app does all the grunt work for you. Enjoy.

.hgignore for Mac OS X applications

 

2008-03-20 05:37:06 UTC

If you use version control (and you should), then you're familiar with the pollution that an Xcode build folder can put into your status output:

? build/.DS_Store
? build/Debug/UTI Plist Helper.app/Contents/Info.plist
? build/Debug/UTI Plist Helper.app/Contents/MacOS/UTI Plist Helper
? build/Debug/UTI Plist Helper.app/Contents/PkgInfo
? build/Debug/UTI Plist Helper.app/Contents/Resources/English.lproj/InfoPlist.strings
? build/Debug/UTI Plist Helper.app/Contents/Resources/English.lproj/MainMenu.nib/classes.nib
? build/Debug/UTI Plist Helper.app/Contents/Resources/English.lproj/MainMenu.nib/info.nib
? build/Debug/UTI Plist Helper.app/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
⋮

Good version-control systems offer a way to ignore any file that matches a certain pattern. In the case of an Xcode project, you want to ignore the build folder and a few other things: .DS_Store files, backup nibs (those Foo~.nib packages that IB creates when you save), etc.

In Mercurial, the way to do that is to create a .hgignore file, and populate it with the patterns you want hg to ignore.

In order to save you repetitive work, here's a .hgignore file, already fully-populated, that you can use when versioning your Xcode-based project with Mercurial:

File: hgignore.bz2

syntax: glob

.DS_Store

*.swp
*~.nib

build

*.pbxuser
*.perspective
*.perspectivev3

What to do with this file

  1. Download it, and save the .bz2 file somewhere such as your Documents folder.
  2. cd into the top level of a repository.
  3. Extract the file using this command line: bunzip2 < ~/Documents/hgignore.bz2 > .hgignore
  4. Add the file: hg add .hgignore
  5. Commit it.

Thereafter, not only do you have a .hgignore file keeping your status output clean, but it's versioned, so it's easy for you to track and revert changes to the ignore file over time.

A public thank-you

 

2008-03-17 00:07:16 UTC

This goes out to whichever engineers at Apple fixed the Image Unit template to not suck.

Before Xcode 2.5, that template was useless. Now, it contains everything I need already set up, to the maximum extent possible.

Thank you, Apple engineers.

The Sinister Divide

 

2008-03-16 15:02:07 UTC

In Dvorak, the Sinister Divide is between y and f, between i and d, between k and x, and between 6 and 7.
In QWERTY, the Sinister Divide is between t and y, between g and h, between v and b, and between 6 and 7.

UPDATE: Sören Nils Kuklau, in a tweet, pointed me to another person's blog post about these people, which tells of a C&D letter they received from Domain Registry of America. Not sure what I'll do if I get such a nastygram.


When you own your own domain name, you tend to get shit like this in the mail:

The lowest third of a letter from “Domain Registry of America”, looking very much like a bill.

That's actually the lowest third of a folded letter. So when you first take it out of the envelope, it looks like a bill. Only when you unfold it do you see that it's not quite a bill:

The full letter from “Domain Registry of America”.

I think that they intend for you to see the looks-like-a-bill part of it, conclude that it's a bill, and pay it—and thereby switch your domain name registration over to them.

The back of the letter contains the “registration agreement”:

Paragraph after paragraph of legalese.

I didn't bother to read all of that text (I have no intention of agreeing to it anyway), but I did notice this bit at the top:

This Registration Agreement (“Agreement”) sets forth the terms and conditions of your use of domain name registration and related services (“Services”). In this agreement “you” and “your” refer to you and the registrant listed in the WHOIS contact information for the domain name. “We”, “us” and “our” refer to eNom, Inc., Wild West Domains, Inc., BRANDON GRAY INTERNET SERVICES INC. (dba “NameJuice.com”), and DROA

Emphasis mine. So not only are these people trying to bullshit their way into being my registrar, but they're not even a registrar—just a reseller for eNom, and two other companies I've never heard of.

By the way, the type in that agreement is really freaking small. I measured the capital A at the end of that first paragraph, and found that it's exactly 1 mm tall.

So whenever you get anything in the mail about your domain name, read it VERY thoroughly. Especially don't trust anything that doesn't come from your registrar.

Multiple methods found

 

2008-03-14 04:56:18 UTC

I wrote some code like this:

[[QTMovie movieNamed:sound error:NULL] play];

and Xcode gave me three warnings:

  • GrowlApplicationController.m:537: warning: multiple methods named ‘-play’ found

    • /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/AppKit.framework/Headers/NSSound.h:47: warning: using ‘-(BOOL)play
    • /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/QTKit.framework/Headers/QTMovie.h:340: warning: also found ‘-(void)play

All warnings are bad, but these are even worse: The compiler is telling me that it's picked the wrong method. I'm creating a QTMovie, so I want it to use -[QTMovie play] (the one that returns void), but it picked -[NSSound play] (the one that returns BOOL).

Now, in this case, it won't matter, thanks to Obj-C's dynamism—all it will do is send a play message to the object, and the object will use whatever play method it knows about. In other words, despite what the compiler is telling me, the program will actually call the correct method (the one in QTMovie).

But this could be a lot worse. If I'm expecting, say, a structure type, and the compiler picks a method that returns a scalar type such as int or float (or vice versa), the compiler will write the wrong assembly code for the message. My method will get gibberish back from the method it called, and Bad Things will follow.

The reason for this  problem is that +movieNamed:error: returns an id—not a QTMovie * specifically. For all the compiler knows, that method returns an NSSound *, or even an NSUserDefaultsController *.

Since the compiler doesn't know what type the method returns, it must pick one from all the methods by that name that it knows about. You can't rely on it picking any particular one, and I could only guess as to how it makes its choice. For all I know, it's blind chance.

The ugly and naïve solution would be to tell the compiler what type we're expecting by casting it:

[(QTMovie *)[QTMovie movieNamed:sound error:NULL] play];

Of course, besides being ugly, this specific code still has the problem of not accepting an error object. What I should do, and will do, is accept the error object and stash the returned movie in a variable, so that I can test it and then either report the error or play the movie.

NSError *error = nil;
QTMovie *movie = [QTMovie movieNamed:soundName error:&error];
if (movie)
    [movie play];
else
    [NSApp presentError:error];

This code is longer, but it will always use the correct method and it doesn't ignore the error. (You may also have noticed that I change the previously-misleading name of the name variable from sound to soundName.)