ISO 8601 parser

I finally finished (more or less) my ISO 8601 parser for Obj-C. I'll be using it in my TTL patches for Vienna and Feed, and Colin will use it in the Adium XML logging code.

Right now I'm working on an unparser, for creating a string from an NSCalendarDate. Colin will be using that too. I think he'll be posting more about it on the Adium blog when it's in.

Technorati tags: .


Report-an-Apple-bug Friday! 42

This bug is PackageMaker (and Installer?) does not support EPS, PDF, or SVG in packages. It was filed on 2006-05-19 at 02:20 PDT.


PackageMaker/Installer should support the use of EPS, PDF, or SVG image files in Installer packages.

Steps to Reproduce:

  1. Create a package in PackageMaker.
  2. On the first step of the Interface Editor, drag a EPS, PDF, or SVG file onto the window, or click Custom Background Picture and choose a EPS, PDF, or SVG file.

Expected Results:

The EPS, PDF, or SVG file is accepted as the background of the package.

Actual Results:

The EPS, PDF, or SVG file snaps back (drag), or is disabled in the list (choose file).


As far as I know, Installer has never supported EPS, PDF, or SVG files.


Vector graphics would scale cleanly to any resolution, which is good for the coming resolution-independent UI. Currently, it is necessary to use a large and/or multi-image TIFF file, and hope that it's enough.

Technorati tags: ,

Report-an-Apple-bug Friday! 41

This bug is PackageMaker (and Installer?) does not support PNGs in packages. It was filed on 2006-05-19 at 02:00 PDT.


PackageMaker/Installer should support the use of PNG image files in Installer packages.

Steps to Reproduce:

  1. Create a package in PackageMaker.
  2. On the first step of the Interface Editor, drag a PNG file onto the window, or click Custom Background Picture and choose a PNG file.

Expected Results:

The PNG file is accepted as the background of the package.

Actual Results:

The PNG file snaps back (drag), or is disabled in the list (choose file).


As far as I know, Installer has never supported PNG files.


PNG supports compression, for smaller Installer packages. True, Installer packages are often distributed on compressed disk images or in compressed zip archives, but PNG can “filter” the image bytes to be more compressable, resulting in greater savings.

Technorati tags: ,


A thought experiment: Negative money

Excerpt (with permission) from the Adium channel on IRC.

00:51:25: <Mac-arena> Heh, I just had a wacky idea.
00:51:38: <Mac-arena> Replace the 1- and 5-cent coins with +2- and -3-cent coins.
00:51:55: <Mac-arena> So, for example, 7 cents would be a dime and a -3. 9 cents would be a dime, a +2, and a -3.
00:52:10: <Catfish_Man> people don't want to carry negative money dude
00:52:19: <Catfish_Man> it's like debt that weighs something
00:52:18: <Mac-arena> It would make robberies interesting.
00:52:33: <Mac-arena> Robbers would run up to people and shove rolls of -3s into their pockets. :D
00:52:39: <Catfish_Man> hahaha
00:53:05: <LostBurner> lol
00:53:45: <LostBurner> people couldn't even handle that kind of math though
00:53:59: <Mac-arena> I know. It'd have to be smart people's money.
00:54:09: <Mac-arena> Only usable by people with a certain level of brightness.
00:54:23: <LostBurner> smart people would throw away their negative money
00:54:52: <Mac-arena> The other way would be to cast it as a status symbol.
00:54:58: <Mac-arena> "Only the cool people use negative money."
00:56:51: <LostBurner> So you'd give someone a real dime, and a negative 3
00:56:59: <LostBurner> Presumably you've given them 7 cents
00:57:08: <Mac-arena> Right.
00:57:13: <LostBurner> but you're out a whole dime
00:57:16: <LostBurner> and they're up a whole dime
00:57:29: <Mac-arena> No. Because you're also out a negative three, and they've gained one.
00:58:15: <LostBurner> So would you say that it was a better transaction if you could give someone more negatives?
00:58:29: <Mac-arena> Yup.
00:58:34: <LostBurner> Dime and 3 neg3 coins, ooh you've only spent a cent
00:58:46: <Mac-arena> Yup.
00:58:55: <LostBurner> but then you could make money by throwing them away!
00:59:04: <Mac-arena> Yup. That's the only problem.
00:59:17: <LostBurner> Negative monies only count if you can force the person to keep them
00:59:24: <LostBurner> hey, negative monies... that reminds me
00:59:38: <LostBurner> did you get this inspiration from aarond?
00:59:38: <Mac-arena> That's actually where I got the idea.
00:59:39: <Mac-arena> 00:39:01:   <aarond> I have minus monies :)
00:59:50: <LostBurner> I beat you to that one by 1s
00:59:52: <LostBurner> I knew it!
01:00:32: <Mac-arena> Anyway. If you pay a retailer with -3s, and they throw them away, YOU haven't re-lost any money.
01:01:00: <Mac-arena> Unless you went around back and picked them up so that you could spend them again.
01:03:43: <LostBurner> besides, it takes more coins with your way to pay for something
01:04:03: <Mac-arena> Depends on the amount.
01:04:25: <LostBurner> Average of the number of coins needed for each of the first ten integers
01:04:36: <LostBurner> your way: 2.8
01:04:50: <LostBurner> current way: 2.6
01:04:16: <Mac-arena> And actually, we're thinking about it wrong.
01:04:35: <Mac-arena> You wouldn't necessarily have to give the seller anything. If it cost 9 cents, say, they could give you three -3s.
01:04:52: <Mac-arena> Though if it cost two cents, you could give them a +2.
01:05:47: <LostBurner> Mac-arena: the idea is an interesting thought experiment, but it's entirely implossible.
01:06:51: <LostBurner> (impossible and implausible)
01:07:03: <LostBurner> hehe, I could see cops citing you for dumping your neg3s
01:08:23: <LostBurner> I just remembered the blank media tax for supposed intended piracy
01:08:24: <LostBurner> grr
01:09:40: <Mac-arena> Ooooh. Suppose you paid your taxes in negative money.
01:09:54: <Mac-arena> Send them a box full of -3s.
01:10:18: <Catfish_Man> they'd just send it back with more :P
01:10:25: <Mac-arena> Hahaha. True.
01:10:29: <Catfish_Man> hell, they'd charge taxes by shipping you -3s


New MacBooks, but...

The new MacBook is out, replacing the iBook. The upside, besides now being an ICBM, is that it now comes in black. The downside is that the screen is glossy.

MacBook webpage, with “13-inch glossy widescreen display” highlighted in red.

You see this a lot on PC laptops made in the last few years. Sure, the colors are beautiful on such a display — but there's so much glare! If I wanted a mirror in my computer, I'd just launch iChat and use the iSight as one.

This in addition to my usual lack of desire for a laptop. I won't be buying one.

Technorati tags: .



Certainly one of my simplest applications ever.

A screenshot of the swatch window, set to white, with the Color Panel in front of it.

You can download it from the GiantColorSwatch webpage.

How to make Photoshop open your EPS file

Sometimes, when I want to draw a graphic, I write it instead. I write it in PostScript, as an EPS file, and then convert to whatever destination format I want.

The problem with this plan is that I was never able to get Photoshop to import the EPS directly. I always got this error message:

Could not open “foo.eps” because the parser module cannot parse the file.

Finally, today, I went looking for the solution. I used strings to see what the EPS Parser plug-in looks for. I found it in under a minute.

So, at minimum, this is what your EPS file must contain:

%!PS-Adobe-3.0 EPSF-3.0 %%BoundingBox: 0 0 width height %%EndComments

The %%EndComments line is the one that I was missing. Make sure yours isn't missing it too.

In case you want to know more, these special comments (% is the comment character in PostScript) are defined by the Document Structuring Conventions. EPS is an application of DSC.

Technorati tags: , , , .


Report-an-Apple-bug Friday! 40

This bug is IB refuses to keep pop-up menus open. It was filed on 2006-05-12 at 02:33 PDT.


IB closes a pop-up menu being edited in response to any key or mouse event in the menu.

Steps to Reproduce:

  1. Drag a pop-up button into a window in a nib.
  2. Double-click on the pop-up button to edit it.
  3. Change the selection by clicking on any item, or pressing up or down. Or, double-click on an item to rename it, then press return or enter or change the selection.

Expected Results:

The current selected item changes, or is renamed, or both.

Actual Results:

The current selected item changes, or is renamed, or both, and then IB closes the menu, interrupting any plans to further edit the menu until the menu is reopened by the user.


This used to work, although I don't know in what version.


No Console output is emitted by IB.

UPDATE 2006-05-24: I got an email from Apple recently telling me that the bug was a duplicate, and just today, Xcode 2.3 came out, including IB 2.5.4 which fixes this bug.

Technorati tags: ,


Why iTunes videos are not widescreen

One of the most frequent complaints about the iTunes Video Store is the resolution. All videos are 320×240.

The reason why lies on Apple's iPod specifications page:


  • 2.5 inch (diagonal) QVGA transflective, over 65,000-color liquid crystal display with white LED backlight
  • 320 x 240 pixel resolution, .156-mm dot pitch

Let's say that iTVS sold shows in their native resolution. Joe User buys a show that comes in 720p HD (a 16:9 resolution). He transfers this to his iPod, and watches it on the train. What does he say as soon as the title screen comes on?

"Wow, this sucks. They cut off the top and bottom of the video. I won't be buying any more TV shows from iTunes again."

What happened?

Well, remember that the iPod's screen has a 4:3 aspect ratio. If you show all of a 16:9 video frame on it, you have empty vertical space — usually manifest as black matte above and below the frame, called "letterboxing" (because it's like looking through a mail slot). Joe User has a screen of a certain height, and the video is not filling that height, so he assumes that the video has been cut.

The other solution is to cut off part of the frame, so that the height is filled, at the expense of the left and/or right end(s) of the frame (called "pan and scan" because the crop must be moved back and forth to keep the important part in-frame). This, in fact, is what Apple does: the videos you buy from Apple have been pre-cut to fit the iPod's screen. Joe User is happy, even though he is in fact seeing fewer pixels than before.

Aspect ratio isn't the only issue; there's also the sheer number of pixels to put on the screen. You can't fit all of a 720-line-high frame onto a 240-line-high screen, unless you scale it. That takes CPU power, which in turn uses up battery life and may reduce the framerate. Apple does that heavy lifting in advance, so that your iPod doesn't have to.

There's a third solution: Make the iPod's LCD widescreen. This means doing one of two things to it:

  1. Cut off 60 vertical pixels, changing the iPod's resolution to 320×180.
  2. Add 106+⅔ horizontal pixels, further reducing the size of each pixel. One advantage would be that it would further help hide compression artifacts.

The problem with both solutions is that they make it harder to browse music. Vertical space counts here (for scrolling menus); horizontal space is not as important. And the iPod is still a music player first.

I think that Steve Jobs looked at all of this and decided that the iPod Video as implemented is the best way he could come up with. And if so, I agree.

Technorati tags: , , , , , .

How to create a RAM disk

I just posted to this lisppaste with a punt solution. Since this solution really has nothing to do directly with the problem stated, I thought I'd share it with you as well, with HTMLization and some editing from the original.

  1. hdid -nomount ram://num_sectors (sector = 512 bytes = 0.5 K)

    This outputs a device path (/dev/foo) on stdout.

  2. newfs_hfs -v volume_name device_path

    Formats the RAM disk as HFS+. See the manpage for other options.

  3. diskutil mount device_path

    The RAM disk will be mounted at /Volumes/volume_name.

You could also do something involving mount(8) instead of diskutil if you wanted to mount it inside NSTemporaryDirectory(). Remember to unmount it (hdiutil detach device_path, or the Eject command in the Finder or Dock) when you're done.

Technorati tags: .

Small world (and: Iron Coder v1!)

So I was uploading a fixed version of one of the screenshots on my Sand Sand Sand blog post, and decided on a whim to look at some of the stats for some of the other pages on my still-temporary (really!) GeoCities site.

Looking at the stats for my plus/minus images, I saw that the #1 referrer (besides "Unknown") is Jonathan Rentzsch's del.icio.us. "Cool," I thought, "Jonathan Rentzsch bookmarked my plus/minus images."

And as I was scrolling down his del.icio.us page, looking for the link to my plus/minus page, I stumbled upon some news: Iron Coder v1 is coming! Huzzah!

I don't know yet whether I'll participate. I'm still residually tired from the last one. It might depend on the API and the theme, and how much work I have as a mentor in Summer of Code.

Technorati tags: Iron Coder.

Some English rants

I've been compiling a list of maltreatments of the English language. Here are my top 10 so far.

  • compatability; definate(ly); desparate(ly); seperate(ly)

    You mean compatibility, definite(ly), desperate(ly), and separate(ly) (respectively). The first one arises from confusion with "ability", and certainly the conflation of "desperate" with "separate" is easy enough. I don't know what excuse there is for "definate".

  • compl[ie]ment

    A compliment is praise. A complement is the inverse of something (for example, 0b101010 is the two's one's (thanks, CHz!) complement of 0b010101, and a film negative is the complement of the positive print).

  • [ae]ffect

    When you affect something, you effect a change in it.

  • Held accountable

    Can't happen. A person is accountable if they can be held to account.

  • classified

    Classified what? USDA Choice? The correct usage is "classified secret".

  • X Department (of the United States Cabinet, e.g. State Department)

    You wouldn't say "United States State Department", would you? No, you wouldn't, because that sounds redundant. It's "Department of State". Also "Department of Defense", "Department of Energy", "Department of Justice", etc. Some of the Departments have a "the", like the Department of the Interior. But deviation from the rule doesn't go beyond that.

  • Dilemma (as problem)

    A lemma is a course of action or line of reasoning (dictionaries define it as a subsidiary proposition … used to demonstrate a principal proposition; in this case, the principal proposition is often a course of action). A dilemma is two of these, from which a person must choose. Not every difficult problem is a dilemma.

  • "Welcome to …" (telephone system, website, etc.)

    "Welcome to" should only be used for a place. "Welcome to Huntington Beach, population 189,594". It should never be used for anything else, including web sites and phone systems. When I hear "Welcome to (mumble). Please choose from the following selections:", I want to reach through the phone and unplug that answering system.

  • Lower 48 states, Continental United States

    First, Hawaii is lower than the lower 48. Technically, the lowest 48 states include Hawaii and exclude Maine. Also, "lower" would be only correct when there are two (e.g. "lower case" vs. "upper case"). We have never had fewer than 13.

    As for "continental United States", you have to include Alaska on this one. It's on the same continent.

    Just use "contiguous United States".

  • x, y and z

    No, no, and no. Use the "serial comma", the comma after the second-to-last element in the list. It just looks better that way. (This does not apply when the list has two or fewer elements.)

Technorati tags: .


Some notes about Sand Sand Sand

I've been playing Sand Sand Sand lately. It's the successor to World of Sand, and it has some important additions.

  • Water now exhibits waves. This means very little, except that it is now impossible to get a perfectly level field of Water.

  • Salt now mixes with Water. Saltwater sinks in plain Water, but other than that, possesses no buoyancy; other substances (besides Water) are suspended in it, rather than floating or sinking.

  • Buoyancy has been added. Oil floats on top of Water; Water floats on top of Sand. But as I mentioned above, this only applies to plain Water, not Saltwater.

  • Wall has been changed to Ground.

  • A new tool has been added: Seed. This tool isn't draggable; you only get one Seed per click. The Seed will disappear if it hits any substance that is not Ground. If it does hit Ground, it is planted, and grows a fractal tree.

    1. The tree starts off with a trunk made of Wood, which is a slow-burning version of Oil (in that it is flammable and erodes surrounding Ground or whatever when it burns).
    2. After a fractal generation or two, it begins growing Leaves instead of Wood.
    3. The Leaves periodically generate Pollen (or maybe it's Sap). Pollen suspends (doesn't float or sink) in any substance, including Water.
  • Fire now generates Smoke, which of course rises. It disappears after a short time, but it can bottle up a small opening. Watch for this if you funnel lots of Oil through a tiny (1–2 px) hole onto a burning stick of Wax.

    Screenshot: A cone filled with Water, pouring onto a roughly diamond-shaped division inside of a small inverted cone. At the mouth of the lower cone is three sticks of Wax, each burning, generating enough smoke to seal off (briefly) the opening between the two cones.

  • Pouring Water now contains bubbles of air/nothing, which of course float to the top. And Saltwater, poured into Water, gets bubbles of Water.

    Screenshot: A cone filled with Water, pouring into empty space. Bubbles are floating up through the Water.
    Screenshot: A cone filled with Water and Saltwater, pouring directly into a second cone filled with plain Water. Water bubbles have appeared in the Saltwater, and air/vacuum bubbles in the top Water.

And a couple of problems:

  • This one existed in WoS, too: Liquids behave more like powders.

    1. They don't equalize. Create a U-shaped container from Ground, with an upright division in the middle (with a gap between that and the floor of the U). Fill one side, above the gap, with Water or Oil or Saltwater. The other side will fill up to the gap, but not above it.

      Screenshot: A box as described. The left side is full to the top; the right side is filled right up to the bottom of the division.

    2. If you rush a large amount of a liquid down an incline, it takes too long for the level at the bottom to equal the level at the top. A liquid would reach the same level at both ends much more quickly than a powder; the behavior in the game is that of a powder, even when the substance being poured is a liquid (Water, Oil, or Saltwater).

    I think that this can be attributed to the game's apparent use of pixels as the backing for all game substances; they act as particles of a powder. Of course, I'm just guessing, having not seen the inner workings of the game for myself. But that is my guess and I'm sticking to it.

  • If you fill a container with Water, then put a lid on it with Pollen or Ground, then inject Oil into the Water, it will float up, but it will not even out. It will just form a lump at the top of the field of Water.

  • Bubbles don't happen in any other liquids or powders, only plain Water. Also, bubbles would only happen when the top is not open (as in a bottle held upside down); a bowl, cone, or box should not have any bubbles. (Maybe I'm asking too much, but you know me: I'm a pedant.)

UPDATE 2006-05-09 04:02 PDT: I knew I forgot one. Turns out I forgot two. Added the list items for smoke and bubbles (amusingly enough, both names of Growl displays).

UPDATE 2006-05-09 05:04 PDT: Error correction to the bubbles list item: Air in water isn't the only kind of bubble in the game. Also added screenshots.

Shading in PostScript

I've recently been beating my head against PostScript's gradient ("shading") system. Plenty of documentation and examples are available for when you're working in the DeviceGray color space, but when you're in DeviceRGB, it gets hard. Part of this is due to the fact that the PostScript Language Reference Manual's description of shadings and the functions that power them is overly abstract and decorated with too much math for my language-oriented mind.

So, here I'll try and explain it more clearly, particularly by explaining functions in the context of shadings, rather than separately.

A shading in PostScript is represented by a dictionary. Valid keys in the shading dictionary are:

The type of gradient: axial, radial, etc.
The color space of colors returned by the function.
The start and end of the gradient on the page. Defined more specifically by the PLRM.
A function dictionary, or an array of them.

Functions aren't as you expect them to be. Rather than a callable object (a procedure), a function is a dictionary. (This, BTW, is the architectural reason for Quartz's CGFunction class, although CGFunction actually uses a C function callback — what would be a procedure in PostScript.) There are three types of function dictionaries; I'll only deal with type 0, a sampled function (a "sample" is a step in the gradient). A sampled function contains, or fetches from a file, the samples it will return, in a "data source".

Two numbers for every input, constraining that input to a range. If an input is below the first number, it will be replaced with the first number; if it is above the second number, it will be replaced by the second number. Generally, these two numbers are 0 and 1. In an axial shading function, there is only one input, so your domain should be two numbers (e.g. [0 1]).
The other end from Domain. Works the same way, but it constrains your outputs rather than your inputs. For a shading function, there is one pair of numbers for each component. So, in DeviceGray, Range should be two numbers; in DeviceRGB, it should be six.
Named slightly misleadingly (the PLRM clarifies), this is actually the number of bits per component. So if you're doing 24-bit RGB, this should be 8.
An array containing the number of samples as an int.
Either a file or a string from which to get the sample data.

You might expect that the samples should be given as an array. You would be wrong. Instead, PostScript wants pure binary data, either from a file or encoded as a string. So, for example, in RGB, every three characters (bytes) are one sample. I use a hexadecimal literal, or when I want to use an array, this procedure (which you may consider to be under the modified BSD license):

% array -> hexstr -> string % Converts an array of integers to a string. [ 65 66 67 13 10 ] -> (ABC\r\n). /hexstr { 4 dict begin /elements exch def /len elements length def /str len string def /i 0 def { i len ge { exit } if str i %The element of the array, as a hexadecimal string. If it exceeds 16#FF, this will fail with a rangecheck. elements i get cvi put /i i 1 add def } loop str end } def

And yes, I know that that procedure has nothing to do with hexadecimal. I was probably tired when I wrote it.

Note: If you use hexstr to create a shading dynamically from an array of samples, be aware that when you divide the length of the array by 1 (gray) or 3 (RGB) or 4 (CMYK) to get the proper value for Size, you must use cvi on the quotient, because div returns a real and makepattern demands an int.

Technorati tags: .


Beware the nib

Say you have an object, X, and a nib containing two other objects, Y and Z. X has two outlets, y and z, with typical accessors for each.

X, or another object on behalf of X, loads the nib with X as its owner. NSNib, naturally, sets the y and z properties of X to the two objects in the nib, using the accessors since they exist.

Now, when an object is instantiated, it has a retain count of 1; it is implicitly owned by the object that created it. If you release that object, the retain count goes down to 0 and the object dies.

Such is the case of the objects Y and Z when they are unarchived from the nib: After they come out of deep freeze, they have that starting retain count of 1. But then they are passed to the accessors of X, which, if written in the usual way, retain Y and Z. Now the retain counts are 2 each.

When X is finished with Y and Z, it releases them, of course (perhaps by calling its accessors with nil). But the implicit retains still exist. Therefore, so do Y and Z.

This isn't a nib bug, though; the bug is in X. Outlets aren't supposed to be retained. So, if you do implement accessors, they should be non-retaining. Or, if you can, omit the accessors; NSNib will do the Right Thing for you.

Example of the bug: NibLeak (source code with Xcode 2.2.1 project).

Technorati tags: .


Report-an-Apple-bug Friday! 39

This bug is Reason parameter to SystemSound API functions. It was filed on 2006-05-05 at 00:23 PDT.


SystemSound API should have functions that take a reason (expressed as a CFString) for the beep.

Steps to Reproduce:

  1. Open <OSServices/SystemSound.h>.

Expected Results:

One or more functions exist that take a CFString parameter called inReason.

Actual Results:

No such functions exist.




One of the most annoying things that can happen in the Mac environment is when a beep occurs, with no explanation. Sometimes this is the result of a processing delay, with the application beeping multiple seconds after the event that triggered the beep (by which time the user has moved on to some parallel task). Other times, the app is just broken, only beeping when it should also display a dialog or when it should use a Growl notification instead (some apps beep at the completion of a task, optionally or otherwise).

This can be solved by adding new functions to SystemSound (and, for convenience, AppKit — NSBeepWithReason, say) that take a reason for the beep. This reason would be logged to the Console (example format: "Beeped (Reason: ^0)"), and if the user so desires, displayed to the user in a bezel (or, better yet, a Growl notification). Existing functions, or the new functions with reason=NULL, would use a localized "No reason was supplied" message.

Example Console.log line:

2006-05-04 22:52:15.974 Safari[252] Beeped (Reason: Quit playing online games and get back to work!).
2006-05-04 22:52:16.974 AppThatDoesNotSupplyAReason[253] Beeped (no reason supplied).

Even if no reason is supplied, the log message is still useful, because it at least says which app beeped.

A Growl notification could have "APPNAME beeped" as the title and the reason as the description. Separate notifications should exist for reason and no reason, with the with-reason notification turned on by default, and the no-reason notification turned off by default.

Technorati tags: ,


More Beads

My entry in Iron Coder, Beads, had a bug in it. I fixed this bug and called it 1.1. You can get it at the shiny new Beads webpage.

I also finished an article that I'd been working on, called How to draw Beads. It documents the creation of the pretty bead graphics, step-by-step.

Technorati tags: , .



I got my California ID card today. :D