Rick Swift & Apple & Embedded I make things. Sometimes, I’ll talk about it here.

Filed Under #Computers

macOS TCC: Transparency, Consent, and Control

macOS TCC: Transparency, Consent, and Control featured image

zsh Prompt Template

zsh Prompt Template featured image

Debian 12 Parallels VM on M1 MacBook Pro

Debian 12 Parallels VM on M1 MacBook Pro featured image

A Better Scheme for the Fediverse?

Streaming the Linux Desktop to Remote OBS

I wanted to stream my LinuxCNC desktop to a Mac running OBS.

BoringSSL Root Certs on Mac OS X

Fixing Vapor 4 Fluent/SSL errors connecting to DigitalOcean DB instances.

LC_VERSION_MIN and App Store Validation of bare dylibs

Problems validating bare dylibs in an iOS App.

LC_VERSION_MIN and App Store Validation of bare dylibs featured image

Using dbus on OS X Yosemite

In the ongoing effort to enhance Podtique for mere mortals, I'm building a web server within the device to aid in configuration. I've chosen node.js (really, locomotive) for this. But the main code is written in C++, and I needed a way for the node.js code to communicate with the C++ process.

Antique Radio Podcast Player

One of my favorite things in the world is The Thrilling Adventure Hour, a stage production in the style of old-time radio, performed live on stage, and recorded as a podcast. This got me thinking about what it was like before television, how people gathered around their radios to listen to radio plays. What if you could listen to The Thrilling Adventure Hour on an old radio?

Validating a Self-Signed SSL Certificate in iOS and OS X Against a Changing Host Name

We developed a device with which we communicate securely over SSL using a self-signed certificate. The device gets a dynamically-assigned IP address, and that is communicated to the iOS app via other means. By default, NSURLConnection tries to validate the SSL certificate against the hostname, but it was impossible for us to create a wildcard cert that would match.

Trouble with Static C++ Constructors in ChibiOS/ARM

For the last few days I've been troubleshooting a problem with a C++ thread class I created to aid in the static allocation of threads under ChibiOS.

The problem boiled down to the fact that the ChibiOS ARM port (specifically, the ARM7 port, but it's probably true for most ports) isn't properly executing the constructors for statically (globally) allocated class objects. To clean up the other post, I moved the troubleshooting material to this post.

Note: I've discussed this with the author of ChibiOS, and he hopes to resolve the issue in ChibiOS version 2.3.2.

When any object with a vtable pointer is allocated on the stack (i.e. at run time), it works. But when it is allocated as a global variable, the vtable pointer is NULL. Here's the test code and output:

class FooParent

virtual void doSomething();

uint32_t mField1;
uint32_t mField2;



Foo : public FooParent
virtual void doSomething();

uint32_t mField3;



Foo f;

uint32_t* p = reinterpret_cast<uint32_t*> (&f);
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("f dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;

Foo g;
p = reinterpret_cast<uint32_t*> (&g);
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;
sDebug.log("g dump @ 0x%08x: 0x%08x\n", p, *p); p+=1;

f dump @ 0x00203090: 0x00000000
f dump @ 0x00203094: 0x00000000
f dump @ 0x00203098: 0x00000000
f dump @ 0x0020309c: 0x00000000

g dump @ 0x00202a60: 0x0010a0a8
g dump @ 0x00202a64: 0xbeefba55
g dump @ 0x00202a68: 0xdeadface
g dump @ 0x00202a6c: 0xfeedabcd

As you can see, the constructor isn't getting called, (and vtable initialization isn't happening) for the statically-allocated object f, but does get called for object g, allocated on the stack.

This is a GCC issue. It needs to call static ctors (and dtors, theoretically), but it's failing to do so. It could be a mis-configured build of the toolchain, or a bug in the run-time library, or something else along those lines.

Thoughts While Troubleshooting

It currently fails on ARM (on an AT91SAM7X). The symptom is typical of exceeding the allocated stack space: the processor appears to reset (that is, it re-starts execution from the start of code).

There are two failure modes: in the first, it fails in ThreadEntry(), where the the thread context is cast to a pointer to the BaseThread class, and the virtual entry() method is called, executing the CThread subclass' implementation. If I remove the call to entry() and just implement some code directly in ThreadEntry(), it works fine.

The second failure mode has to do with what I put in the modified ThreadEntry(). Although it executes, subsequent execution later in the program fails (by failure, it is meant that the processor appears to reset).

At this point, I'm not sure what is wrong. Code seems well-enough aligned, when the GCC .map file is examined. The self/this pointer in ThreadEntry() has the correct value. I've tried with very large stacks to ensure I'm not overrunning the stack. I've tried a non-template class hierarchy to be sure virtual method dispatch works correctly (it does).

I'm going to try twiddling some outputs on the MCU (instead of calling the stdlib routines I have been). Without JTAG debugging, it's going to be difficult to figure this out.

Balloon Controller

I'm probably just procrastinating a bit before getting into writing firmware for this thing, but I though I'd post a picture of the Balloon Controller with nearly everything populated. I'm still waiting for the barometric pressure sensor and GPS connector to arrive, but everything else is installed.

Balloon Controller

I've verified that everything powers up, but beyond that, I have no idea if anything works. I was able to flash the MC with a blinky LED program, though, so that's a good start.

UPDATE (15:38): Got the DBGU serial port work. Note that this board has two USB ports. One for the MC proper, and one for an FTDI chip attached to the SAM7X's DBGU port. This was easier than writing a Mac OS X virtual serial port driver against the MC's USB port.

DBGU Port Working

UPDATE (18:27): Got the battery voltage being measured, and also got the radio link working!

It's a little cumbersome to flash the MC when you have an external power source, because it needs to power cycle to re-enumerate the USB and set up for download. So I pulled the fuse that USB bus power goes through, which means that I only have to disconnect the main power supply to power cycle it, rather than disconnect that and unplug the USB cable.

18 km Range Test a Success

Darren and I tried an 18 km range test today with the n920. Amazingly, we had success with just the rubber ducky antennas, and down to 250 mW transmit power on both ends! He was up near this winery, and I was on the fifth floor of Yahoo! building D.

At first we tried the new Yagi, but it didn't seem to work (at all). We were astonished to get a link with just the whip antennas. They didn't even have a proper ground plane, just being stuck out the side of the plastic boxes I had put the gear in (and pointing upward).

Using the ATS123? command to query the receive signal strength, Darren had -88 dBm, I had -105 dBm (measurements varied, but I think that was at 250 mW). I tried sending a file to myself via loopback, < 1 KB in length, which failed the first time and succeeded the second. A 131 KB file failed, and I didn't try it a second time. I could see it dropped stuff from within the file. We'll have to investigate exactly what went on. Are the radios full duplex? How big are their buffers? It seemed to send the entire file before receiving anything, but that could've been an artifact of PortTermX.

Interestingly, the Yagi didn't seem to offer much. It was also nearly impossible to hold while operating the computer. Next time, we need to put it on a stand of some kind.

Hopefully this weekend we'll try a much longer range test, from the winery to Coyote Hills.

New 900 MHz Yagi Arrived

Our balloon experiment is using a 920 MHz frequency-hopping radio link (we also have 2.4 GHz radios, but will probably stick to 920 MHz). The balloon will carry a dipole or vertical bazooka tuned for 920 MHz, but it will be rotating and squirrelly. It will also be 30 - 50 km away. So I decided a good Yagi on the ground will help ensure we maintain our fade margin.

I looked at a couple options from L-Com. The best 900 MHz Yagi they had offered 14 dBi in 109 cm, but was $120. The next best offered 13 dBi for $44, so I bought it. I didn't realize until it arrived that it was 145 cm long!

900 MHz 13 dBi Yagi

So, this will prove to be unwieldy, at best, especially from a moving car. We might decide to have a fixed ground tracking station, but that approach will need investigation.

Radio Link Test 2

I put the n920 slave in a box and left it with a co-worker on the fifth floor of my office building. I took my laptop and the master radio over to our other building, 5 km away, and set up on the sixth floor. My co-worker was on the balcony outside the building, and I was in a conference room inside.

After we powered up the radios, and after I dealt with my radio coming loose from its dev board, we established a link and I was able to send a few characters to the slave. It was set up with a loopback connector, so those bytes came right back.

A query of the master's receive signal strength returned -91 dBm.

Hopefully this weekend we can do a 20 km test.

Snow Leopard Code Blocks

I've recently been developing a Mac OS X project in which I was able to utilize the new code blocks feature to write some asynchronous code. They are a very exciting development, and I hope the C standards body adopts them as an official part of the language. They are similar to D's delegates. A good introduction to blocks can be found in Apple's Blocks Programming Topics.

I won't explain what a block is here, other than to say it's like a function. For a very brief introduction to the syntax of blocks, see “Declaring and Using a Block.”

What I will do is show you how code blocks can simplify inter-thread communication. First I'll present a pre-code block approach to the problem, and then show how, by using code blocks, you can dramatically simplify the code.


The project includes a little USB hardware device, with Mac OS X software to talk to it. I needed to implement a console-like UI, allowing the user to send bytes to the device, and see the bytes coming in from it (in this regard, the device behaves like a serial port). The idea is to simply append whatever bytes are sent by the device to an NSTextView. To do this, it would be nice if the driver (a user-land driver embedded in the app) would just call my window controller whenever there is data available from the device.

However, there is currently only a blocking read call implemented in the driver.[1] So, I need a separate thread to block on a read call, and when data becomes available, to send my window controller a message to handle it. Problem is, the window controller needs to then interact with NSTextView, which should only be done on the main thread. The traditional solution in a situation like this is to use -[performSelectorOnMainThread:].

Traditional Approach

The window controller mentioned above is really just the app delegate (it's currently a very simple app). The app delegate's declaration looks something like this. For simplicity's sake, I've left out a lot, but for our purposes, assume that the user presses a button which calls -[openTerminal:], which starts the balls rolling.

[cpp 1="CallbackReadOp;" 2="@class" 3="Device;" 4="@interface" 5="AppDelegate" 6=":" 7="NSObject" 8="<NSApplicationDelegate>" 9="{" 10="NSWindow*" 11="mWindow;" 12="NSTextView*" 13="mConsole;" 14="Device*" 15="mDevice;" 16="CallbackReadOp*" 17="mReadOp;" 18="}" 19="@property" 20="(retain)" 21="IBOutlet" 22="NSWindow*" 23="window;" 24="@property" 25="(retain)" 26="IBOutlet" 27="NSTextView*" 28="console;" 29="@property" 30="(retain)" 31="Device*" 32="device;" 33="-" 34="(IBAction)" 35="openTerminal:" 36="(id)" 37="inSender;" 38="@end" language="@class"][/cpp]
Pretty straightforward, right? We've got some references to the UI, a reference to our device, and the action to start the read-append operation.

The implementation looks like this:

[cpp 1=""AppDelegate.h"" 2="#import" 3=""CallbackReadOp.h"" 4="@interface" 5="AppDelegate()" 6="-" 7="(void)" 8="readData:" 9="(NSData*)" 10="inData;" 11="-" 12="(void)" 13="appendToConsole:" 14="(NSString*)" 15="inString;" 16="@end" 17="@implementation" 18="AppDelegate" 19="-" 20="(IBAction)" 21="openTerminal:" 22="(id)" 23="inSender" 24="{" 25="[self.device" 26="26="open"];" 27="//" 28="Create" 29="an" 30="operation" 31="to" 32="loop" 33="reading" 34="from" 35="the" 36="board," 37="//" 38="calling" 39="us" 40="back" 41="when" 42="there's" 43="data" 44="available…" mreadop="[[CallbackReadOp" 45="alloc]" 46="init];" 47="mReadOp.device" 48="=" 49="self.device;" 50="mReadOp.target" 51="=" 52="self;" 53="mReadOp.selector" 54="=" 55="@selector(readData:);" 56="[mOpQueue" 57="addOperation:" 58="mReadOp];" 59="}" 60="-" 61="(void)" 62="readData:" 63="(NSData*)" 64="inData" 65="{" 66="NSString*" s="[[NSString" 67="alloc]" 68="initWithData:" 69="data" 70="encoding:" 71="NSUTF8StringEncoding];" 72="if" 73="(s" 74="!=" 75="nil)" 76="{" 77="[self" 78="appendToConsole:" 79="s];" 80="}" 81="}" 82="#pragma" 83="mark" 84="-" 85="#pragma" 86="mark" 87="•" 88="Attributes" 89="@synthesize" window="mWindow;" 90="@synthesize" console="mConsole;" 91="@synthesize" device="mDevice;" 92="@end" language="#import"][/cpp]
But wait, there's more! We need to implement CallbackReadOp. Here's its declaration:

[cpp 1="Device;" 2="@class" 3="CallbackReadOp" 4=":" 5="NSOperation" 6="{" 7="Device*" 8="mDevice;" 9="NSObject*" 10="mTarget;" 11="SEL" 12="mSelector;" 13="}" 14="@property" 15="(retain)" 16="Device*" 17="device;" 18="@property" 19="(retain)" 20="NSObject*" 21="target;" 22="@property" 23="(assign)" 24="SEL" 25="selector;" 26="@property" 27="(assign)" 28="bool" 29="reading;" 30="@end" language="@class"][/cpp]
The implementation looks like this:

[cpp 1=""CallbackReadOp.h"" 2="@implementation" 3="CallbackReadOp" 4="-" 5="(void)" 6="main" 7="{" 8="while" 9="(self.reading)" 10="{" 11="uint8_t" 12="12="buf[512"];" 13="uint32_t" numbytes="[self.device" 14="read:" 15="buf" 16="length:" 17="512" 18="timeout:" 19="250];" 20="if" 21="(numBytes" 22=">" 23="0)" 24="{" 25="NSData*" data="[NSData" 26="dataWithBytes:" 27="buf" 28="length:" 29="numBytes];" 30="[self.target" 31="performSelectorOnMainThread:" 32="self.selector" 33="withObject:" 34="data" 35="waitUntilDone:" 36="true];" 37="}" 38="}" 39="}" 40="#pragma" 41="mark" 42="-" 43="#pragma" 44="mark" 45="•" 46="Attributes" 47="@synthesize" device="mDevice;" 48="@synthesize" target="mTarget;" 49="@synthesize" selector="mSelector;" 50="@synthesize" reading="mReading;" 51="@end" language="#import"][/cpp]
This should be fairly self-explanatory. When this custom NSOperation subclass is added to the NSOperationQueue in the app delegate's -[openTerminal:] method, its -[main] is invoked. It sits in a loop, waiting for data to be available, and sends the app delegate -[performSelectorOnMainThread:withObject:waitUntilDone:], passing the NSData object it creates for the app delegate to handle.[2] If the user closes the console, the app delegate can set the reading property to false, and the loop will exit.

-[appendConsole:] takes care of presenting the data to the user in the app's window. The details of that aren't relevant here, so I've left it out.

So, all of that wasn't too bad. But it requires two methods in the app delegate, and a custom subclass of NSOperation. Now let's see how it works when using code blocks.

With Code Blocks

With code blocks, we can get rid of the custom NSOperation subclass altogether, and get rid of one of the two methods in the app delegate. All we need is a new implementation of -[openTerminal:]:

[cpp 1="(IBAction)" 2="openTerminal:" 3="(id)" 4="inSender" 5="{" 6="[self.device" 7="7="open"];" 8="//" 9="Create" 10="an" 11="operation" 12="to" 13="loop" 14="reading" 15="from" 16="the" 17="board," 18="//" 19="appending" 20="to" 21="the" 22="console…" 23="NSBlockOperation*" op="[NSBlockOperation" 24="blockOperationWithBlock:" 25="^{" 26="NSAssert([NSOperationQueue" 27="currentQueue]" 28="!=" 29="[NSOperationQueue" 30="mainQueue]," 31=""We" 32="should" 33="be" 34="running" 35="on" 36="a" 37="different" 38="queue!");" 39="while" 40="(self.reading)" 41="{" 42="uint8_t" 43="buf[512];" 44="uint32_t" numbytes="[self.device" 45="read:" 46="buf" 47="length:" 48="512" 49="timeout:" 50="250];" 51="if" 52="(numBytes" 53=">" 54="0)" 55="{" 56="NSData*" data="[NSData" 57="dataWithBytes:" 58="buf" 59="length:" 60="numBytes];" 61="//" 62="We've" 63="got" 64="some" 65="data," 66="now" 67="append" 68="it" 69="to" 70="the" 71="output" 72="view…" 73="NSOperation*" callbackop="[NSBlockOperation" 74="blockOperationWithBlock:" 75="^{" 76="NSString*" s="[[NSString" 77="alloc]" 78="initWithData:" 79="data" 80="encoding:" 81="NSUTF8StringEncoding];" 82="if" 83="(s" 84="!=" 85="nil)" 86="{" 87="[self" 88="appendToConsole:" 89="s];" 90="}" 91="else" 92="{" 93="NSLog(@"Got" 94="%lu" 95="bytes," 96="but" 97="no" 98="valid" 99="UTF-8" 100="string"," 101="data.length);" 102="}" 103="}];" 104="[[NSOperationQueue" 105="mainQueue]" 106="addOperation:" 107="callbackOp];" 108="[callbackOp" 109="waitUntilFinished];" 110="}" 111="}" 112="}];" 113="[mOpQueue" 114="addOperation:" 115="op];" 116="}" language="-"][/cpp]
What's happening here? There are two (nested) anonymous code blocks, each delimited by ^{ and }. This notation is a shorthand for a block that takes no parameters and returns void.

The Outer Block

First, line 9 creates an NSBlockOperation, and provides a block definition inline (the definition ends on line 43). This block is essentially the same as the code in CallbackReadOp: It loops over a device read call, creating NSData objects every time it gets some data. (It also asserts, on line 11, that it is in fact executing on a thread that's not the main thread.)

Keep in mind that the code in this code block will not execute right now (that is, right after the call to +[NSBlockOperation blockOperationWithBlock:]). It is simply being defined, and a reference to it is passed as the sole parameter to +[NSBlockOperation blockOperationWithBlock:]. More on that later.

On line 17, the code block references self.device. This is where the beauty and power of blocks becomes apparent: code blocks have access to all the variables in scope at the place they are defined. In this case, the blocks are defined in the scope of the AppDelegate method -[openTerminal:]. So they can access anything “regular” code in -[openTerminal:] can access, even though it will actually execute on another thread, after -[openTerminal:] has exited!

Note: It's important to understand that this access isn't completely without restriction; you still have to take care to synchronize access to shared variables just like you would with conventional multithreaded code, and remember that the block will hold strong references to garbage-collected objects (see the “Garbage Collection” section below). But what you don't have to do is squirrel away references to things like we did above with the CallbackReadOp class.

For more details on the subtleties of variable access from within code blocks, see “Blocks and Variables”.

Now take a look at line 45. Here we take the NSBlockOperation object op that we just created, and add it to mOpQueue, an instance of NSOperationQueue that we created earlier in the application's execution. At this point, our code block is scheduled to execute on a different thread, and -[openTerminal:] exits.

Eventually, that new thread gets scheduled, and the outer block we just created executes.

The Inner Block

So we have an outer code block executing on a thread other than the main thread, looping over a read call and passing data back to the main thread. Let's take a look at how it actually accomplishes that second part.

In the traditional approach, CallbackReadOp calls -[performSelectorOnMainThread:withObject:waitUntilDone:], calling the app delegate's -[readData:] and passing it the NSData object it created as a result of the device read. -[readData:] converts that to a string and calls -[appendToConsole:] to display it.

While we could certainly do that in the outer code block above, we can get rid of the -[readData:] method altogether and just call -[appendToConsole:] directly. Remember, a code block has access to everything that was in scope at the place it was defined, even when executing later. The only thing here, though, is that we need to call -[appendToConsole:] on the main thread. So we just do what we did with the outer block, but this time schedule it to run on the main thread, via +[NSOperationQueue mainQueue].

Everything from line 26 to line 36 will execute on the main thread. The separate thread conducting the device read will block until the inner code block has completed execution, thanks to the call to -[waitUntilFinished].[3]

Improving the Code

There is at least one small improvement we can make to this code, and that is to move the creation of the NSAttributedString to the outer block. Doing so will push more work into the other thread, reducing the burden on the main thread an improving UI responsiveness (on multi-core machines, at least). In this case it's not likely to make a noticable difference, but it's important to think in these terms.

Without code blocks, making such a trivial change would be more burdensome, because you'd have to change code in two different classes, and change a method signature. With the code blocks we've structured here, it's mostly just rearranging a few lines:

[cpp 1="(IBAction)" 2="openTerminal:" 3="(id)" 4="inSender" 5="{" 6="[self.device" 7="7="open"];" 8="//" 9="Create" 10="an" 11="operation" 12="to" 13="loop" 14="reading" 15="from" 16="the" 17="board," 18="//" 19="appending" 20="to" 21="the" 22="console…" 23="NSBlockOperation*" op="[NSBlockOperation" 24="blockOperationWithBlock:" 25="^{" 26="NSAssert([NSOperationQueue" 27="currentQueue]" 28="!=" 29="[NSOperationQueue" 30="mainQueue]," 31=""We" 32="should" 33="be" 34="running" 35="on" 36="a" 37="different" 38="queue!");" 39="while" 40="(self.reading)" 41="{" 42="uint8_t" 43="buf[512];" 44="uint32_t" numbytes="[self.device" 45="read:" 46="buf" 47="length:" 48="512" 49="timeout:" 50="250];" 51="if" 52="(numBytes" 53=">" 54="0)" 55="{" 56="NSData*" data="[NSData" 57="dataWithBytes:" 58="buf" 59="length:" 60="numBytes];" 61="//" 62="Convert" 63="the" 64="data" 65="to" 66="a" 67="string…" 68="NSString*" s="[[NSString" 69="alloc]" 70="initWithData:" 71="data" 72="encoding:" 73="NSUTF8StringEncoding];" 74="if" 75="(s" 76="==" 77="nil)" 78="{" 79="NSLog(@"Got" 80="%lu" 81="bytes," 82="but" 83="no" 84="valid" 85="UTF-8" 86="string"," 87="data.length);" 88="continue;" 89="}" 90="//" 91="We've" 92="got" 93="some" 94="data," 95="now" 96="append" 97="it" 98="to" 99="the" 100="output" 101="view…" 102="NSOperation*" callbackop="[NSBlockOperation" 103="blockOperationWithBlock:" 104="^{" 105="[self" 106="appendToConsole:" 107="s];" 108="}];" 109="[[NSOperationQueue" 110="mainQueue]" 111="addOperation:" 112="callbackOp];" 113="[callbackOp" 114="waitUntilFinished];" 115="}" 116="}" 117="}];" 118="[mOpQueue" 119="addOperation:" 120="op];" 121="}" language="-"][/cpp]

Garbage Collection

As you may have surmised by looking at the code, this app is garbage collected. That is, the code doesn't use retain and release to manage objects. This can obscure the fact that code blocks strongly reference the objects “captured” by them.[4]

Here, the blocks explicitly reference self and self.device, which will cause both of those objects to persist for as long as the blocks persist. If you were to directly reference an ivar, that would implicitly reference self, so again, both would continue to live for the life of the block. In this case, the app delegate and the device are both objects that always exist longer than the span of a user's console session, so this is acceptable.

The outer block defined above can live for a very long time (for as long as the user has the console window open). Blocking operations within a block can also cause a block to live for an extended period of time. If you're not careful, this can cause the worker thread count to increase dramatically, a condition you almost always want to avoid.

Final Thoughts

Code blocks (and the NSOperation classes to support using them) provide a clean and concise way of writing asynchronous and multi-threaded code. For this app, we got rid of an entire class definition (the CallbackReadOp), and a method in the app delegate. We did have to add an atomically-access reading property to the app delegate (not shown). Much easier to write, and to understand (once you understand code blocks).

Most often you will write small, anonymous blocks of code like those above and pass them to other functions for execution. Being able to access the variables in scope at the point of definition makes it very easy to write complex code, just don't forget to synchronize access to shared variables.

For additional information, and if you have Apple Developer access, check out A Short Practical Guide to Blocks.


Special thanks to Joar Wingfors of Apple, Inc. for technical review and other suggestions.


[1]Yes, it's possible to implement an asynchronous read, but we'll ignore that for now to better illustrate the advantages of code blocks.

[2]Don't worry too much about this tight loop hurting performance. The nature of the hardware device is such that it blocks for a while when there's no data, so this loop isn't as tight as it appears.

[3]While not strictly necessary, it reduces CPU load a little, allowing more bytes to accumulate in the USB buffers before they're read again. If this were a higher-speed device, it might be necessary to read it as fast as possible, but that's not the case here.

[4]Thanks to Joar for the term “capture” to denote external variables referenced by a code block. I think it will prove useful in future discussions of code blocks.

MissionClock Sales

MissionClock has been in the iTunes App Store for a few weeks now, and I thought I'd post some sales information. The chart below shows the relative number of unit sales per day from July 30, 2009 to September 10, 2009. The two big spikes in sales corresponded to the STS-128 launch attempt on August 24, and the actual launch on August 28. Labor Day was particularly bad. There is no data for the dates from August 5 to August 8.


Clearly, launch days are good for MissionClock.

Watching NASA on Snow Leopard

UPDATED: 2009-10-19
I'm not sure for how long this little tip will work. I figure when Akamai & Apple catch on to the fact that people are watching a stream they intended for the iPhone, they'll put a stop to it.
But in the meantime, you can watch a very high quality stream of NASA TV in Snow Leopard's QuickTime X Player. Just launch QuickTime Player, go to the File menu and choose “Open URL…”. Then enter the following URI:


Old URI: http://qthttp.akamai.com.edgesuite.net/iphone_source/yahoo/nasa/nasa_all.m3u8

You can also follow along with STS-128 with MissionClock for iPhone and iPod Touch.
I've been watching for the past hour or so, and it's not without its problems. It's about 45 seconds behind Spacevidcast, which seems to be the lowest-latency stream available. Every now and again it will stop momentarily. Sometimes the window shrinks and turns black for a while, then comes back. But overall, it's a high-quality image that should work on a variety of connections, and doesn't suck down CPU like watching in a Flash player. However, it does cause the fans in my Aluminum MacBook Pro 2.5 GHz Core2Duo to run a little bit, and I suspect Apple could do some work to improve this.

Making Dots

I am by no means a Photoshop expert, so there doubtless better ways to do this. With that disclaimer out of the way, hopefully this will help someone.
Yesterday I needed a nice-looking dot, like the one next to unread email messages in the iPhone Mail client. At first I tried lifting the dot from the phone directly, taking a screenshot. But that gave me a 13 x 13 pixel dot that was antialiased to white, and I needed it antialiased to transparent, so that it would work against any background. This is the dot I wanted (the final result is at the bottom):

Screenshot 2009.07.16 16.53.26.png

So I tried my hand at creating it from scratch in Photoshop, and it turned out to be surprisingly easy (even easier when I reproduced the steps in order to create the screenshots here). The Photoshop tools are very well designed for exactly this sort of graphic.
For this, I used Photoshop CS3 for Mac OS X. This article assumes you have a basic familiarity with Photoshop, but I try to be specific in how to carry out the operations. I glossed over the configuration of the Marquee tool a bit, but hopefully you'll get it.
Start by creating a new document of the overall size you want. I wanted a 13 x 13-pixel dot, so I created a 13 x 13 document. It's important that it be RGB, and have a transparent background:


Zoom way in on the document, by typing Command-+ a few times. I worked at 3200% zoom. Then choose the colors you'll want to use. I used just two shades of blue, lifted right from the screenshot of the Mail dot. You'll need three, one for the border color, and two for the gradient start and end.
For this step, make sure the darker color is the front color:


With the Ellipse Tool, create a circle by clicking in the very upper-left corner of your document, and dragging to the lower-right:


It should fill in a nice antialiased circle of the chosen color:


Then choose the Elliptical Marquee Tool:


And create a circular selection that's smaller than the circle you filled before. I did this by holding down the Option key as I clicked in the center of the image, and dragging toward the lower-right. Holding the shift key while you do this will constrain the proportions to be square:


When you let go, it'll change shape to show the actual pixels that are selected:


At this point, you want to fill in the circle with the gradient, to give it a highlight. On Mac OS X and iPhone OS, lights are always directly above the graphic.
To fill the gradient, Photoshop needs a layer into which it can draw. Click the New Layer button in the Layers utility window:


Set up the colors for the gradient fill. Since I chose the colors I was going to use already, I just had to make sure the light color was on top:


Then select the Gradient tool:


And make sure the tool is set up to do radial gradients. At the top of the screen, there's a tool bar that lets you configure the gradient tool. Set it up so it looks like this:

Picture 1.png

At this point, you should have a selection of pixels and a new layer selected that match the steps above, and the colors you want your gradient to be. Then use the gradient tool by clicking near the top-center of your dot, and dragging downward, not quite all the way:


When you let go, you'll have a nice gradient filling just the selected pixels, and properly antialiased, to boot, although that's not as noticeable here since we painted over the same blue color:


Now you can use "Save for Web & Devices…" from the File menu to save this as a 24-bit PNG file with transparency, and it'll be ready for use in iPhone apps. Here's the result (it might be ever-so-slightly different, as this is the dot I got from my first run through these steps, and the screenshots above are from the second run through them I made to write this):


Stream overload during LRO/LCROSS launch

I'm sitting here suddenly overwhelmed at the utter coolness of what I'm doing. I'm sitting at my desk in my home office, "working from home," as NASA's LRO/LCROSS mission prepares for launch in a few hours. In front of me is a 22" Apple Cinema Display attached to a 15" Aluminum MacBook Pro (Core 2 Duo, 2.5 GHz).
Thanks to NASA and Spacevidcast, playing on my desktop I have no less than six video streams, some with multiple angles, showing me the rocket and various other video. Thanks to ScanAmerica, I'm listening to the Kennedy Space Center ground loops via iTunes internet radio streaming. A NASA Java applet shows the Atlas countdown information. I'm chatting with friends via AIM, Yahoo! Messenger, and GTalk, as well as Spacevidcast's chat room. I'm following NASA agencies and employees via Twitter. And I have my as-yet-unfinished iPhone app MissionClock counting down to LRO. It looks like this:

Stream overload 1

This is all cool by itself, but every now and again I get a tweet like this one from Andy, who works cryogenics (fuel) and other things on the launch pad:

Been on the tower for the last 5 hrs. Finally got down and now they are kicking us out for the Atlas launch.

They just started the go/no-go poll. Time to do some real work while I listen/watch. Weather is a bit of a concern, here's hoping it holds!
One last bit of commentary: this ULA/Atlas launch has a lot more transparency/awesome geek factor than NASA Shuttle launches. I get to see a lot more info, and hear a lot more. I hope the Shuttle public outreach can surpass that of the Atlas someday soon. There aren't many opportunities left!

Safari 4 Public Beta

Hmm. I just installed it, and after 5 minutes, I'm disappointed and unconvinced. The tabs now live in the window's title bar. Inactive tabs' close boxes only appear when you hover over the tab, a practice I generally despise (don't make me hunt for shit in the UI). The close boxes also look different from how they did in 3.x. The tab/title bar text doesn't look like title bar text (the font is different), giving Safari the fragile, unpolished feel of non-Mac-native apps (like Java apps or Qt-ported apps).
Most disappointing, Safari continues to SPOD when loading pages and there's any kind of I/O burden on the system (possibly even just the I/O burden caused by Safari itself). This is on a last-gen 15" MBP Core 2 Duo, 2.5 GHz, 4 GB RAM.
Going from a "top site" thumbnail to the actual page is slow, I'm sure due to typical Safari page rendering slowness.
I'm running Klicko, so it's hard to know how inactive window clicks actually behave, but there might be some oddness there. Overall, I'm not at all sure what the improvements are in this new Safari. Good thing it's a free update, but I think, so far, they should be paying me to update.

Comcast Block Port 25, AGAIN

I moved into a new house, got a new Comcast account for my internet & cable, and not four weeks later, they had blocked port 25, for exactly the same reasons they did it before.
I called the number again, and Eric was very competent and agreed to put in the unblock request. He also helped me to understand why Comcast suggests using a port other than 25. It’s not as ineffective as I had thought, but I still don’t think it’s worth the invconvenience.
His reasoning goes like this: By blocking port 25, they prevent most spamming viruses from getting to open relays that typically run on port 25. Even if the virus is updated to use port 587 (Comcast’s suggested port), Comcast’s mail server requires authentication, and so it won’t be able to send (of course, if they hijack your local Mail client, none of that will matter).
Now, if open relays start appearing that listen on other ports, then it won’t matter.
The real problem is this: Comcast claims that they had reports that spam was being sent from my IP address (at the time it was assigned to me), but they won’t tell me anything about these reports. Now, I’m certain no spam has gone out from my house. My wireless network is locked up tight, the access logs don’t show any unauthorized accesses, and I’ve never run Windoze, so there’s no way I got one of those viruses. So, the report must be in error. But I have no way to track that down.
Hopefully, thought, I’ll get unblocked. And maybe the FCC’s point of view will eventually prevent them from blocking port 25 after all.

Customer Service Experience

Before remembering that I had written an entry about this problem (which had the info I needed), I tried using the regular Comcast online chat customer support. The first time I called, they insisted this was a permanent block and there was nothing I could do to remove it. That, of course, wasn’t true. This time they tried to pull the same shit, and after explaining to them that I was able to unblock it before, she said no, now it’s really permanent. As it turns out, it’s not.
I also have been trying to get a PIN number, so that I can get online access to my account. The agent could only give it to me if she called my Comcast Digital Voice number (a service I have but don’t use because it makes my bill cheaper). She couldn’t even call the number listed on my account (which I do use).
Here are a couple of photos showing our conversation (their stupid chat client doesn’t allow copy-and-paste):


Electric Motorcycle Project

I’ve decided to convert my old motorcycle to electric. This involves ripping out all the gas-related parts, and putting in an electric motor, batteries, and associated control electronics to make it all work. I’ve started a new blog for the project, go check it out:

The bike in San Marcos, CA

Electric Motorcycle Conversion Project

Image Upload Utility Idea

A quick entry to record an idea I had for a useful utility. A droplet application that takes the images dropped, makes a set of thumbnails, and uploads them and the originals to a server, and then puts markup on the clipboard.
It could be enhanced to pop up menus for frequent destinations, and image sizes. It could even pop up a crop editor, which could provide constraints for common aspect ratios/sizes/widths/heights. These could be set by destination.

Using dd to write floppy disks on Mac OS X

At work I had the need to write a bootloader directly to a floppy disk. In-house we use dd on Linux to do this, but it was giving me trouble on Mac OS X. I finally figured it out. Here are the instructions I wrote up:
These steps work on Mac OS X 10.5.2. They probably work on earlier versions, too, but I haven't tried it. This works with a TEAC FD-05PUW USB floppy drive that I picked up at Fry's (sometime in 2008-02).
When you plug in the USB floppy and insert a disk, the Finder will mount it on the desktop (if it's formatted) and create a couple of entries in /dev like /dev/disk1 and /dev/rdisk1 (the actual numbers corresponding to the drive will depend on how many other drives are attached. Be sure you're working with the right one!)
You would then be tempted to execute something like the following. Unfortunately, you'll get an error:

$ sudo dd if=redboot-pc/install/bin/redboot.bin of=/dev/disk1
dd: /dev/disk1: Resource busy

If you try using the raw device instead, you get a different error:

$ sudo dd if=redboot.bin of=/dev/rdisk1
dd: /dev/rdisk1: Invalid argument
382+1 records in
382+0 records out
195584 bytes transferred in 41.107951 secs (4758 bytes/sec)

In this case, the file is actually 195936 bytes in length. I'm not sure why it seems to write some of the bytes (I'm not sure it actually even wrote that many).
Using the buffered device (/dev/disk1 is correct, but it's busy because it's mounted by the Finder. If you simply unmount it via the Finder, then all the entries in /dev for the device go away, and you're unable to tell dd what to do. The solution is to unmount the disk using diskutil unmount, which leaves the /dev/disk1 entry in place, and then you can use dd correctly:

$ diskutil unmount /dev/disk1
$ sudo dd if=redboot-pc/install/bin/redboot.bin of=/dev/disk1
382+1 records in
382+1 records out
195936 bytes transferred in 13.345421 secs (14682 bytes/sec)

After that, I think it's safe to just unplug the USB drive, but I'd feel better if I knew how to completely unmount the device before doing so. In any case, the OS didn't complain like it would if a volume were mounted and online.

DNS Standards to Support Wide-Area Bonjour

Over the past few weeks I've been trying to move my DNS services to third-party DNS providers, like DreamHost, FreeDNS, and DynDNS. So far, I haven't found a provider that accepts arbitrary data for the various resource records' values (including spaces), severely limiting how nice wide-area Bonjour can be. I've been able to advertise services, they just look bad.
For more information, consult these pages on Bonjour and Wide-Area Bonjour.
Here I've tried to collect relevant parts of DNS-related RFCs to provide evidence that DNS service providers should support arbitrary characters in their DNS records.
Summary: there’s no reason a DNS provider should restrict the content of any resource record name or data field, except for its length. Those providers who use HTML forms for configuration can also make it easy to use UTF-8 text by just accepting what’s entered into each form field, and handle conversion to BIND configurations themselves (if that’s their implementation).

RFC1035 Domain Names—Implementation and Specification

From 3.3. “Standard RRs,” page 12:

<domain-name> is a domain name represented asa series of labels, and terminated by a label with zero length. <character-string> is a single length octet followed by that number of characters. <character-string> is treated as binary information, and can be up to 256 characters in length (including the length octet).

3.3.12. “PTR RDATA format,” page 17:



PTRDNAME A <domain-name> which points to some location in the domain name space.

PTR records cause no additional sectionprocessing. These RRs are used in special domains to point to some other location in the domain space. These records are simple data, and don't imply any special processing similar to that performed by CNAME, which identifies aliases. See the description of the IN-ADDR.ARPA domain for an example.

From 5.1. “Format,” page 33:

<domain-name>s make up a large share of the data in the master file. The labels in the domain name are expressed as character strings and separated by dots. Quoting conventions allow arbitrary characters to be stored in domain names. Domain names that end in a dot are called absolute, and are taken as complete. Domain names which do not end in a dot are called relative; the actual domain name is the concatenation of the relative part with an origin specified in a $ORIGIN, $INCLUDE, or as an argument to the master file loading routine. A relative name is an error when no origin is available.


<character-string> is expressed in one or two ways: as a contiguous set of characters without interior spaces, or as a string beginning with a " and ending with a ". Inside a " delimited string any character can occur, except for a " itself, which must be quoted using \ (back slash).


Because these files are text files severalspecial encodings are necessary to allow arbitrary data to be loaded. In particular:

of the root.
@ A free standing @ is used to denote the current origin.
\X where X is any character other than a digit (0-9), is used to quote that character so that its special meaning does not apply. For example, "\." can be used to place a dot character in a label.
\DDD where each D is a digit is the octet corresponding to the decimal number described by DDD. The resulting octet is assumed to be text and is not checked for special meaning.
( ) Parentheses are used to group data that crosses a line boundary. In effect, line terminations are not recognized within parentheses.
; Semicolon is used to start a comment; the remainder of the line is ignored.

RFC2181 “Clarifications to the DNS Specification”

Section 11. “Name Syntax”:

Occasionally it is assumed that the Domain Name System serves only the purpose of mapping Internet host names to data, and mapping Internet addresses to host names. This is not correct, the DNS is a general (if somewhat limited) hierarchical database, and can store almost any kind of data, for almost any purpose.

The DNS itself places only one restriction on the particular labels that can be used to identify resource records. That one restriction relates to the length of the label and the full name. The length of any one label is limited to between 1 and 63 octets. A full domain name is limited to 255 octets (including the separators). The zero length full name is defined as representing the root of the DNS tree, and is typically written and displayed as ".". Those restrictions aside, any binary string whatever can be used as the label of any resource record. Similarly, any binary string can serve as the value of any record that includes a domain name as some or all of its value (SOA, NS, MX, PTR, CNAME, and any others that may be added). Implementations of the DNS protocols must not place any restrictions on the labels that can be used. In particular, DNS servers must not refuse to serve a zone because it contains labels that might not be acceptable to some DNS client programs. A DNS server may be configurable to issue warnings when loading, or even to refuse to load, a primary zone containing labels that might be considered questionable, however this should not happen by default.

Note however, that the various applications that make use of DNS data can have restrictions imposed on what particular values are acceptable in their environment. For example, that any binary label can have an MX record does not imply that any binary name can be used as the host part of an e-mail address. Clients of the DNS can impose whatever restrictions are appropriate to their circumstances on the values they use as keys for DNS lookup requests, and on the values returned by the DNS. If the client has such restrictions, it is solely responsible for validating the data from the DNS to ensure that it conforms before it makes any use of that data.

See also [RFC1123] section

RFC1123 section Extensibility

DNS software MUST support all well-known, class-independent formats [DNS:2], and SHOULD be written to minimize the trauma associated with the introduction of new well-known types and local experimentation with non-standard types.


The data types and classes used by the DNS are extensible, and thus new types will be added and old types deleted or redefined. Introduction of new data types ought to be dependent only upon the rules for compression of domain names inside DNS messages, and the translation between printable (i.e., master file) and internal formats for Resource Records (RRs).

Compression relies on knowledge of the format of data inside a particular RR. Hence compression must only be used for the contents of well-known, class-independent RRs, and must never be used for class-specific RRs or RR types that are not well-known. The owner name of an RR is always eligible for compression.

A name server may acquire, via zone transfer, RRs that the server doesn't know how to convert to printable format. A resolver can receive similar information as the result of queries. For proper operation, this data must be preserved, and hence the implication is that DNS software cannot use textual formats for internal storage.

The DNS defines domain name syntax very generally—a string of labels each containing up to 63 8-bit octets, separated by dots, and with a maximum total of 255 octets. Particular applications of the DNS are permitted to further constrain the syntax of the domain names they use, although the DNS deployment has led to some applications allowing more general names. In particular, Section 2.1 of this document liberalizes slightly the syntax of a legal Internet host name that was defined in RFC-952 [DNS:4].

Update: Time Machine

Feh. Time Machine sucks. After a painful setup process, I left Time Machine to do its thing. I just saw it mount a disk image that it created on the remote volume, so I know that all the speculation about enhancements to AFP (and possibly HFS+) are bunk. If it’s going to create disk images, it could do the same thing on any kind of file server. There’s no excuse for the AEBS not working.
That, I’m sick, and it’s pretty clear Cal’s going to lose to ASU. Fuck, what a shitty weekend.
Update: Feh. Time Machine does not estimate time remaining nor current data rate. I seem to be getting about 28.92 GB/h (over wired gigabit Ethernet).
Update: Time Machine really consumes CPU cycles. When the MBP is idle, the fans are not audible. Since Time Machine has been backing up, they've been continuously audible. The average data transfer rate has dropped to 16.9 GB/h. I have spent a few minutes of the last two hours watching streaming video, and doing a little bit of other work, but mostly it has been running undisturbed. mdimport is also running, not sure why.
Update: The combination of Time Machine and Leopard on the client and server make for some seriously fast network volume mounting! Whereas SuperDuper! takes ages to mount a network volume served by a Buffalo GigaStation NAS (first the volume, then the disk image on that volume, a process that takes several minutes), Time Machine and Leopard get the disk image mounted in seconds. After clicking on the Time Machine icon in the Dock, most of the time spent waiting for time machine to actually engage (with a tip of the hat to Picard) is waiting on the server’s drives to wake up.
I have yet to see how well the whole system does when I sleep the MBP, go to another network, and wake it up again. Maybe I’ll try that this afternoon. For sure I’ll try it when I go to work tomorrow.
One other note: When engaging Time Machine, the network volume does not mount; only the disk image mounts. Not sure how they pull that off, but maybe that’s one of the enhancements to AFP in Leopard. Hardware Growler reports both the server volume and the disk image mounting; just the network volume is hidden from the desktop (even though I have configured things to show mounted volumes).
When Time Machine begins an automatic backup, it does not display the floating progress window. Opening the System Preferencs panel shows a progress bar, though.
Update: Time Machine doesn’t deal well with lost servers. I engaged Time Machine, let it mount the backup volume (disk image), closed the lid on the MBP (it took a minute or more to sleep, but this is not new behavior in Leopard for me), and went to a breakfast place with free WiFi. There, I opened the MBP, saw the Time Machine screen still up, waited for Hardware Growler to indicate that the system had self-assigned an IP address, and then started moving through time. After a bit of back-and-forth, Time Machine appeared to hang (although the starry background animation continued). After several minutes (5 - 10), I decided to force-quit Time Machine. Pressing Command-Option-Escape had no effect, and after pressing it several times, Time Machine suddenly disengaged and there was a server-disconnect dialog on the screen.
Also, during the time that Time Machine was up, a dialog was presented asking if I wanted to join one of a couple of networks, including the free one at at the breakfast place. However, I was unable to click on any of the networks to select them, and hence, was unable to join a network (the window could move, and the “Other…” and “Cancel” buttons worked fine). Feh. Feh.

Time Machine, AirPort Extreme and ZFS

First, the good news. It’s not new news, but it’s still good. Leopard shipped with a read-only implementation of ZFS. To get a beta version of a full read/write ZFS, you need to have an Apple Developer Connection account (the free Online membership is enough). Look in the “Mac OS X” section of the downloads area. I’m using v1.1.
Now, the bad news: you can’t use ZFS storage pools as your Time Machine Backup drive. Sigh. I’m not surprised, but I had hoped. Eventually, it makes sense for Apple to move to ZFS as the default file system, but who knows how long that will take? For the time being, HFS+ (Mac OS Extended) file systems store meta data about files that other file systems can’t handle natively. I suspect this is true of ZFS, too. You can hack your way around these limitations, by simply creating additional files on the system and storing the meta data in there, but that’s ugly. My hope is that Apple will enhance ZFS to support HFS+’s metadata natively, and that will be that.
Time Machine has other limitations, too. I’m not too upset that I can’t yet use ZFS for my backups (so long as Apple fixes this in the next six months or so), but I am upset that I can’t use the AirPort Extreme Base Station as a backup file server. It was said, in the months leading up to the release of Leopard, that Time Machine could back up to the AEBS. In fact, it’s the reason I bought the AEBS: I couldn’t be sure that a non-Apple file server would properly support AFP, and I had it on good authority (Apple) that the AEBS would do the trick.
I can speculate as to why: other Mac backup solutions, like SuperDuper!, create a disk image on the target volume to work around limitations in AFP. Although I’m not certain of the precise limitations, they have to do with file ownership and permissions (for example, a user ID on one system is not necessarily the same as a user ID on another system). From what I understand, Apple has enhanced AFP in Leopard (and by one account, HFS+, or at least the filesystem API) to accommodate the needs of backup software.
So, at the last minute, Apple tells us that you can’t use an AEBS as a backup server, but you can use Personal File Sharing on another machine running 10.5. I have an older PowerBook sitting around, so I decided to buy a FireWire external drive and use that as my backup solution (for now).
I bought a Buffalo DriveStation Duo. I chose it because Fry’s had it (I could get it right now) and I was able to verify that it can operate in JBOD mode. I wanted to try using ZFS first, and if that didn’t work, the DriveStation supports mirroring.
I followed the directions in the Apple ZFS Readme’s Getting Started section. As described in the readme, it was necessary to repartition the drives to use the GUID Partition Table. I had a bit of difficulty with this. The volumes mounted when I first connected it, and I used the Finder to unmount them. I tried to make a ZFS pool before repartitioning, which ZFS did without complaint, and which subsequently caused a new volume to mount. I unmounted that, but attempts to repartition resulted in “resource busy” errors (the other drive repartitioned fine). Disconnecting the entire DriveStation and reconnecting it seemed to fix it.
I built a nice ZFS mirrored pool out of the two drives, shared it via Personal File Sharing, and mounted it on the other Mac. Time Machine refused to recognize it as an acceptable backup volume. I briefly considered making a disk image on the drive and trying that, but decided I disliked that solution enough that I didn't want to use it even if it worked.
Attempting to use the ZFS pool on the local machine also doesn’t work.
The next step was to reconfigure the DriveStation as a mirrored array, with an HFS+ volume format. I tried to do this with the RAIDSetting application from Buffalo, but it failed with complaints about the "The old volume lable [sic] is not valid. Delete volume label by using disk utility.” After half a dozen attempts to repartition the drives as PeeCee drives, I still can’t get RAIDSetting to function without complaint. The front of the DriveStation shows a green #2 and a yellow flashing #1.
Also note: the RAIDSetting app from Buffalo only works on PowerPC Macs. Basically, the Buffalo DriveStation Mac support is crap, and I would recommend strongly against using it (if you want to use their RAID support).
I finally decided to just play through the pain, and ignore the error. It seems to set the drive into the right mode, so we’ll see what happens.
As I write this, I’ve mounted the new, shared HFS+ Backup volume on my MacBook Pro, and Time Machine is “Preparing.” I’ll try to post an update if it works.

Mac OS X 10.5 (Leopard) First Impressions

Well, I've had 10.5 installed for about 24 hours now, and so far, it’s not really worth the money. In day-to-day use (as a developer), none of the new features has yet to significantly impact my life. Sure, windows look a little different, and settings have been rearranged, but so far I don’t feel like I’ve gotten my money’s worth. For reference, I chose to “Upgrade” my system, rather than “Archive & Install.”
A few things are better. The variety of user interface styles has been reduced, and brushed metal is gone, replaced by a nicer-looking gradient (the Menu Bar looks a bit too much like a title bar, and I thought something was wrong with it until I realized it was transparent, and I was seeing the stars in the default desktop image through it).
Xcode has at least one improvement: it shows error messages in the editor window, directly underneath the offending line. It also complains a lot more about implicit conversions from double to float, but I can fix that.
One thing I’m not sure I like is that many standard icons have changed. Some have changed dramatically, like the System Preferences icon (it now looks like the iPhone’s Settings icon), and others have just been modified. These kinds of changes leave insecure users (like my parents) feeling disoriented, and I think they’re generally a bad idea.
One big fix: Apple Mail no longer seems to break long URIs! It has taken three or four major releases (an unacceptable delay to fix a minor, but very annoying, bug), but non-Mail clients can finally use long URIs sent by Mail without having to hand-edit them (Mail used to break them in a way that destroyed the URI for non-Mail clients).
Hardware Growler still works. My ARM development tool chain still seems to work. The Keyspan USA-19HS USB-to-serial adapter still seems to work. The FTDI USB-to-serial IC on the Sparkfun EM406 SiRF III Evaluation Board still works. ZTerm still works!
In the next post, I’ll talk about my experiences with Time Machine, the AirPort Extreme Base Station and ZFS.

iPhone Success!

After help my my good friend on the iTunes team, we determined that my account was still registered as a corporate account, rather than an individual account (iPhone only works with individual accounts). This was the result of me being a customer for more than 10 years.
I called AT&T back, and the CSA very quickly took some action to somehow finalize the conversion of my account from business to individual. Apparently, this final step had not been taken by the previous CSA. As soon as she did that, I was able to activate my phone, and my number ported within the hour (probably faster; I didn’t check it until an hour later).
Thanks to everyone (especially Mike W.!) who helped set this mess straight.
So far, I'm blown away by the phone, but there are some peculiarities. First and foremost, I wish all list views could have entries deleted by gesturing, rather than having to enter edit mode. Perhaps Apple will refine this sort of thing soon.
More to come, I’m sure…

iPhone Activation Woes

Feh. I’m sitting here with my beautiful new iPhone, trying to go through the activation process. iTunes keeps reporting to me how sorry it is that AT&T has determined that my current account cannot be used with the iPhone. It provided me a number to call, or offered me the option of creating a new account, which is really not what I want to do. I’m sitting on hold with a very kind Canadian customer service agent for AT&T.
Apparently I am on a promotional rate plan that is incompatible with the notion that all existing Cingular/AT&T customers can upgrade to iPhone. Okay, fine, after several attempts, he was able to switch me to a non-promotional plan.
Then, it turns out, my account is a business account. This is very strange. I’ve never asked for a business account. I’ve had my Cingular (the new AT&T) service since it was called Pacific Bell Mobile Services. Not once have I ever been told I had a business account. I’ve always used the “personal” account avenues when contacting Cingular (personal account contact numbers, the personal account link on the web page, etc.)
So, the poor Canadian CSA is waiting on hold with the AT&T business account division to convert my business account into a personal account, which should then allow me to activate my iPhone. Apparently the benefit of having a business account is that only a poorly staffed call center can handle your specific issues.

Waiting in Line

I’m in line, as I write this, waiting to buy an iPhone. Yesterday I bought a 3G ExpressCard for my MBP, and discovered that it doesn't work very well. I gave it to my buddy Mike to use, and he’s sharing the internet connection over WiFi (it seems to work much better for him).
A while ago one of the store employees came out (this was after a FedEx delivery at about 1300) and said, “I can’t reveal specific inventory levels, but all of you,” as he gestured to the whole line, "will be getting an iPhone."


It’s now 1428. Less than four hours to go…
Update (1438): I’ve just plugged the MBP into my buddy’s Vector Power Supply. Among other things, it includes a 200 W power inverter.

New AirPort Extreme base station

Well, I just finished installing my new AirPort Extreme base station. This is the one shaped like a Mac mini. The new software is very nice. They added the client signal strength graph feature, something that used to be there, then wasn't, and is now back again. They've also added link status lights to the ports on the back (although no indication of connection speed).

There were a couple of things that caused a fair amount of difficulty. One was that the new admin software has been renamed. The old one was called "AirPort Admin Utility." Thew new one is "AirPort Utility." I kept trying to upgrade my software before I realized the difference. When I was on the phone with Apple tech support, the agent told me this was a frequent source of confusion.

The other problem I had was that Comcast's cable modem seems to not assign a DHCP address to a new MAC address without being rebooted (this is what initiated the aforementioned support call). The AEBS behaves as if it can't get a DHCP address from Comcast, which is exactly what's wrong. The fix (in my case) is to unplug the cable modem for 30 seconds or so, and plug it back in. (Note: the Apple support agent wanted me to unplug it for 5 minutes, but I told him I'd try 30 seconds first—it worked).

I have yet to hook up a drive, the whole reason for getting it in the first place. I want to find out if they've improved AFP enough to where applications like SuperDuper! can back up over the network without needing to create a disk image first.

Now, to get an MBP with 802.11n networking in it...

Carbon Application Development in D

D is a very nice programming language by Walter Bright. Carbon is a very nice API for developing Mac OS X applications. I wanted to develop Carbon applications in D, so I created an open source project to let others do the same. Please check out Darbon, and let me know what you think!

This is what I want next: iPhone

This is the best phone ever, and I want one. The Apple iPhone.

Followup: MacBook Pro Kernel Panic with External Monitor

Some time ago I wrote about how my shiny new MacBookPro crashes whenever I plug in an external monitor. Turns out, Apple displays don't make it crash.
I wrote a bug about it, and Apple responded well. They gave me a tool to use to record information about the monitor.
Interestingly, I no longer have privileges to read or append to the bug I originated, and neither does my friend at Apple. I finally wrote a new bug referencing the old one to try to get some info, but it's been four months (and a few updates) without a fix.
Also, I'm on my third MBP since then, and it still crashes, so I'm fairly certain it wasn't a hardware defect (but it could be a hardware design flaw).


There are some cool things coming in Leopard (Apple's newest version of OS X). I recommend you take the time to watch the Keynote Address. As usual, there's a bunch of eye candy/fluff in Leopard, and it'll be interesting to see if they fix any of the numerous bugs that have been around since day one.


So, they've added a bunch of wizzy stuff in Mail that I could care less about. The ToDo thing might be cool; we'll see. I really want to know if they fixed the URL-splitting bug. My insider friend tells me that bug is fixed in Leopard, but it wasn't mentioned in the keynote (had it been, it would've received the loudest applause).


There's tons more cool shit. Watch the video.

Neat Scrolling Trackpad Tricks

So, if you use the index fingers on opposite hands, and put them far apart on the trackpad, you can hold one still and move the other and watch things scroll (sort of). Sometimes it helps to make initial contact with the trackpad simultaneously. If you move one up and the other down, they can cancel each other out.

Cinema Display Seems to Work

I just tried plugging in my 22" ADC Cinema Display (via an Apple DVI-to-ADC adapter), and it did not cause a kernel panic as did the Princeton LCD19D monitor. Hopefully, the school projectors will work, too, or I'm screwed.

Lest You Think I Have No Sense of Humor About New Technology

In my head, Jason is suggesting not buying one of the new machines because he read about my problems, so maybe this is still bitter and annoyed:


However, I don't think that Apple should've released these new PowerBooks without more testing. I don't think I've done anything particularly esoteric so far, yet my experience has been less than stellar.
Don't get me wrong, when the new MacBook Pro works, it works very well. But for the amount of money I've spent, and the sacrifices I've been willing to make (e.g, not being able to run "mixed-mode" apps, like in the 68k-to-PowerPC transition days), I feel like things should work better.

4 Cycles, 5446 mAh Capacity

After a "proper" recharge-full discharge cycle, my MacBook Pro battery is reporting 5446 mAh capacity.

MacBook Pro Kernel Panic with External Monitor


Wow. I keep finding more things wrong with this Intel machine. Now, if I plug in an external monitor (something I had not yet tried at home with my Cinema Display, but which I just tried now with a Princeton LCD19D flat panel display), I get a kernel panic. If an external monitor is plugged in when I reboot, I get a kernel panic. I've sent the crash report to Apple, but who knows if anyone will ever see it? Meanwhile, I'm now stuck without being able to use my big screens.
Here's the crash reporter info and the unfriendly message I sent along with it to Apple (I have no tolerance for crap like this):

panic(cpu 0 caller 0x0019CAEF): Unresolved kernel trap (CPU 0, Type 0=divide error), registers:
CR0: 0x80010033, CR2: 0x934ecd4c, CR3: 0x00d54000, CR4: 0x000006e0
EAX: 0x0000013c, EBX: 0x00000000, ECX: 0x13cfb6fc, EDX: 0x00000000
ESP: 0x13cfb60c, EBP: 0x13cfb6d8, ESI: 0x00000000, EDI: 0x00000000
EFL: 0x00010247, EIP: 0x0071aa44, CS: 0x00000008, DS: 0x13cf0010
Backtrace, Format - Frame : Return Address (4 potential args on stack)
0x13cfb4d8 : 0x128b5e (0x3bbeb8 0x13cfb4fc 0x131bbc 0x0)
0x13cfb518 : 0x19caef (0x3c1340 0x0 0x0 0x3c1028)
0x13cfb5c8 : 0x197b53 (0x13cfb5dc 0x13cfb6d8 0x71aa44 0x710048)
0x13cfb5d4 : 0x71aa44 (0x710048 0x122f0010 0x10 0x13cf0010)
0x13cfb6d8 : 0x71b089 (0x122fe000 0x0 0x0 0x20)
0x13cfb728 : 0x706739 (0x122fe000 0x1 0x10 0x20)
0x13cfb838 : 0x7082df (0x122fe000 0x13cfb8a8 0x4 0x0)
0x13cfb938 : 0x70ca59 (0x122fe000 0x4 0x0 0x0)
0x13cfb988 : 0x70baba (0x122fe000 0x4 0x8000000 0x10000000)
0x13cfb9a8 : 0x70c722 (0x122fe000 0x1fff 0x1fff 0x0)
0x13cfba08 : 0x702087 (0x122fe000 0x1 0x13cfba48 0x140774)
0x13cfba38 : 0x700aa3 (0x13cfbbce 0x122fe000 0x13cfba68 0x18)
0x13cfba78 : 0x70152e (0x122fe000 0x13cfbb98 0x281b9c4 0x284f8e0)
0x13cfba98 : 0x701681 (0x122fe000 0x13cfbb98 0x13cfbab8 0x19cb02)
0x13cfbad8 : 0x72002d (0x122fe000 0x0 0x13cfbb98 0x13cfbb98)
0x13cfbb68 : 0x596e28 (0x28d4800 0x13cfbb98 0x13cfbb98 0x85) Backtrace continues...
Kernel loadable modules in backtrace (with dependencies):
dependency: com.apple.iokit.IOGraphicsFamily(1.4.3)@0x574000
dependency: com.apple.iokit.IONDRVSupport(1.4.3)@0x58f000
dependency: com.apple.iokit.IOPCIFamily(2.0)@0x565000
dependency: com.apple.iokit.IOGraphicsFamily(1.4.3)@0x574000
Kernel version:
Darwin Kernel Version 8.6.1: Tue Mar 7 16:55:45 PST 2006; root:xnu-792.9.22.obj~1/RELEASE_I386
Model: MacBookPro1,1, BootROM MBP11.0044.B02, 2 processors, Intel Core Duo, 2 GHz, 1 GB
Graphics: ATI Radeon X1600, ATY,RadeonX1600, PCIe, 256 MB
Memory Module: DIMM1/BANK 1, 1 GB, DDR2 SDRAM, 667 MHz
AirPort: spairport_wireless_card_type_airport_extreme (0x168C, 0x86), 0.1.17
Bluetooth: Version 1.7.3f4, 2 service, 1 devices, 1 incoming serial ports
Serial ATA Device: ST9100824AS, 93.16 GB
Parallel ATA Device: MATSHITADVD-R UJ-857
USB Device: Built-in iSight, Micron, Up to 480 Mb/sec, 500 mA
USB Device: Apple Internal Keyboard / Trackpad, Apple Computer, Up to 12 Mb/sec, 500 mA
USB Device: IR Receiver, Apple Computer, Inc., Up to 12 Mb/sec, 500 mA
USB Device: Bluetooth HCI, Up to 12 Mb/sec, 500 mA
How fucking charming. A 100% reproducible kernel panic if I plug in an external monitor. Is my brand-fucking-new MacBook Pro a fucking lemon? Does its external video hardware cause a kernel panic, or is it crappy software? I know you guys never seem to develop while regularly swiching monitor configurations, maybe no one there ever bothered to plug in an external monitor? Fuck.
If I plug in a monitor after boot, or if I have it plugged in during boot, the machine kernel panics.
And crashreporter's "Send to Apple" button is disable when there's no network connection, but there's nothing in the dialog to indicate this is why. It took me 10 minutes of wondering how I was gonna get this info sent to Apple to realize I had not yet gotten on the wireless network here at work (because the crappy Migration Assistant failed to migrate any of my preferred networks' information over).

MacBook Pro Sleep Seems to Have Issues

I decided to run my battery down to do the calibration as suggested in the MBP manual. I got one warning about imminent sleep, and dismissed it. As I was copying a folder, the Mac went into forced sleep right in the middle of playing the "copy complete" sound. It repeated this sound a half-dozen times before the system finally went to sleep.
It darkened the screen, the little white LED came up dully (as it does when the screen's asleep), and then eventually it went into full sleep mode.
I tapped the shift key, to make sure it was really asleep. On my PowerPC AlPB, this is ignored. On this machine, it woke right up. I used it for a few more minutes, and then it completely shut down losing anything I had not yet saved. This was pretty bad.
I've now launched XBattery and plugged it in. Let's see if it gives us any more juice. Currently: 5419 mAh capacity, 3 cycles.

More Migration Difficulties

I reinstalled the OS (via "Erase and Install", removing unneeded languages, printer drivers and apps), completed the Setup Assistant without migrating. Then I allowed Software Update to run, updating to 10.4.6, and updating 9 other apps. Finally I ran Migration Assistant again, and it ran into the same problem: Apparently I have more than 60 million gigabytes of data in my home directory.
I'm currently on the phone with Apple support, but I am not hopeful that they'll resolve this issue (update: nope).
I tried before to remove all of my movies & images, but I had left music and sources from work in there. Maybe I should remove all four of those and try again. Here goes...

My New MacBook Pro

Yesterday I picked up a shiny new 2.0 GHz MacBook Pro. The packaging was expectedly beautiful, and the thing came up immediately after I powered it on. Nicely, Apple didn't insist that I charge it overnight before use; instead, they said to do the charge calibration steps sometime in the first week. It was 3/4 full when I got it. The beauty ended there...
I made sure it was plugged in and charging, and got started. I'd head good things about the Migration Assistant, so I opted to let Tiger migrate everything from my old PowerBook to the new one (via the Setup Assistant). I put the old one into FireWire Target Disk mode, and let it rip. After a few minutes, it had determined that there was in excess of 60,000,000 GB (yes, sixty million gigabytes) of data in my home directory to be transferred over. Unfortunately, I opted for the 100 GB hard disk (thinking that would've been enough), and so all the stuff on my old (80 GB) drive wouldn't fit.
Note the computed sizes of my home directory data to move (sorry about the utterly crappy photograph). Click for a larger image.

Migration Error

The other unconscionable thing the Setup Assistant did was go to sleep before finishing (mind you, it was plugged in and powered). I tried again later with the Migration Assistant directly, and it had basically the same problem. I'm guessing there's either a 32-bit int where there should be a 64-bit int, or someone forgot to swap bytes (I hate little endian, and this is one of the biggest reasons i hate Intel architecture, but since the old Mac is mounted as a drive on the new system, I doubt this is the real problem).
I'm now reformatting, reinstalling, and trying again. I'll post again after that's over.

Soekris net4521 Single Board Computer

I got my net4521 a few days ago, and after borrowing a CF card ('cause I stupidly forgot to get one of my own), I had it up and running Pebble Linux (from Tor Amundson) in no time. A few days later the CM9, miniPCI 802.11a/b/g card, arrived.

I've been poking at getting the 802.11 card up-and-running, and met with some success. Right now a kind soul is helping me learn how to use buildroot to build a Linux from the ground up for use on this box. We'll see how that goes, and I'll try to post the steps here.

Damned Hotlinkers

I discovered that the vast majority of the bytes I was serving was due to sites that hotlink, that is, sites that use image src URIs that refer to my site (thereby stealing my bandwidth), rather than copying the image to their own site and serving it themselves. Using Apache's RewriteEngine, as described in this article, allows me to refuse to serve images referred by any page not my own.
Hopefully this will put a stop to the practice. I currently only FORBID the request, but I may serve up some obnoxious image instead. Not yet sure.

Cingular GPRS and Mac OS X

I just subscribed to the $20/mo, 10 MB/mo plan that Cingular offers. Unfortunately, while you can use your cell phone to subscribe, and they can give you all the information you need (although it's like pulling teeth to get Mac info...like so many others, they only officially support Windoze), you can't download the necessary modem script to enable the whole thing to work.
They recommend you download GPRS Script Generator, which requires that you pay the $10 shareware fee before you can generate the necessary script. Fortunately, a very quick search on Google turned up an article on how to configure the Mac for Cingular Motorola use. It provides a modem script that seems to work well.
I have a RAZR V3, and I modified the script to connect at 115200 bps (rather than the default 57600). It worked great!
This is all temporary, of course, 'till I get my 3G card. We'll see how smoothly that goes...

My New HPI RS4 Pro 4 Hara Edition

I should've been packing, and then sleeping, before getting up at 0600 to catch a flight to the ’rents for the holidays. Instead, I spent the day (after work, of course) finishing the car, an HPI RS4 Pro 4 Hara Edition electric R/C. Three long nights, perhaps a total of 25 hours' build time. Here's a picture of the (more-or-less) finished car:

HPI RS4 Pro 4 Hara Edition Completed
Click for a larger image

There's also a large Gallery of pictures taken throughout the build process.

Overall the kit is well-crafted, with high-quality parts and a clear instruction manual. I do have a few complaints about the parts references, which caused me to waste a bit of time searching parts bags, but in the end, no necessary part was missing. I'll try to post a more thorough review, along with descriptions of the specific issues I had.
This car will be my (actually, my team's) entry into next semester's EE192 class and next year's Natcar competition. Hopefully the professor will allow us to use this car, and our intended processor, the Cypress PSoC.

Apple Ordering Problems

I ordered a Mighty Mouse last Thursday, after much anguish trying to determine if it was suitable. No Apple store had it in stock, and few even had it on display (both of which I consider egregious errors on Apple's part).
So, I finally placed an order via the online store on Thu 8/4. At this point, they're estimating 2-4 days delivery (it was same day/one day). I get an order confirmation, and forget about it for a couple days. I go to check status during the weekend, and the system is "down for scheduled maintenance."
I check order status today, only to discover that the order has been canceled. So, I call, and after speaking to three different people, learn that due to a prior fraudulent order using my credit card, I can no longer use that card with Apple's online store.
Back in April, I received an order confirmation email for a new PowerBook. Now, I never placed this order, so I called Apple. They quickly canceled the order, but my card was never charged (AFAIK). I tend to use a debit card with a $1000 daily limit, so there's no way for something as expensive as a PowerBook to have been purchased.
At no time, did Apple inform me that my card was flagged and could never be used again. Nor did they inform me when my Mighty Mouse order was canceled, nor did they inform me that the card was invalid when I placed the Might Mouse order.
And, to top it all off, the Mighty Mouse delivery estimate is now 7-10 days. While the fraud supervisor was gracious enough to approve this order and give me free overnight shipping, and he made it a "replacement" order, which apparently increases one's priority a bit, he could not really do anything to make up for Apple's incredible lack of communication.
Much of this could've been avoided, of course, if Apple had just shipped 200 mice to each store instead of 20. If they were trying to keep it under wraps, they could've ensured that a subsequent larger shipment arrived a couple of days later, rather than leaving everyone hanging.
But really, why make such an effort to keep it a secret? Who the fuck cares if we learn that Apple is going to ship a new mouse? How could it possibly affect anything about Apple's business? I'm not suggesting a six-month-early leak. But a week or two would not give anyone any kind of competitive advantage, and might have kept a few people from buying competing mouse products in anticipation. Instead, Apple has probably driven away frustrated customers.
In any case, secrecy on this product was not so important that Apple couldn't have shipped more units.

TextWrangler & BBEdit as External Editor

I use tools like Perforce and Subversion on a daily basis. I'm a Mac user at heart, and I hate tools like vi and emacs. However, Perforce and Subversion both use external editors like vi and emacs to allow the user to change things, namely checkin comments.
Well, BareBones Software has a pretty decent little text editor called "Text Wrangler" that comes with a command-line utility edit to make it easy to use TextWrangler from the command line (they also make BBEdit, TextWrangler's commercial big cousin). Invoking edit (use "bbedit" when working with BBEdit) all by itself launches TextWrangler. Specify a file name and TextWrangler opens that file, allowing you to edit it with a proper Macintosh user experience.
But, edit can do much more, including this: if you invoke edit -w <file>, it will open that file in TextWrangler, and block until you close the window! (I've tried this before using Apple's open -a command, but it immediately returns, making it useless.) This means you can use edit -w in the external editor configurations in Perforce and Subversion. And, if you add --resume to it, it will return to the Terminal.app after you're done editing. This may not seem like much, but it's more than any other non-CLI Macintosh text editor has been able to do.
Note: Chris Cotton tells me that TextMate also supports this usage.
Basic configuration for most UNIX tools is to set the $EDITOR environment variables (like this in bash:

EDITOR=edit -w --resume
export EDITOR

Read on for alternative information on how configure these tools.

To configure an external editor for Perforce, you can also set the $P4EDITOR environment variable.
To configure the external editor for Subversion, modify your ~/.subversion/config file to include this line:

editor-cmd = edit -w --resume

See the Subversion Book for more information on setting external editors.

Why Intel is Bad for Apple

Speculation hit the fan a few days ago when CNet (and WSJ?) reported that Apple would end its partnership with IBM and Motorola, and switch from using the PowerPC to using the Intel x86 architecture (I had heard the rumor even earlier through some old friends). Knowing this is almost meaningless, because there are so many details missing. For example, will Apple simply start manufacturing x86 computers that can run Mac OS X or (shudder) Windows? Does that mean that Mac OS X would run on any x86 PC?

This just in: the rumor is true.

Almost certainly not. Despite soaring sales of iPods, Apple's income comes almost entirely from the sale of Macintosh hardware. Releasing Mac OS X for x86 would kill their Macintosh hardware sales, because very few people would continue to go to Apple when they could get machines elsewhere for much less. I don't see any way Apple can make the switch without a significant drop in income.

But that's not the real problem. Apple could still make x86-based hardware that runs Windows, but allow Mac OS X to run only on their hardware. This would piss people off, but it's completely feasible (I'll post another entry about how sucky it will be for loyal Mac users to switch to x86 hardware).

The real problem is much more complex and subtle. And at first blush, doesn't sound like a problem. It sounds like a windfall for Mac users. Try to follow along.

Picture this: Apple makes the switch to Intel-based hardware. Mac OS 10.5 is released and runs flawlessly on it. All of your favorite apps release updates (never mind that these will be expensive upgrades, not maintenance releases), even Metrowerks. Then, using the knowledge gained from the 68K-PowerPC migration and a clever adaptation of WINE (an open-source implementation of the Win32 API), Apple adds the most significant feature: the ability to double-click a Windows application and run it on your Macintosh. No Virtual PC, no separate environment, no Start menu.

It's not that big a stretch. The windows might even look like Aqua windows. No doubt it would be a boon to Mac users, and would remove serious hurdles to Mac adoption across all market segments.

Mac users would notice a difference. See, Windows applications generally suck. While Apple could put the window close box in the right place, the OK and Cancel buttons would always be backward. Text selection in fields would be different (although Mac OS X kinda broke that anyway). Pressing the Tab key would tab through all of your controls, regardless of your system settings (although maybe some apps could be made to respect those settings). In many cases, menu shortcuts would require that you use the control key, not the Command key, to access them (no, you would not simply be able to replace "ctrl" with "command" inside WINE…for many reasons I can't get into here). I could write an entire article about differences between Mac and Windows apps, pointing out the real reasons why Windows is inferior to Mac OS. But I think most of you understand this. The Windows UI is fundamentally different from that of the Mac.

OK, so you say to yourself, so what? I've had to run VPC for years, I'm used to that. It's only in the one app I have to use, but now I can have it run fast? Sign me up! This is a perfectly understandable reaction. There's no reason a Windows app couldn't run at nearly the full speed of its Windows XP counterpart (there would be some overhead mapping I/O to the Mac OS, but not much; double-buffering windows takes time).

Now imagine you're a software developer making an application for both Mac and Windows. Your Mac customers comprise, generously, 15% of your market share (you've got more competition in the WIntel market). In reality, it costs you to work on the Mac version enough that your Mac margins are pretty slim, but it's still more income overall.

All of a sudden, Mac OS X/x86 is released with WINE. It doesn't take you long to realize that you will lose only a few of your Mac customers if you drop the Mac version of your product, because now they can run the Windows version just as easily. Sure, it'll take a year, maybe two, for Apple's base of Intel users to grow enough. But the old version of your app will still be available for your Mac customers who don't switch.

But you'll save so much money on development! Now all you have to do is make sure each new version of your Windows app runs on Mac OS X/Intel! And you won't have all of the marketing costs associated with delivering multiple versions of your app. What a boon!

If this sounds alarmist, it's because I haven't explained it well enough. (I have to get back to work, and I've already spent too much time writing this.) But think it through. Software developers who've made Windows and Mac OS versions of their applications will inevitably drop their Mac efforts. It's in their bests interests. Most people don't care enough to do more than grumble. They need the functionality, hamstrung as it is, to do their work. They will continue to pay for the application, especially because they can run it reasonably well. Mac-only developers will rarely, if ever, be able to profitably compete with established Windows applications. The growing momentum to provide Mac versions of applications will stop dead in its tracks.

It may take a few years, but you will slowly see the erosion of the Mac into an elegant OS for launching crappy apps.

And how long after that will once-loyal Mac users simply switch? There are so many more hardware choices in the WIntel world. Apple can never allow Mac OS X to run on that hardware, so we users won't see that benefit if we stick to the Mac. And once all our important applications are available only in their Windows flavors, what's to keep us using the Mac? Safari? Mail? iMovie? Sure, there will be some who stick around, like those who use FInal Cut Pro 90% of the time. But most of us? What would be left?

All of this is predicated on developing an architecture that allows Mac users to "painlessly" run Windows applications. Does anyone believe that will never happen?

The move is certainly bad for us. Within a few short years, we will lose many of our native Mac applications. But within a decade, it will be bad for Apple, too, as users abandon a platform that's lost all its advantages.

.xxx Will Never Work as Intended

ICANN has finally approved .xxx as a top-level domain. Unfortunately, according to one article, the strictly volunteer use will never encompass the majority of porn sites because ICN, the group responsible for administering the TLD, is going to impose rules about where and how a porn site may operate. Not only that, but domain names will cost significantly more than .com domain names do today:

The new domain will cost less than $100 and will be available to registrants willing to adhere to the predetermined best business practices.

There will remain countless porn sites in the .com TLD, dramatically reducing any "save the children" benefit that proponents claim the new domain provides.

Mac OS X 10.4 "Tiger" First Impressions

Okay. I've been running Tiger now for about 24 hours. Rather than work on my CS184 final project, I'll tell you a little about my experiences. This isn't terribly well organized, but I want to write things down before I forget them.

In a nutshell: there were some frightening hiccups along the way, and some bizarre behavior by the Spotlight indexer, but it all seems to be working fairly well now.


First off, I'd like to express my displeasure that while Apple has labored to create wonderful new features and eye candy, they still have not fixed small nagging bugs. For example, auto-scroll in list view in the Finder (and other apps) still does not work. There are also things that Apple refuses to fix, claiming they are by design: you still cannot let go of a scroll bar, and single-line edit fields have a broken selection model (someday I'll post a detailed analysis of why it's broken, and why the Mac OS 9 model is superior).

Before I complain too much, I'd like to point out that Spotlight is a pretty nice feature.


First hiccup: when I was updating my system (I chose to update, rather than "archive and install" or "clean install"), I was unable to deselect any of the additional languages. My very smart friend at Apple suggested that was because I was doing an update, and perhaps the existing system already had those languages installed. While that may be, an app should not provide me with an enabled checkbox and then not let me check it, and it should provide explanations.


I had PGP 8.0.10 installed, and the Mail plugin is horribly incompatible. This is not the first time PGP broke Mail, but it took my very smart friend to suggest it. After laboring to find the plugin, I removed it, and Mail worked again. Mail is much faster at some things, like deleting a bunch of messages. They also added the option to bold a message line if it was unread. But there are still many annoying quirks to Mail: it still breaks long URIs (I've heard the team is very sorry, that this fix just didn't make it, but is scheduled for an upcoming update; nevertheless, it's a pretty big bug, as it affects everyone who receives long URIs sent from Mail and who does not use Mail). Mail has other problems, too. In general, though, it seems to be faster. Note that Mail now stores each message as a separate file, so that Spotlight can index it well. Hopefully this won't overburden the file system. If it doesn't, then this will bring many improvements, not the least of which are improved robustness and more efficient backup (you don't have to back up your whole email store just because one new message arrived).

There's a PGP update coming someday.


This is the only feature, so far, that really pleases me. It has a robust, C-like query language, and seems reasonably fast. On my 60+ GB of data, the indices take up less than 1 GB.

When you first install, Spotlight must index your drive. After that, the file system updates the index every time a file is written. My very smart friend assures me that this is fast, and doesn't impact performance.

At first, Spotlight estimated 35 hours to index my drive. After a while, that went down to a couple of hours. Then, suddenly, it was done. I was able to search for a few things. Then, it was back to indexing. Then it was done. Then it indexed some more. All very bizarre, but in the end, it seems to have my disk indexed.

I've already created a smart folder that searches the Mac OS X 10.4 SDK (another good new addition: separate SDKs for separate OS versions) to find stuff in header files (suggested by my very smart friend).

CodeWarrior 9.0

That CS184 final project I'm avoiding? At first it wouldn't build after I installed Tiger. So I created a new project from stationery, and removed an #include <unistd.h>. Some experts on a list suggested that I didn't have the latest CW update installed, and they may be right. But that same list also had some traffic recently about the update breaking other headers in Tiger, so I'm reluctant to install it. At least I got my project compiling, and I don't really need getopt().

Since Apple keeps usurping command-key equivalents, I've moved my "find header file" key to be Command-Option-`. For some reason that no longer works, but I can't figure out who owns it.

Adium X

I use Adium X for chat, so I won't get to enjoy the new iChat very much. The only problem I've experienced so far with Adium X is that my iChat sound set broke. This is because it used Aliases to refer to the original iChat sounds, so I had to do some manual fixing to get it to work. It's almost where it was, but the new iChat seems to be missing the "1st IM" sound it used to have.


Autoscroll in list view still broken, but FS notifications are finally hooked up, so files should update instantly (rather than you having to deactivate and reactive the window).

Windoze Sucks

What a bunch of assmasters the people in Redmond are. According to David Kirkpatrick's article, Jim Allchin, some cheesehead at Microsoft, says Longhorn will be much better than previous versions of windows. At the start of the article, he (Kirkaptrick) writes "Jim Allchin, Microsoft's group vice president for platforms, looked at my Apple PowerBook and smugly pointed out that the number of copies of Windows sold this year will be more than all the Macintosh computers used worldwide." And he's proud of that fact!

So what? So what if your company is so big it can cram its product down the throats of millions of unaware customers. So fucking what? All the things Longhorn supposedly will do (like automatically reconfigure its network settings when you move from office to home), Mac OS X (even with its sucky-assness compared to OS 9) has been able to do for years. "If you put in a DVD, the volume will automatically adjust and the video will just start playing full screen"? This is a feature? With its armies of engineers (and a year and a half to go), this is the best fucky Microsoft could come up with after decades of stealing other's ideas? Losers.

"Longhorn will automatically clean up, or defragment, your hard drive, if it is required." Whoopdie-fuckin' do. Mac OS X's filesystem rarely requires defragmenting. But my old housemates shitty home theater PC choked on its own excrement if he did defragment daily.

Longhorn will show me the first page of a document instead of an icon? BFD. Been there, done that. I can put the same file in multiple places on my drive? Been there, done that.

"Microsofts research shows that the average corporate employee spends about 20% of her time on the PC simply looking for items." That's because Microsoft has never encouraged any sense of consistency among its legions of third-party developers, and because Windows' window management is piss poor, at best. No wonder people have a hard time finding things on windows. It's a direct result of the design of the UI. (More like LI…"loser interface").

Allchin talked about an upcoming 64-bit release of Windoze. Kirkpatrick writes, "For Allchin, this is a very big deal for businesses and individuals. The reasons are technical, but the bottom line is that 64-bit computers will be much faster. They should also be more secure." Is this what Allchin is spouting? Sorry, wrong and wrong. Not even the 64-bit Tiger will make your computer faster or more secure. Application developers will have to re-build their apps, and even then, most of what you'll get is the ability to address more memory. Which will probably mean that developers will create even more resource-hungry apps, creating additional burden on our already-overtaxed I/O subsystems.

And, I should point out, that the G5 is already a 64-bit processor, and Tiger ships this weekend, as opposed to "the end of the year" in Allchin's predictions.

Windows "Just Works"? Give me a break. Windows seems to go out of its way to prevent the user from getting work done. What a joke. And to those blind cattle who use windows: you suck, too. It's your fault Windows is as wide-spread as it is, and it's your fault computers suck as much as they do. Windows even pulls down the Mac (which, despite being utterly superior to Windoze, sucks too). Sure, lots of people use Windoze. Lots of people believe in a god, too, and look where that's getting us.

And Kirkpatrick, as a Mac user, you're way to upbeat and positive in your story. Afraid you'll lose future interviews?


RayTracing is Fun

CS184's assignment due a few hours ago was a simple ray tracer. So far, the most work, but also the most fun. I implemented a ray tracer that supports ellipsoids and triangles, point lights and directional lights (oops, forgot to mention that to the reader…hope (s)he picks up on that from the images), subsample antialiasing (jittered). It also renders to the screen and outputs jpeg directly, and uses an ANTLR-generated parser to read in scene files. Here are the images I submitted along with my assignment.

Some represent mistakes, but they're interesting anyway. I thought my images were cool, but Sarah Beth's snow globe takes the cake. Creative and refractive. How cool is that?



























If this works, Ecto kicks ass

I'm not sure how to use it yet, but I'll give it a try. Hopefully it will play nicely with SmartyPants.

This is some indented text. Dunno if it's really block-quoted, or what. Hmm, no, not block-quoted, which means Ecto might restrict the HTML structure I can impose on my entries.

Now, let's see what the iTunes button does: Let Go from the album "Details" by Frou Frou. Cool. It inserts the currently-playing song. Not sure why that needs to be a button right here in the app, but I guess we're all likely to have lots of need to make emergency references to songs...

Why Apple Fucked Up with Aliases

Aliases used to be this thing in the Mac OS, prior to Mac OS X, that allowed applications to remember where a file was located. More importantly, if you moved that file, the application could still find it. They worked across network volumes, too, automatically mounting a volume if necessary.
With Mac OS X, Apple recommends that an application store URLs to reference files. The problem with URLs is that they are just fancy pathnames to files, so if you move or rename a file, they break. To be fair, I've seen documentation that suggests CFURLRefs should be used only for transient storage of a file reference, but this gets abused across the board.
Safari's downloads window, for example, is guilty of this. Try donwloading something, moving it, and then finding it via the download window. You can't. And Apple puts the blame on the user by popping up a message saying, "Safari can’t show the file 'foo.pdf' in the Finder because it moved since you downloaded it."
Fuck you, Apple. So what if it moved? You can find it, almost always. You had tried and true, superior technology, and when you shitcanned or otherwise drove out all the true Macintosh engineers, replacing them with NeXT Unix weenies, you got rid of that good technology. Everyone knows engineers brought up on Unix are lazy, and don't give a rat's ass about the user. Well, that attitude shows through in Mac OS X.


I've created a Delicious Library-to-HTML converter. It's very raw, but it gets the basic task done. I'll try to avoid schoolwork by continuing to improve on it over the weekend.

Followup: Brother MFC-8840DN

A while back posted an entry about my Brother multifunction laser printer. In it I mentioned that 20-lb 3-hole paper almost always jammed, but that 24-lb paper worked. Well that wasn't quite true. 24-lb paper works about 70% of the time, but still jams far too frequently.
The longer I own this printer, the more and more disappointed I am with it. I could care less about the fax and scanner if the printer doesn't meet all my needs. It's painfully slow (at least compared to the HP 2300N at work), and often times can't print.
For example, printing AMC theaters movie listings from Safari results in a command syntax error. Printing the same page to a PDF file and then printing also does not work.

The Brother MFC-8840DN Multifunction Laser Printer

I recently bought the Brother MFC-8840DN Multifunction Laser Printer from Staples online. I wanted an HP 2300DN, but what I needed was a duplexing, networkable, Mac OS X-compatible laser printer. Mike Kobb pointed out the Brother, and I decided that it was a much better deal.
It arrived the day after I ordered it (free shipping!), and I excitedly set it up. It's very important to pay attention to the installation instructions--there are a great many pieces of stabilizing tape that need to be removed.
Of course, getting a Windows XP machine to work with it proved to be difficult, but the Mac OS X setup was a breeze (just copied the PPD, didn't bother with the MFC ad-ons yet). The printer supports Rendezvous, which is very cool.
Now comes the bad part: Almost everything I'm going to print will go into a three-ring binder. So, I bought some Hammerhill 20 lb. 3-hole multipurpose paper, which claims to work well in any copier or laser printer. Unfortunately, my MFC-8840DN just couldn't cope. It jammed 9 out of 10 times. My first attempt to get support from Brother was useless. My second attempt was better, in that I got a response, but they simply said that the printer is not advertised to work with 3-hole paper. Although the user manual mentions kinds of paper you should not use, it does not even mention 3-hole paper. Another exchange with the customer service rep produced nothing helpful. The manual did recommend Hammerhill 24 lb plain paper, so I decided to try a heavier stock.
The only way to get that was via Office Depot online, so I ordered a ream. Fortunately, using Hammerhill brand 24 lb 3-hole paper seems to work. If it starts to screw up again, I'll post here and let you know.

I finished Halo

What an accomplishment. I played the entire game through on "Heroic" difficulty, and re-played the last level on "Legendary." The alternate ending was cute. I wonder if there's another ending for playing the entire game on Legendary.


So, I got this nifty little MT plugin called "SmartyPants." If I installed it correctly, the quotation marks around "SmartyPants" will be proper open- and close-double-quotes, even though I typed them as straight quotes (\") when writing this entry.

OS X Still Sucks in So Many Ways

I just recently came across this message in the Finder when I tried to rename a running application:

Are you sure you want to change the name of <appname> while it is open?

Changing the name of an application while it's open may cause problems with the application.

This is caused by the same problem experienced in ScreenSaver: if you change the name of, or move, the folder of pictures to which ScreenSaver is pointing, it will lose track of it.
Both of these problems happen because Mac OS X dicourages the use of Aliases, system-standard data structures for referring to file system objects. Instead, applications are encouraged to use path names. The problem with a path name is that it’s fragile: if you move the item or change its name or the name of any of it’s enclosing directories, an extant path no longer points to that item.

Because Mac OS X encourages the use of pathnames in applications as references to files (via CFURLRef, among other mechanisms), applications are very likely to store these paths, despite the occasional feeble warning against doing so.
Now, it’s one thing for an individual application to make this mistake, but for Apple to endorse this behavior by warning users that they shouldn’t change the name of running applications, rather than letting those applications break. Instead of forcing applications to do the right thing (store file system item references with Aliases, not paths), they make the user wrong by preventing (or at least discouraging) him from changing the name of a file.
Related to this is OS X’s emphasis of filename extension as the way to identify a file’s type. The filename is for use by the user, and the OS’s use of it should not impose any restrictions on what the file name can be.
In the case of filename extensions, Apple has gone to great lengths to try to hide the extension from the user. They still use a string of bytes to store an ID representing the file type, but what they’ve done is move the storage of those bytes on disk from a tidy, dedicated location to the end of the filename, where it gets in the way of the user. Though the hide it, it’s easy to get into situations where the user is either warned about changing the file extension (exposing it), or they inadvertently change the represented file type (without changing the underlying bytes). Bad, bad move, Apple.
It’s just another indication of how Apple has lost sight of what it takes to make a great OS: the details (to get really nit-picky, notice that the error message uses a single straight quote, instead of an apostrophe. It&rquo;s possible it just looks straight given the rendering). Ever since NeXT engineers crowded out Apple engineers, this has been the case.

AirPort & USB Problems with AlPB and Panther

I love my new 15" Aluminum PowerBook G4 (1.25 GHz, backlit keyboard, SuperDrive) very much (many thanks to my facilitator at Apple who helped make it a reality). It’s mechanically much more sturdy than was my TiPB, the fan runs almost never, and the backlight works (which is why I replaced my otherwise fine TiPB). I also think Panther (10.3.1, build 7C107) is a huge improvement over Jaguar.
However, I’m starting to have serious problems, and I don’t know how much of it to blame on Panther and how much to blame on the new hardware.
It started yesterday or the day before, when I restarted (I can’t remember why) and all of sudden my separate keyboard and mouse stopped working (I typically connect the PowerBook to my 22" Cinema Display which has a black/clear Apple keyboard and mouse connected to it). I have an Apple ADC adapter which is normally plugged into the DVI port and the USB port on the right side of the PB.
The USB devices had no effect on the UI, and the mouse light was dark. After a bit of unplugging and re-plugging, I discovered that if I plugged the mouse directly into the port on the left, everything came back, and I could plug the mouse back into the Cinema Display.
BTW—I’ve noticed that unplugging or plugging in a USB device causes a sleeping PowerBook to wake. I understand this to be a problem other PowerBook/Panther users are experiencing, and not just on AlPBs.
I came into work this afternoon, plugged everything in and opened the lid on the PowerBook. Everything came up fine. I read through the day’s mail (Mail), checked to see who was online (Adium), listed my bugs (IE; normally I use Safari, but Bugzilla doesn’t work quite right with it), and then headed for lunch with the group. When I came back, both screens were dark, and hitting keys on either keyboard failed to wake the machine (this is the kind of problem I’d been having on my TiPB prior to Panther).
So, I held the power button until the PB shut off, pressed it to start it up, and ran into the same USB problems described above, but slightly different. Before, the mouse’s light would not come. This time, the light was on, but the mouse had no effect. I unplugged it and plugged it back in to the Cinema Display, but now the light was off for good. I finally discovered that I had to plug the ADC adapter into the left-hand USB port to get those devices to work at all, but they still had no effect on the UI (although the mouse’s light would at least come on).
Apple System Profiler shows two USB roots. Nothing under the first, a hub under the second, a hub under that, and an Apple Optical Mouse under that.
Now, here’s where it gets much worse: the PowerBook thinks there’s no BlueTooth and no AirPort! They’re not off, they’re simply not installed!
So I restarted a couple of times throughout all of this, trying various things (e.g., I removed the Cinema Display from the mix altogether). The PB now recognizes that there is BlueTooth hardware, but refuses to see the AirPort card. And no amount of restarting or USB device permutations seems to make USB work. I just tried plugging the mouse directly into the left port, and the light comes on feebly (just sort of flickers, and not in the way it does when you move the mouse and it gets brighter), but the cursor won’t move.
At this point, I’m at a loss. I’m writing this entry using the PB’s own keyboard and mouse, and hopefully that will hold out so I can get some work done today.
Oh, one more issue: I got into a situation a couple nights ago where the keyboard backlight refused to come on (or be adjusted). The room I was in was very dark. I had to restart to get it straightened out.

I hate Cocoa

I’m getting so tired of hearing people say things like “our product for Mac OS X features a completely new Cocoa-based user interface to take maximum advantage of Apple’s new operating system.” Cocoa does not give an application any superiority over Carbon. Cocoa is not more stable, nor does it perform better. It doesn’t even really make life any easier on the developer.
But people continue to buy into the hype, and then regurgitate it on their customers.

Panther & Office X

Here’s a hint for those of you upgrading to Panther. I just tried running Office X for the first time since installing Panther, and Word kept crashing. After a little investigating, I realized that (for some reason I don’t remember), I had Office X 10.0.0. After applying three updaters, Office X 10.1.5 seems to work fine.


HTTP Future Features

I have no idea what’s in store for HTTP 1.2 and beyond, or if there’s even any work being done on it. But here’s one feature I’d like to see.
In general, an HTTP request is made to be secure or non-secure by the scheme used in the URL sent by the user agent (https: or http:, respectively). However, this puts a burden on the developer of the website (usually a webapp) to ensure that URLs get written correctly.
This is a consequence of the use of SSL for HTTP security. SSL happens at a protocol layer below that of HTTP. The secure connection is established first, then the HTTP protocol is layered on top of that. By the time the server gets a chance to determine what resource is being requested, the SSL connection must have already been established.
It makes much more sense for an HTTP request to be made, and if the server determines that the requested resource is secure, that the connection then become secure. In other words, the requested resource should be able to dictate whether or not it needs to be secure.
This means we need a way to transparently make secure a connection that began unsecure.
There are complications with this, of course. Many times, information needs to be sent as part of the request in a secure fashion (your login and password information, for example). A way to handle this needs to be devised, of course.
Even the specific URL might need to be secure. That’s what HTTP currently does. The only thing you can’t keep from prying eyes is the IP address and port to which the request is being sent.
There are ways to mimic this behavior. For example, an unsecure request to a secure resource can cause a secure redirect. But redirects cause problems in the user agents, most notably involving the back button.
Okay, that’s all I can write for now, but I’ll try to get back to this subject later&hellpi;