I upgraded from a TiBook 667 to an AlBook 1.25ghz (15″). Quite the upgrade. It was also an entertaining experience.

My home directory is about 10GB and it is encrypted using FileVault. My first thought was that I shoudl be able to configure the new powerbook appropriately, copy over the sparse disk image containing my home account, log in and everything should “just work”.

My TiBook doesn’t have firewire any longer. The magic smoke in the FW controller chip escaped in a rather cataclysmic event some time ago. Once you let the magic smoke out, electronics just never work quite the same, if at all, afterwords.

So, I was faced with copying a 10GB disk image through ethernet. As I didn’t have enough cabling to have all of my machines connected at the same time, I decided to try something radical.

I simply dropped an ethernet cable between the two powerbooks. I knew that would work because the powerbook ethernet ports are smart enough to figure out when a crossover connection is needed vs. a normal connection.

Not only did it work, but it turned out that I didn’t need to turn on internet sharing or give either machine IP addresses. Rendezvous just worked and I was able to share files and, even, ssh between the two machines by using their sharing name.

As well, because I was using direct cabling both machines automatically used the highest speed setting available on the port; 1 gigabit. Nice and speedy!

Once copied, I simply created a user account with the same username and with filevault enabled on the new machine. I then logged out of the new account (you have to log in ot the account to turn on FileVault) and simply replaced the new sparse disk image with the old sparse disk image.

Upon logging back in, my entire account was now on the new machine and everything “just works”.

Nice!

3.25 miles. Wonderfully still foggy morning.

Over the weekend, I installed a dryer and fixed the washing machine. Both jobs required dealing with user serviceable parts. Which surprised me. The consumer electronics and small appliance industries expects the customer to deal with devices as black boxes that are not to be opened or repaired by any but trained professionals. Yet, the large appliance industry still ships documentation describing various basic internal maintenance tasks and still offers replacement parts directly to the consumer (a new belt will cost $10.65 when the current belt finally fails).

It seems that the auto industry’s attitude has shifted from DIY to Black Box as cars have become more computerized.

I enjoy taking things apart and making them work better or work again. While I find it a challenge to figure out and fix devices that are not “user serviceable”, it is refreshing to work with devices where user service is supported by the manufacturer.

Key/Value coding is a large part of what makes Enterprise Objects, WebObjects and the Cocoa Bindings so elegant and consistent while requiring very little code.

I have often wanted to be able to start a key path at a class. By doing so, it would allow one to express key paths that could retrieve user defaults, use the app’s main bundle, retrieve anything hanging anywhere on a path reachable from the shared NSApplication instance, or retrieve or set any other attribute found via a shared instance of one of the various manager classes. It would also allow one to express any of the standard colors as a key path.

Extending the evaulation of key/value paths themselves would be easy, but doing so would have an unfortunate performance impact. Since key/value paths always start at some random subclass of NSObject, the alternative is to simply add a method to NSObject that returns an object that knows how to evaluate the next element in the key/path as a class name.

Adding this functionality is trivial. The code below can be added to any Cocoa our Foundation project. This project contains the code below and some example usages contained within the NIB file using the Controller layer. It displays two windows. The first window contains the identifiers and paths of all frameworks linked into the application using an Array Controller with its contentArray binding bound to the path keyValueClassCoding.NSBundle.allFrameworks. Another window displays all font families.

#import <Foundation/Foundation.h>

@interface ClassCoder:NSObject
@end

@implementation NSObject (ClassCoderAccess)
- keyValueClassCoding
{
    static ClassCoder *classCoder = nil;
    if (!classCoder)
        classCoder = [[ClassCoder alloc] init];
    return classCoder;
}
@end

@implementation ClassCoder
- valueForKey: (NSString *) aKey
{
    return NSClassFromString(aKey);
}
@end

Update: Oops. I screwed up. +intialize won’t work in categories. For some reason, I had latched onto the notion that it worked like +load in that it would be invoked per category as well as per class. As it turns out, multiple +initialize implementations per class (loaded via categories) behaves in a non-deterministic fashion. Thanks to Mike Ferris for kindly pointing out my error. The above code will work much better an the zip file linked above has been updated.

I chose not to use +load because it is relatively evil in that it is invoked well before main() and there is zero control over order of invocation. In this case, I could most likely get away with it, but I would rather have “100%” working over “most likely” working. If the extra cycle used to if (!classCoder) bothers you, there are a couple of solutions including one truly evil solution involving IMP swizzling (but still using public API).

All of my old posts have now been extracted from Radio. Upstreaming to the filesystem didn’t work. Backup didn’t work. Fortunately, Radio implments the Blogger XML-RPC API and, equally as fortunate, Python offers a trivial interface for calling out to XML-RPC servers.

This was the first post I ever kept in Radio. It was posted on 19-January-2002, within days of exactly two years ago. The first few posts I made were deleted accidentally. Nothing really lost.


Maybe I’ll actually start posting to this thing. Maybe not. Radio is really a pretty crappy application. I mean, I appreciate the power and everything that has been achieved– but the look and feel SUCKS.

This whole half-desktop-app-half-browser-app-lets-duplicate-functionality-between-but-make-it-different approach to an app is really broken.

Yet, at the same time, it does make publishing notes and sharing ideas really bloody easy (as long as you don’t even remotely attempt to look under the hood– then it doesn’t make sense). To those ends, Radio is a hell of an achievement and the community surrounding it is confirmation.

I would really like to roll my own solution, but time is not something that I have a surplus of.

If I could only figure out how to publish via WebDAV, life would be good… I am not a number, I have a domain all my own.

Radio was an education, certainly, and worth every penny of the $40 or so that I put into it. Thanks UserLand! I sincerely hope that Radio 9.0 ships someday and, when it does, that it follows some kind of useful modern API and HI guidelines.

The script to export from Radio is as follows:

#! /usr/bin/python
import sys

password = sys.argv[1]

import xmlrpclib
import xml
server = xmlrpclib.Server('http://localhost:5335/RPC2')
lastPost = server.blogger.getRecentPosts('export','home','default',password,1)

if not lastPost:
    print "failed to get last post"
    sys.exit(1)

postCount = int(lastPost[0]['postid'])
print "Exporting %d posts..." % postCount

for i in xrange(0, postCount + 1):
    try:
        post = server.blogger.getPost('export',i,'default',password)
        content = post['content']
        dateCreated = post['dateCreated']
        out = file('post-%03d.txt' % i, 'w')
        out.write(post['content'])
        out.write('\n\n%s\n' % dateCreated)
        out.flush()
        out.close()
        print "Wrote post %d...." % i
    except xml.parsers.expat.ExpatError:
        print "Skipping post %d...." % i
    

It expects your password as the first argument on the command line. You could easily hardwire it by replacing the sys.argv[1] with your password in ‘quotes’ on the 4th line.

Only 2.2 miles today, but at a considerably faster pace. Mostly due to lack of time. Looks like a house near ours burned in the last few days. Just the garage. Bummer.

Spring comes early in the south bay area. My Iris are going nuts, the bird of paradise is in full bloom, and the paperwhites are nearly over.

Jeff laments the dysfunctionality he experiences when LaunchBar isn’t running.

I totally sympathize.

I have gotten so used to banging <cmd><space> to switch apps as a sort of punctuation to my work flow that my keyboard has started to show signs of wear specific to <cmd><space>. Specifically, part of the cmd squiggly is gone.

Back when I was using LaunchBar on cheap PCs running OpenStep (good OS makes bad hardware passable), I hit <cmd><space> hard enough that the space bar on the cheap PC keyboard went flipping across the room. That was fun.

From Drudge:

In what political watchers are calling possibly the biggest gaffe in years, former Vice President Al Gore is set to give a speech tomorrow on the perils of global warming — on what is expected to be the coldest day in New England in nearly half a century!

Translation: Either voters are stupid or no one is interested in educating them, so we are going to make up a really big story about how Gore is stupid instead!

It seems that people do not understand and the press is unwilling to actually try to educate the reader that Global Warming is about the average temperature of the whole world rising. In other words, the total amount of energy contained within the atmosphere is increasing. While the average temperature may be increasing, the increase in energy also results in more variance within the weather patterns. A sustained increase in the amount of energy within the atmosphere will cause climatic changes, including permanent changes in weather patterns.

While high temperatures will increase, so will extreme lows. Worse, areas that don’t normally have extreme temperatures one way or another probably will. Similarly, areas that are generally dry may have massive rain and vice-versa.

So, that fact that is butt ugly cold in NYC could certainly be the result of “global warming”. Of course, it could just as easily be that cold because it was time to be that cold and not because of any climatic changes.

The press is full of dumbasses that are more salesman than factfinder. “If it requires more than 3 brain cells to understand what might be going on, we’ll make something up that even total nimrods can understand — any resemblance to truth is purely coincidental.” It is too bad that so many people don’t realize that that is the case and make an active effort to figure out what the hell is really going on before casting their vote.

Update: Roy Blunt, the republican representative from Missouri, took the opportunity to poke at Gore with the statement of “It is fitting that Gore chose one of the coldest daysof the year to spread false information about the Bush Administration’s record on global warming. Mother Nature didn’t agree with his message and neither do I. Al, it’s cold outside”. What a dumbass.

Regardless of the Global Warming thing, one event does not a trend make. Blunt should have learned that in the equivalent of junior high statistics. Not only has Blunt made an uneducated statement about global warming, he is further demonstrating his clue impairment using a single event as evidence supporting the uneducated statement.