Archive for March, 2008

The Targus Laptop Chill Mat is a piece of crap

Sunday, March 30th, 2008

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

Sunday, March 23rd, 2008

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

Friday, March 21st, 2008

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

(more…)

UTI Property List Helper 1.0

Friday, March 21st, 2008

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

Thursday, March 20th, 2008

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
build
*.swp

*.mode1
*.mode1v3
*.mode2
*.mode2v3
*.pbxuser
*.perspective
*.perspectivev3
xcuserdata

*~.nib

.DS_Store

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.

UPDATE 2011-05-05: Updated for Xcode 4.

A public thank-you

Monday, March 17th, 2008

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

Sunday, March 16th, 2008

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.

Beware of potential domain registrar scammers

Saturday, March 15th, 2008

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

Friday, March 14th, 2008

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.)

hg st says modified, but hg diff doesn’t say anything

Tuesday, March 11th, 2008

You have a puzzle. When you run hg st, it says one of your files is modified:

hg st                                                              %~/Python/run_tests(0)
M test.py

But when you run hg diff, it doesn’t say anything about the file:

hg diff test.py                                                    %~/Python/run_tests(0)
___
                                                                   %~/Python/run_tests(0)

The reason, at least in my case, was that the file’s permissions had changed. hg st acknowledges this change exactly the same way it acknowledges a change to the file’s contents, but hg diff only shows changes to the contents of the file, not the metadata. Thus, a metadata change only gets reported by hg st and not by hg diff.

While I prefer hg over svn, this is one advantage that svn has over hg. hg only uses one column to indicate the type of change, and shows the same letter (M) for metadata changes as for content changes. svn, on the other hand, uses seven columns, and a metadata change puts the M in a different column.

There’s no way to make hg st use the svn st format, but you can make hg diff show metadata changes. The way to do this is to edit your hgrc file and enable git mode:

[diff]
git=True

There are two hgrc files; you can choose to change either or both. You can edit ~/.hgrc (this is what I recommend), or you can edit the per-repository .hg/hgrc file. (There is no .hg/hgrc file by default, so if you haven’t created one already, you would need to create it.)

The difference, as you’ve probably guessed, is that ~/.hgrc sets hg’s default for all repositories, whereas the per-repository hgrc changes the setting only for one repository, overriding ~/.hgrc and hg’s own defaults.

Once you make this change, the output from hg diff will include metadata information:

hg diff test.py                                                    %~/Python/run_tests(0)
diff --git a/test.py b/test.py
old mode 100755
new mode 100644
___
chmod a+x test.py                                                  %~/Python/run_tests(0)