Thursday, March 31, 2005

Test Cases redux

Dave Winer again:

The uniform response was that since Cory's book is offered under the Creative Commons attribution share-alike license, I am not "permitted" to change the author's name, or charge for the right to a copy. I put the word permitted in quotes, because the responders haven't explained why Cory's work is so-protected and my work, which is offered under a standard copyright, isn't.
My response did not claim that Dave's work is not protected; the issue is that Cory's work is protected, and that the extent of that protection is clearly delineated by the license he's chosen.

(Note that Dave misstates Cory's license here: the Attribution-ShareAlike license would, in fact, allow Dave to charge for a copy of Cory's work. But Down and Out is actually under the Attribution-NonCommercial-ShareAlike license, which explicitly forbids commercial uses.)

[N]ot only is it possible for Cory to opt-out of my creative rip-and-burn act of 21st Century artistry, but it actually requires Cory to opt-in! Well well well.

Does this perhaps ring a bell?
Ah, back to Google Toolbar again. No, it doesn't ring a bell. Regardless of Dave's copyright or Cory's license, fair use suggests that, for personal use, I'm free to print portions of their work and annotate it; doodle on it; cross out the author's name and replace it with "arsehole"; fold it into a paper plane and fly it into the waste-paper bin.

There's no "opt-in" or "opt-out" from fair use: it gives rights to users, not producers, of content.

Now, Google Toolbar's modifications are made in my browser; at my request; and without republication. That to me sounds very much like annotation for personal use. The "print-it-out" analogy holds: would it be OK for me to print out your web page and use a pencil to annotate an address with a reference to a street map grid square? Clearly yes. Why then is it not OK for me to use Google Toolbar to annotate an address with a link to a map?

Wednesday, March 30, 2005

Cookbooked

Python Cookbook, 2nd Edition, p480: look, it's me!

12.10 Merging Continuous Text Events with a SAX Filter; Credit Uche Ogbuji, James Kew, Peter Cogolo

My contribution was minor: a couple of comments on Uche's original recipe. But still, it's nicer to be in than out. And O'Reilly were true to their word: my free copy arrived yesterday.

I haven't had a chance to read much of it yet, but the first edition was excellent both as an all-round grounding in Python idiom and as a source of concrete examples. The second edition drops coverage of Python 2.2 and below to concentrate in more detail on Python 2.3 and 2.4, with 338 recipes vs the first edition's 245. I'm greatly looking forward to ploughing through it.

(For future reference: O'Reilly's Python Cookbook page also carries an up-to-date list of errata.)

Oh sweet irony, redux

Paul Graham's quickie essay on how to write well ends in a single-sentence paragraph so long that simply reading it makes me feel dizzy. Want to write well? Give your readers room to breathe!

I'm more than guilty of this myself, of course. I overuse colons, semicolons, and dashes, overloading my prose with unnecessary run-on sentences. But I'm fighting back: one of my standard editing steps is to work through the text challenging every linking piece of punctuation. For me, the rule is simple. If it could be a full stop, it probably should be a full stop.

I love his ending, though:

[L]earn to recognize the approach of an ending, and when one appears, grab it.
And he's right: writing well is important. It's particularly important for techies. The best idea in the world won't fly unless you can communicate it well.

Writing code has a lot in common with writing prose: good code is crafted to clearly express its meaning to readers. The Literate Programming methodology takes this to extremes. But there are plenty of little things that help make code tell its story. Name things thoughtfully; use simple constructs; group related things together.

And at a very basic level: your code comments speak for you. Make sure they speak clearly and well. A lot of my first impressions of reading code come from the comments. If they're misspelled, ungrammatical, incomplete, or cryptic: what does this say to me about your code?

Test cases

Dave Winer kicks the tires of copyright and has a poke at Cory Doctorow, who's spoken out against restrictive copyright many times:

Somewhere in there, there's got to be a line.

I'm thinking of mirroring Cory Doctorow's Creative Commons-licensed book and crossing out his name and replacing it with mine. Then I think I'll go to a printer and print up a bunch of copies of my book and stand on a corner in Times Square and sell copies.
This is all very fine and rhetorical, but it seems to me that Cory's already drawn a very definite line in his choice of Creative Commons license for his books: they're all released under the Attribution-NoDerivs-NonCommercial 1.0 license, which specifically disallows both uses suggested by Dave.

[Update: while Down and Out in the Magic Kingdom was originally released under this licence, Cory relicenced it in February 2004 under the broader Attribution-NonCommercial-ShareAlike 1.0 licence; this licence allows transformation for non-commercial use as long as the attribution remains and only if the transformed work is distributed under an identical licence. Still no good for Dave's uses.]

A Creative Commons license does not mean "do whatever you want with this content". As they say:

We have built upon the "all rights reserved" of traditional copyright to create a voluntary "some rights reserved" copyright.
Dave's strawman argument takes a stark black-and-white stance: "Cory doesn't like restrictive copyright, so he must be against all copyright." But the reality is more shades of grey; Cory's happy for you to redistribute his books, but he's very definitely and clearly reserving some of his rights.

Tuesday, March 29, 2005

Sorting in Python

List sorting in Python (the list.sort method) is fast: sorting has been heavily optimised in successive versions of Python.

However, there's always been a penalty to pay if you don't want the sort's default ordering. Maybe you want to sort on one field, for example sorting a list of log items by timestamp. Or maybe you want to sort by some function of each item, for example sorting a list of vectors by magnitude.

Historically there have been two methods of doing this. The simplest is to pass a custom comparison function to list.sort:

def cmp_magnitude(a, b):
    return cmp(a[0]*a[0] + a[1]*a[1],
               b[0]*b[0] + b[1]*b[1])

vectors.sort(cmp=cmp_magnitude)


Here we're sorting 2D vectors by magnitude, using the standard trick to save an expensive square-root operation: sqrt(x) is monotonic in x, so sorting by the square of the magnitude is equivalent to sorting by magnitude.

This code is easy to understand, but slow. It makes a Python function call for each comparison made in the sort; and a sort will typically make many more comparisons than there are elements to sort.

The second, trickier method is known in the Python world as decorate, sort, undecorate (DSU) and in the Perl world as the Schwartzian Transform. The trick here is to decorate each element in the list by prepending a key to each element; to sort the decorated list with the default sort; and then to undecorate the list by stripping off the keys, leaving the sorted list of elements.

decorated = [(val[0]*val[0] + val[1]*val[1], val)
             for val in vectors]
decorated.sort()
vectors = [val for (key, val) in decorated]


This avoids multiple calculation of the key by precomputing each key once; and avoids the multiple expensive calls to a custom comparison function. However, the auxiliary list, decorated, takes extra memory and extra time to construct and deconstruct. And the code is not straightforward to the untrained eye: once you're familiar with DSU, you'll easily identify it as such, but if you haven't seen DSU before it takes a little puzzling through.

And there's another potential pitfall to DSU: it may not have the same behaviour in the face of equal keys as sort-with-cmp. In sort-with-cmp, elements with equal keys will be subject to whatever behaviour sort implements for equal elements. In Python 2.4, sort is guaranteed stable, so the existing order will be preserved. In previous Python versions, sort was not guaranteed stable; although in practice it usually was.

In DSU, elements with equal keys will be sorted by value. This may or may not be a problem, depending on the application. To avoid this and retain stability in elements with equal keys, decorate with both key and index:

decorated = [(val[0]*val[0] + val[1]*val[1], i, val)
             for (i, val) in enumerate(vectors)]
decorated.sort()
vectors = [val for (key, i, val) in decorated]


Or you could borrow from a typical C programming pattern: don't sort elements, sort pointers or indexes to elements:

indexed = [(val[0]*val[0] + val[1]*val[1], i)
           for (i, val) in enumerate(vectors)]
indexed.sort()
vectors = [vectors[i] for (key, i) in indexed]


Python 2.4 adds an extra optional argument to list.sort, key, which can be passed a custom key-computation function. One call to key is made for each element in the list. The list is then sorted by the key of each element, rather than the value of each element. In effect, this internalises DSU within list.sort's implementation. The code is straightforward:

def key_magnitude(a):
    return a[0]*a[0] + a[1]*a[1]

vectors.sort(key=key_magnitude)


This is as clear and concise, and has the same stability in the face of equal keys, as sort-with-cmp. But it also avoids most of the overhead of sort-with-cmp, calling a key function once per element rather than a comparison function multiple times per element.

Some timings, sorting float vectors of various lengths N (code); all times in seconds:

sortN=
1001,00010,000100,0001,000,000
sort(cmp)0.001170.01910.2723.4743.6
DSU0.0002120.002740.2653.5741.9
stable DSU0.0002250.002890.2733.6945.4
index DSU0.0002280.002950.2753.7344.6
sort(key)0.0001680.002020.02780.4486.28
normal sort0.0001050.001650.02390.3785.38

And the same data in a log-log chart:

Chart.

What this shows is that, for small N, the DSU pattern is significantly more efficient than sort-with-cmp. However, at N=10,000 and above, DSU's overhead in list allocation, decoration, and undecoration starts to bite, leading to similar performance to sort-with-cmp. The two stable DSU patterns have slightly higher cost than plain DSU, with index DSU in general performing slightly worse: possibly the indexing overhead in reassembling the undecorated list is to blame.

But in all cases, sort-with-key is an order of magnitude faster than any other sorting pattern, with performance close to that of a regular sort. If you're targetting Python 2.4, it's time to let go of DSU: sort-with-key is the new state-of-the-art.

Monday, March 28, 2005

iTunes script: Album Shuffle

Although normally I love iTunes Party Shuffle, today I'm suddenly sick of it. It's too choppy, like channel-surfing TV; today I want to listen at album length but I'm not sure what I want to listen to.

It strikes me that what I need is an Album Shuffle to choose for me. Here's a first cut: iTunesAlbumShuffle.py. (Requires: iTunes 4.5 or above; Python 2.4.x or above plus the pywin32 extensions -- or just get the ActivePython distribution.) Run once to populate an album's-worth of tracks into an Album Shuffle playlist, which it'll create if necessary.

Ideally it'd stick around and watch what's being played, removing played albums and adding new albums as needed; but those are version 2 features.

At the scripting level, you get a glimpse into iTunes internals. Sources, playlists and tracks are what iTunes really deals in at the database level. Albums are an abstraction which iTunes, and iTunes scripters, have to build by aggregating tracks with common Artist and Album attributes. That's why this script has a long startup time: it has to walk the entire iTunes library to determine what albums are present.

A quicker method might be to pick a random track from the library and then do an IITPlaylist::Search to find other tracks in the same album. Pitfalls await the unwary here, though. IITPlaylist::Search can match either on all track attributes, or on one and one only of the track attributes. In either case, you'd need to filter the search results to flush out any false positives. And selecting with this method skews the random choice by weighting albums with many tracks heavier than albums with few tracks. (The current code gives an equal weighting to all albums; possibly the fairest method would weight albums by the inverse of their length, allowing short-and-sweet singles a better chance than bulky doubles.)

And as I'm using Python 2.4, I get a chance to play with two new minor features: the sorted() builtin, and the key argument to list.sort() and sorted(). Nice. A lot of the sorting code I've written in the past could have be streamlined with these.

Oh and its first pick? Coldplay's A Rush Of Blood To The Head.

I made this: Pistachio Cake

This pistachio cake was very good.

I didn't bother with the odd-sized tin the recipe recommends; I used a 9"x5" loaf tin. And I didn't bother lining the tin after I greased it; there's plenty of butter in the cake mix, and it released easily from my non-stick tin.

I substituted 2 tsp natural vanilla extract for the vanilla bean. And I mixed it all in the food processor: first grind the nuts and reserve. Then cream the butter and sugar; add the eggs one by one; add the lemon zest and vanilla; add the nuts and flour; pour out into the tin.

It took a shade over 60 minutes to bake in my oven, and be careful: for me it went from wobbly-in-the-middle unset to slightly-too-browned-on-the-edges set very quickly. Maybe the slightly shallower tin the recipe recommends would avoid this.

If you're using raw pistachios, toast the nuts for the topping. And I doubled up the lemon juice and sugar for the glaze to use up the naked lemon left over from the cake.

I was very pleased with this: it's moist, very nutty, and has a good hit of lemon from the glaze. And it came out just like the picture.

I made this: Onion Dip

Potluck at Melinda's parents. I'd bookmarked this dip at The Amateur Gourmet a while ago and it seemed like a good time to try it out.

It's a Barefoot Contessa recipe, Adam's cagy about the exact proportions, and I don't have the book — I had checked it out of the library a while ago, but wasn't all that impressed by it. But, I thought, how hard can it be?

Anyway, I winged it like so:

3 onions (I used 2 ½ white, ½ red, 'cause that's what I had on hand), roughly chopped and slowly fried 30 minutes with a knob of butter, a splash of olive oil, 1 tsp paprika, ½ tsp chili powder. (Adam says cayenne, but I didn't have any.) Fry until very soft and golden; and it really doesn't matter if some of them catch a bit.

Cool the onions down and mix with: 2 tbsp mayo, 2 heaped tbsp sour cream, 2 heaped tbsp cream cheese. Refrigerate overnight to let the flavours blend.

It came out good and it all went; I'd definitely make it again. Although next time I'd make two minor tweaks: chop the onions finer, and thin it a little with a splash of milk.

[Update: made it again with these tweaks for the 4th of July; good.]

Saturday, March 26, 2005

Las Trampas, again

Back to Las Trampas, with the East Bay Casual Hikers this time. I'm starting to become a regular: now sometimes it's me that disoriented new members approach asking "are you with the East Bay group"?

A change from the usual 10am Sunday start: today we're Saturday at 1pm. I rather like the later start, but there are fewer of us today: 13, compared to last time's 25.

We take exactly the same route as Melinda and I followed last December: up the Rocky Ridge Road, along the ridge on the Upper Trail, down on the Elderberry Trail. I'm definitely fitter than last time I walked it. Today I'm able to get up to the ridge with only a few stops to catch my breath.

It's a cool hazy day, but the views are still good. And no chill winds blowing along the ridge today. A lot more comfortable than last time. The way down is still just as muddy, though.

We stop by afterwards for a treat at TCBY in San Ramon. What does TCBY stand for? "The Country's Best Yogurt", apparently, although their website gives no clues. But I think that's overstating it a little. I have a white chocolate and peanut butter frozen yogurt swirl. It's good, but it's not great. I've had better yogurt at Yogurt Park and, oddly, at Costco.

Categories: Hiking

Scary and depressing

Metroland Online (via BoingBoing, ambiguous.org): Texas's block-buying policy for school textbooks has led to all textbooks adopting the Texas "abstinence-only" stance on sex education, which prescribes abstinence until marriage without any mention of safe sex or contraception:

Consider the fate of two health-education textbooks submitted for adoption in 1994. Holt Rinehart Winston proposed a modestly worded abstinence-first textbook. Texas conservatives sharply disapproved. Even worse, the textbook used line drawings to show girls how to conduct a self-examination for breast cancer. The notion of taxpayer-funded pictures of breasts drove conservatives wild with rage. The Holt textbook went down to defeat.

[...]

Mindful of the 1994 experience, progressive activists prepared in 2004 for another harsh battle over sex education. But they had reckoned without the textbook executives’ keen instinct for self-preservation. "The books came precensored," says Steve Schafersman, president of Texans for Science. "Textbook manufacturers can tell which way the wind is blowing far ahead of time. They capitulated in advance."

Holt’s new textbook corrects the previous edition’s ideological missteps. For example, Holt Lifetime Health provides a list of eight tips for preventing STD infection. The list starts with "Practice abstinence" and moves on to such helpful tips as "Get plenty of rest," "Respect yourself," and "Go out as a group." But the list omits Holt’s recommendation from the 1994 edition: "Using a latex condom properly during sexual intercourse reduces the risk of getting an STD during sex."
"Get plenty of rest" is considered better advice than "be safe"? What is wrong with this country?

[Update: and of course, "respect yourself" is a new-millenium retread of that 50s staple, "nice girls don't".]

Thursday, March 24, 2005

The Office US

Like falling through into an alternate reality: you recognise the situation, the camerawork is the same, the characters are vaguely familiar but all have different names... but it's not funny any more.

Without Ricky Gervais, it's nothing. The actor playing the Brent character (here renamed Michael Scott) tries hard but is too pinstriped to fill Brent's shoes.

And the original Office was all about the supporting cast too: it was as much about Tim as it was about Brent. Here Tim is renamed to Jim, and played well by an actor with more than a passing similarity in appearance to Martin Freeman. But the Gareth character (now Dwight) is wasted. His pompous self-importance here comes over as petulant and whiny.

On the evidence of tonight's pilot episode, not much cop. Maybe it'll pick up and find its stride in future episodes.

One good new joke, though: Scott shows off his "World's Greatest Boss" mug ("says it all, really") before letting slip that he bought it for himself ("I found it at Spencer Gifts").

Why iTunes rocks

I claimed a while ago that iTunes rocks. Here's why: having all your music at your fingertips at all times completely changes the way you experience music.

We went digital by necessity: a dead hifi left the PC's CD-ROM drive as the only device we owned capable of playing music. But we stayed there by choice.

The biggest, most fundamental difference: every piece of music you own is a few clicks away. When you play CDs, there's a cost to changing albums: eject, swap, load. And that's if you can find the CD you want to listen to. Often you can't be bothered; easier to simply play the CD again, or rotate through the stack of CDs close to hand. When you're playing digital, changing albums is as cheap as changing tracks. You can be much more of a magpie; roaming across the library, picking artists, albums, tracks at a whim. Everything's to hand. It lures you into becoming your own DJ.

iTunes isn't unique in this, of course; before Windows iTunes appeared, we used RealJukebox (now RealOne or Real Player 10 or whatever it is Real call it this month). But iTunes does it very well: it's slick, quick, and intuitive.

iTunes search is great for roaming the library. It searches for full or partial words across all the track metadata (artist, album, track name etc). And it does it live and on-the-fly; you can see the search narrowing as you type more characters. It feels enormously natural: you remember an artist and maybe one word of the title, type 'em in, and up comes the track.

Oddly, though, I didn't twig this to begin with. Maybe it's the engineer's viewpoint, but my first impulse, faced with tracks organised by artist and album, was to find tracks by first finding and selecting the artist, then finding and selecting the album, and then finding and selecting the track. "Why would you want to search?" I thought, "it's all organised logically for you." Melinda's first impulse, faced with a huge library of tracks, was to go for the search box. And boy, was she right: it's quicker, easier, and more flexible to search than to select.

Recent iTunes versions add Party Shuffle, which essentially allows you to have iTunes play DJ for you, picking tracks at random from the library. At first glance this seems underwhelming; I can do a better job than that! But using Party Shuffle tends to break you out of your recent favourites, pulling up tracks from albums you might not have heard for a long time.

But best of all, you can co-operate with Party Shuffle: you can override it's choices of upcoming tracks. Reorder them. Delete them, forcing it to choose again. Add your own choices. You get to cooperate with iTunes, deciding how much freedom to give it. I love this: Party Shuffle pulls up a mixture of the familiar and the esoteric, leading me into albums and tracks which I don't necessarily remember well, and if I like what I hear I can take over and cue up more of the same.

It's not clear what algorithm Party Shuffle uses to choose tracks. You can tell it whether or not to favour highly-rated songs, but it often feels like there's more than pure randomness at work. It'll often pick songs by the same, or related, artists close together. Conspiracy theories abound. My suspicion is that it's pattern-matching and selective memory at work: it probably is truly random, but us humans are very good at spotting islands of order amid chaos, and we're better at remembering the pleasingly-ordered selections than the less-interesting stretches of randomness.

As the library gets bigger, maintaining it becomes more of a task. Metadata becomes more and more important the more tracks you have. Accurate titles, years, and genres make searching and playlisting easier and more flexible. But at a more basic level, there's something enormously satisfying about a well-organised properly-labelled iTunes library. And there's a payoff for having decent track metadata: it's food for Smart Playlists.

Smart Playlists choose songs from the library by matching against the metadata, so you can build playlists of (for example) "20 random 70's songs", or "all country songs". And iTunes generates extra metadata for you: it keeps track of how often each track is played and when it was last played, so you can build playlists like "most recently played songs" or "all songs never played". Smart Playlists are live, so when you change the metadata (by editing the track's info, or simply by playing the track) the playlists are automatically updated.

It goes deeper and deeper; you can build playlists with multiple conditions ("all songs rated 4 stars or higher that were not played in the last month") and you can build playlists which theselves refer to other playlists ("all songs which appear in either/all of these playlists"). More and more ways of exploring the library, more and more ways of tuning iTunes to approach your ideal personal radio station; more and more things to play with. It's so much fun that there's a blog dedicated solely to collecting Smart Playlist settings: SmartPlaylists.com.

And Smart Playlists themselves play well with Party Shuffle: you can set Party Shuffle to choose songs from either the whole library or from a playlist. Bingo! Create a Smart Playlist of "all songs never played or not rated", Party Shuffle on it, and you get iTunes playing DJ over all the stuff that you either haven't listened to yet or that you haven't rated yet.

Finally — and this appeals to me enormously as a software engineer — iTunes is extendable and scriptable. Extendable with a plugin architecture, which is how visualisers like the excellent G-Force hook into iTunes. Mac iTunes was AppleScript-able from very early on; us Windows users had to wait until release 4.5, which is scriptable from VBScript, Perl, Python etc via a rather nice set of COM interfaces.

I'm not sure anyone's done anything major with the COM interfaces: they're still relatively new. But they're ideal for knocking up quickie utility scripts. Simon Brunning's had some fun with them using Python (fixups, batch conversion), which works very well once you've gotten to grips with the (rather sparsely documented) pythonwin extensions. Hopefully the large number of iTunes AppleScripts available on the web (many collected at Doug's AppleScripts for iTunes) will inspire Windows scripters.

Oh sweet irony

Via Kottke's remaindered links, I find Glassdog's article on Boing Boing's increasing embrace of paid advertising: Boing Boing, Ka-Ching Ka-Ching.

And what's the banner ad running on Boing Boing when I hop over there to check them out? By some serendipitous accident, this:

browser screenshot of BoingBoing with banner ad reading: I LIKED YOU BETTER BEFORE YOU SOLD OUT

(The ad, by the way, is for an indie t-shirt.)

"Not like our old album"

Lemon Jelly sticker: This is our new album. It's not like our old album. So I finally got around to buying the new Lemon Jelly album, '64–'95.

As the sticker on the front says, "it's not like our old album". Less whimsy; more rock. Fewer vocals; more looped samples.

It's a big risk to take when the last album was so well-loved for its quirkiness, and for me it doesn't quite come off. Compared to Lost Horizons, there's nothing here that's as witty or as memorable as Ramblin' Man and Nice Weather for Ducks; and there's nothing as joyous as Spacewalk ("whoa! beautiful, just beautiful").

Part of the problem is that many tracks are repetitive in their use of sampled vocals: Don't Stop Now is the worst offender here, repeating the phrase "don't stop now" innumerable times over a rhythmic background.

It's not that it's a bad album; a lot of it's very pleasant, and some tracks (for example, the rocking opener Come Down On Me) are excellent. The trouble is, it's just not as good. Maybe it's a grower; time will tell.

Oh, and as an aside: I simply don't get the whole William Shatner revival. Have we forgotten how awful The Transformed Man, his terribly earnest 60s album was? He's a good fit on the last track here, Go; but as a singer — and arguably as an actor too, although its impossible to imagine Star Trek without him — he's a novelty act, nothing more.

Tuesday, March 22, 2005

Recipe tweaking: Asian Chicken Salad

I find I'm checking a lot of recipe books out of the library at the moment; my initial infatuation with novel preprepared junk food has worn off. (Tater Tots: good. Hot Pockets: despite what Dr. Evil says ("try a Hot Pocket, they're breathtaking"), not so good. Rice-A-Roni: varies, some good, awful. Hamburger Helper: suprisingly and embarrassingly good.)

Anyway, this recipe — from Mark Bittman's book, The Minimalist Cooks at Home — was a real stinker the first time. Mostly my fault: I misjudged the amount of water and my cheap bottle of soy sauce is probably a lot saltier than his. The second time around I cooked it my way and it turned out a lot better; it may yet be a keeper.

Here's how much it changed between his version and mine:

Asian Chicken Salad
4 2 servings

1 1/2 pounds 1 boneless, skinless chicken thighs or breasts
3 tbsp 4 tsp soy sauce
1 1/2 2 tbsp crunchy peanut butter or tahini
1 tsp roasted sesame oil
1 2 small garlic cloves (or 1 large), peeled and crushed
a few drops a good dash Tabasco
1/4 tsp sugar
1 tbsp rice or other mild vinegar (cider vinegar works well)
1 cucumber
1/2 cup minced cilantro leaves
1/2 cup rice
2 handfuls salad leaves (baby spinach works well)


Cut chicken meat into cubes, skewer, drizzle with 2 tbsp soy sauce. Grill or broil. Season chicken and pan-fry whole in a little oil.

Cook rice by absorption method with 1 cup water.

In a blender bowl, mix remaining soy sauce, peanut butter, sesame oil, garlic, Tabasco, sugar, vinegar. Add 4 tsp hot water 1 tsp at a time until smooth and creamy. (You will not need more than 3 tsp water.) (Don't bother with the blender: the dressing is too thick to pour easily from it, and it's one more thing to clean.)

Peel, deseed, and dice cucumber.

Dice chicken. Combine, garnish with cilantro with cucumber and dressing. Serve on rice and salad leaves.

Still basically the same, but a bit less fidgety. More of a hot meal than a salad. I upped the peanut butter because I like it; and who scoops half-tablespoons of peanut butter, anyway? Similarly, I upped the Tabasco because I liked the undertone of heat; and because a dash is easier to shake out than a few parsimonious drops.

It seems to me that, to make cooking fun, you need a smidgeon of confidence and a healthy disregard for what your recipe says. Once you know the basic mechanics and have some feel for what flavours work together, you can work by feel through a lot of the time.

That said, I've been feeling more like a beginner in my new American kitchen. A different cooker with different idiosyncrasies. Some ingredients are new; some are different; some have changed name; some are harder to find or more expensive than I'm used to. And American recipes all work by volume rather than weight.

It interests me, too, how recipes evolve through familiarity. A lot of my favourites get cooked more from memory than from their recipe card, and a lot of them have changed over time as substitutions and simplifications get made. Most annoyingly for Melinda, most of the changes remain in my memory rather than being committed back onto the recipe card: "oh yeah, it says 1 teaspoon chili powder, but that one's really strong so I use half a teaspoon".

I told you already

I like Windows XP's Automatic Update feature; if there are patches available, particularly security patches, I want to know ASAP. Although I don't quote trust Microsoft enough to let it auto-install updates, so I have mine set to "download, but let me choose when to install"; this also lets me choose what to install.

But, having installed an update earlier, I'm getting a bit sick of seeing this alert popping up:

Alert: Automatic Updates: Updating your computer is almost complete. You must restart your computer for the updates to take effect. Do you want to restart your computer now? with buttons Restart Now and Restart Later.

Look, buster: I'm in the middle of something. I already told you I'll restart later. Take my word on this. You don't need to keep popping back up every 15 minutes like a nervous puppy: "are you gonna restart now? how about now? huh? huh?"

Chickpeas

I have a big pot of chickpeas soaking in the kitchen. There's something very comforting about the quiet cracking noises they make to themselves as they swell.

(Yes, I know; they call 'em garbanzos over here. I can deal with calling courgettes zucchini, aubergines eggplants, and coriander cilantro; but I fear to me a chickpea will always be a chickpea.)

Cucumbers and muffins

Regular cucumbers here are garden cucumbers: thick, squat, and full of seeds. Skins are thick, dark green, slightly warty, and usually so heavily waxed that peeling them is the only option.

The cucumbers I knew from home — long and narrow, with thin slightly ridged skin — are sold here as "English cucumbers", usually at a premium.

Oddly though, "English muffins" here are neither muffins nor English; they have a much more open texture than the breakfast muffins sold in UK supermarkets, almost closer to a crumpet. Thomas' is the main brand, but I'm rather partial to the Orowheat sourdough muffin.

Friday, March 18, 2005

Somewhat addicted

Net Game: connect up all the tiles to the power source.

It interests me because you very soon start constructing heuristics on how to solve it: for example, no wire can connect to a wall which makes the normal game (with walls around the board) pretty simple to solve.

The wraparound game is a lot harder, with only a few walls to start you off, which brings in other heuristics (everything must connect, so any move which forms an closed island is wrong) and more indictive reasoning ("if I did this, what would that imply?").

Sometimes the game gets the minimum required number of moves wrong:

Net game screenshot showing minimum required moves 94, finished in 93 moves.

Libraries

I read voraciously, so I'm a big fan of the county's library system: libraries here are well-stocked and open long hours. The catalogue and renewals system is online. Video and DVD rentals are free — which'd be useful if we had a video or a DVD player, but anyway...

And best of all, you can put a hold on anything at any library in the system and have it sent to your local library for pickup, free. This hugely increases the pool of books I have available; in Windsor, I had to pay for holds which meant I rarely used them. Here, I'm placing holds regularly.

There's a huge contrast between Danville library, which I used to use, and Walnut Creek Library, which I use now. Danville built a huge and expensive new library in 1996, which means they have a very nice building filled with a pretty poor stock of books.

Walnut Creek still uses its original 1961 library building, which was built to handle a population of less than 10,000; Walnut Creek now has a population of 65,000 and the library is way too small. But the stock: the stock is fantastic. Plans are afoot to rebuild, subject to securing finance, but the new library could yet be a long time coming.

Valid

After some template tweaking and some minor fixups to a few articles (all fixing this little nit):

Valid HTML 4.01!

And I'm claiming this one too, on moral grounds at least: my CSS validates, Blogger's included CSS doesn't:

Valid CSS!

Wednesday, March 16, 2005

AZERTY

This BBC news headline floated across my Bloglines: Azertyuiop out to defend crown. Yep: this racehorse is named after the first line of the French keyboard layout. I wonder if he has a brother named Qsdfghjklmù?

US keyboards differ just enough from UK keyboards to throw me off slightly: " and @ changing places, in particular, are a problem to adjust to.

But French keyboards? As I learnt from several work trips to Paris offices: French keyboards are a nightmare to work on for developers used to QWERTY layouts. Most letters are where you'd expect them to be, but some aren't. Punctuation keys are scattered. Unshifted, the number keys produce punctuation and accents; you have to press Shift to get numbers.

So: when working overseas, always take a keyboard with you. But even then, sometimes fate and Microsoft conspire against you. What's harder to use than a French keyboard? A UK keyboard to which Windows has applied the French keyboard map. Try typing your password on that, sucker!

Tuesday, March 15, 2005

Metablogging

I've been reading Burningbird a lot recently, and boy is she on top form. A lot of her recent posts have been in the metablogging (blogging about blogging) category: in particular, about the circles of "successful" — so-called A-list — bloggers.

Links are the currency of trade here; a link from a successful blog brings audience and so increases reputation. But the blog world is cliquey; successful bloggers tend to link to other successful bloggers. And so the in-crowd forms.

And surprise surprise: as Steven Levy recently noted in the mainstream press, most of the blogging in-crowd are male and white.

In Guys Don't Link, Burningbird skewers the whole Google Toolbar furore in style: all the "don't add links to my pages" complainants are in-crowd male bloggers, for whom links equate with power. Her writing is witty, but it's also angry:

Sites such as Technorati become the internet version of a locker room, where the guys can hang around, comparing themselves to each other. Those that come up short look at their better endowed brothers with both envy and admiration; sucking up in order to increase their own stature.

When we women ask the power-linkers why they don’t link to us more, what we're talking about is communication, and wanting a fair shot of being heard; but what the guys hear is a woman asking for a little link love. Hey lady, do you have what it takes? More important, are you willing to give what it takes?

Groupies and blogging babes, only, need apply.
In Our Weekly Allowance, she asks:

Is the trick for being a successful female weblogger to promote ourselves among the A-list? Does this mean, then, that we must act nice, be nice, to the A-List, in order to get the notice resulting in a 'successful' weblog? Well if that’s true, then I’m really screwed.
In You Are Hurting Us, a response to the Levy piece, she notes the immediate "no, we are diverse" response from white male bloggers:

I knew as soon as I saw the Steve Levy article that we would see a backlash about the domination of whites and males in the weblogging ranking systems.

[...]

To the white guys who have been proclaiming your race and sex with such pride: It would seem that not only are you not content with being king of the hill, you also want to be chief underdog, too. Not content to being the center of too many dialogs within weblogging, you also want to be the center of one discussion that, oddly enough, doesn't center around you: being a weblogger who is not a male, or is not white, or both.
before railing against the popularity culture of weblogging:

Dave Sifry from Technorati: Dave, you are hurting us.

The Technorati Top 100 is too much like Google in that 'noise' becomes equated with 'authority'. Rather than provide a method to expose new voices, your list becomes nothing more than a way for those on top to further cement their positions.
This is great writing: passionate, well-thought out, expressive, and unafraid. Bravo.

It all seems a long way off though for this Z-list blogger: my readership consists of a handful of family and friends, plus anyone who stumbles in through the "Next Blog" button or a misguided Google search. Do I need more readers to be successful? Probably not to meet my original goals for this blog: "keep in touch" and "write more often and more widely".

Sunday, March 13, 2005

Python decorators

I'm getting back into Python; in particular, I took the plunge and upgraded to 2.4.

One of the new features in 2.4 is decorators: a decorator is a function which wraps a function, adding extra behaviour. The name comes from a well-established design pattern, although it's slightly misapplied in Python; strictly speaking, a classic GoF Decorator adds responsibility without changing the interface, while a Python decorator may change both behaviour and interface.

Really though, decorators were always possible in Python:

def func(...):
    # Function body.
    pass

func = decorator(func)


In earlier versions of Python, the classmethod and staticmethod builtins were used just like this.

What 2.4 adds is syntax. The decorator syntax was thrashed out in one of the longest and bloodiest debates on python-dev — second only to the great Ternary Operator War of 2004 — which eventually led to Guido (Python's BDFL) pronouncing that the syntax should be:

@decorator
def func(...):
    # Function body.
    pass


And look: in 2.4, the classmethod and staticmethod builtins are decorators and can be applied with the @-syntax. What the @-syntax brings to the table is brevity (no repetition of the function name) and better scoping (the decorator is applied at, not after, the function definition).

The best current documentation for decorators is the relevant section of the Python 2.4 What's New; there's also a library of decorator examples forming in the Python wiki, and a number of Python Cookbook recipes for decorators.

I thought I'd have a play with decoration to attack a problem: expressing prerequisites. Say I have a pile of data — track metadata extracted from iTunes — and a pile of functions which validate various aspects of that data and which need to be applied in a certain order. For example, in my example, it may not be meaningful to validate disc numbers until the disc counts have been validated.

The blunt way to do this is to hard-code a list of functions that obey the constraints of the prerequisites. But it'd be nice to be able to plug in new functions without having to manually update that list; Python's introspection capabilities make plugin architectures easy.

So, step 1: add a prereqs attribute to each function. (In Python, functions are objects so can — and do — carry attributes.) The What's New gives an example for this:

>>> def deco(func):
... func.attr = 'decorated'
... return func
...
>>> @deco
... def f(): pass
...
>>> f
<function f at 0x402ef0d4>
>>> f.attr
'decorated'


The decorator takes a function as argument and returns a function as result. But I want to be able to provide a list of prerequisites as arguments to my decorator. This is funkier: decorators which take arguments must themselves return a decorator. As the What's New says: "getting this right can be slightly brain-bending". Here's my decorator:

def prereqs(*args):
    def deco(func):
        func.prereqs = args
        return func
    return deco


Two notable Pythonisms at work here: firstly, the *args syntax means "list of all positional arguments". And secondly, the nested def defines a new function on each invocation of the containing function. This dynamic definition of functions is a common Python idiom.

Here's some functions with applied prerequisites:

def f1(): pass

@prereqs(f1)
def f2(): pass

@prereqs(f1)
def f3(): pass

@prereqs(f2, f3):
def f4(): pass


Step 2: sort these functions into a list ordered by prerequisites. This is in fact a topological sort of a directed acyclic graph, and the method for sorting a DAG is well-known: accumulate final vertices by locating them with successive depth-first searches.

def sort_prereqs(funcs):

    # Depth-first search, accumulating in result.
    def depth_first(func, result):
        if not func.visited:
            func.visited = True
            try:
                for prereq in func.prereqs:
                    depth_first(prereq, result)
                except AttributeError:
                    pass
            result.append(func)

    # Mark all vertices as unvisited.
    for func in funcs:
        func.visited = False

    # Perform depth-first search from all vertices.
    result = []
    for func in funcs:
        depth_first(func, result)

    return result


The try... except block handles the case where functions have no prerequisites listed, as is the case for f1 above. Here's the results of an application of this sort on an misordered list of the functions defined as examples above:

>>> sort_prereqs([f2, f4, f1, f3])
[<function f1 at 0x0115B9B0>, <function f2 at 0x0115B9F0>, <function f3 at 0x0115BA30>, <function f4 at 0x0115BA70>]


Mildly cool. I was lukewarm about decorators during the arguments: the @-syntax struck me as just so much syntactic sugar. But it really does make decorators easier to apply; and if they're easier to use, they're more likely to be added to a developer's personal toolbox.

Finally, a note: this has been a noddy example. But dealing with prerequisites is a problem I've faced in real production code. How to determine the initialisation order of modules, some of which are dependent on others? In the past I've used both hard-coded orders and dynamic ordering with explicitly-stated dependencies, as shown here. While the dynamic solution cost more initially, it caused a lot fewer maintenance problems in the long run.

Mount Diablo Waterfall Trail

Another hike with East Bay Casual Hiking; this one is a repeat of the Donner Canyon hike Melinda and I took last December.

There were 25 of us today, a big group to set out with, although we spread out a bit on the trail. And we sat and ate lunch on an outcrop overlooking the falls, which was very nice. Again, there's not a great deal of water in the falls; but there's enough that you can often hear the sound of running water. And unlike last time, there are many, many wildflowers out.

As we're sitting eating lunch, the Berkeley Hiking Club passes us; they seem an older bunch in general, kitted out in some serious gear. A bit too formal a group for me. I do like the comic touch in their March schedule though: "Shock the tourists in Muir Woods with our hiking gear/grim expressions."

The going is a bit tricky at times; it's dry today, but there are still a lot of descents which are stony or dusty and risk a fall. I wouldn't want to hike this one in the wet.

Next Sunday is the hike from hell: 20 miles to the summit of Mount Diablo and back. I'm not sure I'm ready for that, but I'm thinking of coming along to walk halfway and back.

Categories: Hiking

Thursday, March 10, 2005

Grāpple

Serendipity: I saw these in the supermarket yesterday and thought "how gimmicky"; apparently, so did Philip Torrone.

The macron on the a smacks of Heavy Metal Umlaut, but is phonetically correct: it means "pronounce long". But I'm not sure the Grāpple folks are terribly confident about it: they provide a pronunciation guide ("say Grape-L") right underneath the name.

And I rather enjoyed the hyperbole on their Making Grāpples page: "the process is complex". Oh yeah? Not terribly it's not: "Fiji apples are dipped into a combination of pure water and Concord grape flavouring".

Did I buy some? No. They cost $4 for 4; my 3 Granny Smiths cost me $1.34. And reading Steve Portigal's review, I'm glad I didn't.

But as it happens, I do have Concord grape juice in the fridge. Soaking Granny Smith slices in it does produce a vaguely grape-flavoured apple, as well as dying the apple flesh pink. I'm not sure, however, that this is altogether a good thing; on balance I'd prefer my apples to taste like apples.

Apple's Sudden Motion Sensor

File under "cool but not very useful": new PowerBooks have an embedded motion sensor which the firmware uses to park the drive heads after detecting sudden motion.

Amit Singh discovered how to read it, and wrote a couple of demo apps; Matt Webb promptly used it to control iTunes; and finally Guile, a commenter to AccordionGuy's weblog, suggested the Etch-A-Sketch move: turn the laptop over and shake it to reboot.

So, cool yes. But why not useful? Well: despite the name, most laptops are not used on the lap; too low, and often uncomfortably hot. Most of the time, they're sitting on a desk. Matt suggests a possible use of the sensor for mail reading: "tilt right to delete, left to keep, like you're driving through time through your mail inbox". But with a laptop on your desk, this would first require picking it up. Suddenly it's all more hassle than it's worth.

Maybe there's still potential, if the sensor's sensitive enough, to pick up on directional taps on the laptop's housing. But really, as Matt describes earlier, motion sensing is much more useful for truly handheld devices.

It did get me thinking though about new ways to control iTunes; more on this later.

Astound user webspace

Astound have nice fast cable internet, and supposedly I get 10MB/user of web space. I'll be darned though if I can find anything in their web pages, or in the printed Internet Get Going guide, which tells me how to use it.

But no worries; a bit of poking around with likely hostnames identifies the following:

FTP upload: ftp to users.ca.astound.net (or ftp.ca.astound.net; same IP address); login with your email username/password; put files in the public_html directory.

Web server: http://users.ca.astound.net/username. Their web server serves index.html or index.htm as the default page for a directory.

Minnesota Astound customers replace ca with mn as usual.

Oh, and while we're at it: they don't tell their customers about NNTP service either, but it exists. Newsserver at nntp.astound.net.

Wednesday, March 09, 2005

Shell Ridge 2: Sugarloaf Loop

Another day on my own company; another hike out from the apartment. I'm considering another stretch of the Iron Horse Trail — Walnut Creek to the Willows Shopping Center in Concord is about a 9 mile round trip — but it's a glorious sunny day and the hills are calling.

This time, I plot a circular hike through Shell Ridge Open Space and along the connector trail to Sugarloaf Open Space; returning by taking the Iron Horse Trail from Rudgear Road.

And it works out very well. The trails are empty today: I meet in total 3 other people. It's very hot on the hillsides, and I sweat like a horse. I keep telling myself it's good acclimatisation practice for summer — I prefer cool to hot, and I'm somewhat apprehensive of how I'll deal with midsummer California heat. There are lots of bluejays out today, and I see my first two lizards of the year basking on the hot ground of the trail.

I choose the Indian Creek Trail again, and it's a good choice: it's shaded and cooler alongside the creek, and there's more wildlife to see. The ground squirrels are out in force today, and it's hard to move more than 10 paces without hearing scurryings up ahead as they notice me and startle. At a bridge just after crossing Fossil Hill Trail, I find two fat warty toads huddling in the wet grass.

I continue on the Briones–Mt. Diablo Trail before cutting right on the Sugarloaf–Shell Ridge Trail. This trail can be frustrating; it doubles back on itself several times, so you often end up walking just across a valley from where you were minutes ago. A shorter route would to take the Joaquin Ranch Trail to the Whitecliff Way trailhead, and then the lower Twin Ponds Loop Trail to rejoin the Sugarloaf–Shell Ridge Trail at Bull Frog Pond — with the advantage that the Twin Ponds Loop Trail skirts Vierra Creek and is likely to be shaded.

Bull Frog Pond is fun; today it's covered with a red carpet of tiny 5mm-wide floating plants. Algae maybe? And there are frogs; I disturb a few basking at the edge of the pond as I approach, and I spot a number more watching me with just their bulging eyes visible above the water.

Immediately after the pond, a gate marks the edge of the Open Space and the beginning of Diablo Foothills Regional Park. The Sugarloaf–Shell Ridge Trail continues, unmarked, to the right just inside the gate. After 0.5 miles, turn right on Franco Ranch Loop Trail before turning left back onto the Sugarloaf–Shell Ridge Trail. The trail here is narrow and almost disappearing into long grass, and drops down into a valley. If I were doing it again, I'd probably stay on Franco Ranch Loop Trail, which runs along the ridge and has better views. There are lots of ground squirrels here too, and in the grass I can see that squirrels have trails too; a network of narrow tracks on the valley-side connects adjacent squirrel holes.

The trail leaves Shell Ridge Open Space here and heads through residential neighbourhoods to Sugarloaf Open Space. It's a pleasant interlude: for most of the distance, the trail runs along the backs of houses and is shaded by trees. At one point, I hear a whole choir of frogs croaking in Franco Creek.

Sugarloaf Open Space starts off well: good facilities at the trailhead. I decide I should take the opportunity to get up onto Sugarloaf Hill and plan to take the Ridge Top Trail to get there. And here the trouble starts: the trails here are unmarked. What I believe is Ridge Top Trail rapidly turns into a muddy cow-track before petering out altogether. I climb cross-country up the side of the ridge to find the trail. But here too, the trail has been heavily trafficed by cows making it uneven and uncomfortable to walk on. The views from the ridge are good, but it's just above highway 680 so there's a lot of freeway noise; I can see Bottom Hill Trail below me, which looks muddy and noisy. Oh well.

The map doesn't show a trailhead at the end of the Ridge Top Trail, but I decide to investigate anyway. A stile over the boundary fence encourages me; a mobile-phone antenna farm with chain-link fences discourages me; but the gates are unlocked so I go for it and eventually emerge onto Rudgear Drive. A roadside trek brings me down to Rudgear Road and the Iron Horse Trail home.

Total distance estimate just short of 10 miles, but a lot of it is flat; total time 4 hours. You could shorten it by about 2.5 miles by taking the Joaquin Ranch shortcut and by not faffing around in Sugarloaf.

Categories: Hiking

Virgin Radio podcasts

BBC reports: Virgin Radio starts daily podcasts.

The Virgin Radio podcast is an half-hour edit of its four-hour breakfast show with all the music, news, weather, traffic and travel cut out.

*splutter*

So, music radio... with all the music cut out? Just half an hour of Pete & Geoff's DJ blather? With adverts? I'll pass, thanks ever so much.

(What's podcasting? A cross between radio and blogging; but the cynic in me notes that it's simply a hip name for "downloadable audio".)

That said, Virgin do offer streaming audio in a multitude of formats and bitrates; I've never been able to get their iTunes 128kbps service to work (it always appears as crunchy 32kbps audio) but the RealOne 128kbps service works nicely, and the Real 10 AAC service sounds great.

Update: a "contact us" to Virgin about the iTunes streams gets the following potted response:

Virgin Radio is a UK radio station, aimed at radio listeners and advertisers in the UK. To ensure that UK listeners get the best service, at certain peak times, non-UK residents may automatically receive our 32k MP3 stream, instead of our 128k MP3 stream.

Y'buggers.

Tuesday, March 08, 2005

How-to: 2 users, 1 iTunes library

iTunes rocks. Those that use it already know this; for those that don't, at some point I'll talk more about why. (I have a vague mental shortlist of "things to write about soon" — compare and contrast to Raymond Chen, whose article queue for The Old New Thing stretches out at least six months...)

However, I do have one significant nit with the Windows version of iTunes (I know nothing about the Mac version, so assume everything's Windows-specific from now on): it's not particularly multi-user friendly. This is a problem for us, as we run Windows XP with multiple user accounts: one for me, one for Melinda, and one for guests. This lets us have our own My Documents folders, email identities, bookmarks, browser home pages, desktop wallpaper, and all that jazz. And we like Fast User Switching: we're often both logged in at the same time and switch users as we sit down to use the PC.

So what are the iTunes problems? Twofold. Firstly, iTunes will only run under one account at any one time. If user A has iTunes running, user B cannot start iTunes; the new instance detects the existing iTunes instance and refuses to start. This one isn't a big problem for us as it's easy enough to switch accounts and quit the unused iTunes.

But secondly, iTunes doesn't fully support sharing its music library between users. Apple's take on this is that you should share the music files between users, but that each user should then build their own iTunes library on those shared files (and any user-specific files the user cares to add).

That's one way to go, but it neglects the fact that in many ways the library metadata — artist, album, genre, year, rating, play counts etc — is the most important part of the library, is fundamentally useful in building playlists, and certainly the hardest part to construct. It's useful for us to share the metadata, as well as the raw music, between users.

Well, it can be done, but it's not easy. Here's the skinny:

Firstly, it's easiest to share the music data from a common location — we use C:\MP3 — and point each user's iTunes at that location. Make sure all users have the same setting for "Keep iTunes Music Folder Organised", so that one user's iTunes doesn't end up reorganising the library when other user's iTunes aren't expecting it. Personally I like the "keep organised" option.

Secondly, the thing to know is that, for each user, the iTunes library lives in the user's My Documents\My Music\iTunes folder. Specifically, the library lives in two files there: iTunes Music Library.xml, an XML file (using Apple's rather unfriendly plist schema) and iTunes 4 Music Library.itl, a binary file which seems to be the cached result of processing the XML file.

My first thought was to use Windows shortcuts to alias one user's iTunes folder, or iTunes Library files, onto the other user. No good. Windows shortcuts are a shell-level thing; most Windows programs, iTunes amongst them, are not shortcut-aware. (Because a shortcut is essentially just a file containing a pointer to the target file, they appear as regular files to Windows programs, unless they use the shell link APIs to resolve them.)

No, the solution is to go deeper. NTFS (on Win2K and up) has a little-known feature called "junction points". A junction point is a filesystem-level hard link, aliasing a directory entry in the filesystem to another tree in the filesystem.

Why little-known? Because they're dangerous. The shell doesn't distinguish junction points from regular files or directories, so you can get yourself confused fast — particularly as you can create recursive filesystems (where points low in the filesystem are junctioned to points higher up, so a traversal unaware of junction points can tend up traversing the filesystem forever).

But junction points are most dangerous because the hard link metaphor isn't carried through to the shell. Junction points are transparent to Explorer: the junction point appears as just another directory. Unfortunately, this means that when you delete a junction point in Explorer, you delete not only the junction point, but the target of the junction point. Not the same behaviour as you'd expect in a Unix shell, where deleting a hard link simply removes a reference from the target, and almost certainly not what you intended. (Doug Harrison complains about this behaviour in a comment on The Old New Thing.)

So, Microsoft keeps junction points firmly out of reach of home users: Windows XP Home contains no tools for creating junction points. Administrators can play with linkd if they buy the Win2K Resource Kit.

The rest of us can hack it with junction, a free tool from SysInternals. Junction lets you create and inspect junction points.

So: pick a location for the shared iTunes library. I put ours in C:\Documents and Settings\All Users\Documents\My Music\, copying the iTunes folder there from the most up-to-date user's My Music folder.

Then, for each user, delete their iTunes folder, and create a junction to the shared iTunes folder:

junction "C:\Documents and Settings\User A\My Documents\My Music\iTunes" "C:\Documents and Settings\All Users\Documents\My Music\iTunes"

Bingo: because the junction points are at the filesystem level, iTunes reads right through them. Many users, one shared library.

Sunday, March 06, 2005

Lime Ridge Open Space

Another hike with Easy Bay Casual Hiking, and another hike in the Walnut Creek Open Space; this time on Lime Ridge.

It's a hot Sunday morning and about 25 people have turned up; a lot of new members, many due to a recent craigslist posting, and very few who I recognise from last time. A mixture of abilities; a few drop out at the first sight of mud on the way up, the majority are reasonably fit and fast, and a handful bring up the rear. We take frequent breaks to regroup.

It's 4.3 miles, considered "moderate", which feels about right: it's almost all hilly. From the start point at Arbolado Park, at 250 feet elevation, we climb 300 feet on the Ohlone Trail; turn right on the Paraiso Trail, gaining another 300 feet; turn left on the Crystyl Ranch Trail, dropping some 200 feet before regaining 100 feet; turn left on the Manzanita Trail, gaining another 200 feet to our highest elevation at ~950 feet. It's all downhill from here as we drop down to the corner of Boundary Oak Golf Course. We overshoot slightly and have to scramble over a locked gate into the golf course grounds; but nobody seems to mind. We walk through the golf course, passing the driving range which, from a distance, seems to be carpeted with white flowers — golf balls, of course.

In total, about 2 and a half hours; long enough for me to catch quite a tan on the face and neck I forgot to apply suntan lotion to, but fortunately not long enough to burn. I'm going to have to be a lot more careful about sunblock over here.

And again, you really need the Open Space trail map to do Lime Ridge; most of the junctions here are unmarked. This is annoying, especially as copies of the map seem to be in short supply; I've yet to see a trailhead which has any. Best off printing the PDF from the Open Space website.

Categories: Hiking

Saturday, March 05, 2005

Three Milky Musketeers

So we're watching TV and an advert for Three Musketeers — one of the many US-specific candy bar brands — comes on. We get to the clichéd cross-sectional view, and:

"Hang on — that's a Milky Way!"

"No it's not, Milky Ways have caramel."

"They do not! Mars Bars have caramel. Milky Way is just fluffy nougat. Eat it between meals without spoiling your appetite, and all that stuff."

Well, it turns out we're both right. Wikipedia spells it out:

UK Milky Way = US Three Musketeers
UK Mars Bar = US Milky Way

And stranger yet, there was a US Mars Bar, now called the Snickers Almond Bar (US) or Mars Almond Bar (UK).

In other chocolate news: the renaming, 15 years ago, of the UK's Marathon bar ("packed with peanuts, Marathon really satisfies") to the Snickers brand prevalent in the US and elsewhere still rankles. So, odd then to see the Marathon name resurface, attached to the really rather crappy Snickers Marathon energy bar.

All that said though, the US does have the best junk-food chocolate ever: the Reese's Peanut Butter Cup.

Iron Horse Trail 2: Trail Harder

Last time we walked on the Iron Horse Trail, we did the 6-mile round trip from Danville to Alamo and back.

Today we tried it the other way: from our front door in Walnut Creek to Alamo and back again. About 4.2 miles each way. I enjoyed it, but the extra 2 miles was enough to do for Melinda.

And to be honest, the stretch in Walnut Creek, from downtown along South Broadway to the Rudgear Road staging area, isn't really worth it. It runs alongside some major roads before crossing under highway 680; a little too noisy and urban for my taste. After Rudgear Road, the trail pulls away from the road a bit and gets quieter, although it takes a mile or so to get far enough from 680 to lose the freeway noise.

The trail is wide here, too wide to get much if any shade; it was hot walking today and in summer would probably be unbearable. And it's well-used; many, many cyclists out today, including a few diehard recumbent bikers sporting aerodynamic plastic covers, and quite a few rollerbladers.

There are a few odd sights: all along the trail, water fountains for both people and dogs (a separate push-button faucet fills a built-in water-bowl). Near Hillgrade Avenue, stabled horses look out onto the trail, with a sign warning agaist feeding them the plants growing nearby ("carrots only!"). Near Livorna Road, a bay window built into a backyard fence, presumably to give a curious dog a view onto the trail. Near Ridgewood Road, a backyard tableau of full-size plastic farmyard animals, complete with farmer.

Lunch is a deli sandwich at Safeway (always very good) followed by cheap icecream at Rite Aid (ditto; scoops always seem generous at this Rite Aid) before the long trek back.

Categories: Hiking

Thursday, March 03, 2005

Redwood Regional Park

Another bahiker walk yesterday, in Redwood Regional Park — one of the string of parks in the Berkeley hills which include Wildcat, Tilden, Sibley, and Huckleberry.

Redwood is at the same time a sad story of destruction and one of regeneration. There are few redwoods in the East Bay now, but the forest here used to be immense. Some of the trees so large that ships entering the bay, 16 miles away, used them to navigate by. The park booklet quotes a Royal Navy log: "...in order to miss treacherous Blossom Rock between Alcatraz Island and San Francisco, one should line the northern tip of Yerba Buena Island with two trees south of Palos Colorados, over San Antonio, too conspicuous to be missed."

The forest was logged clean in the 1840s–1860s, leaving a sea of stumps. Malcolm Margolin, in The East Bay Out, claims that one stump measured 33 feet in diameter, larger than any redwood alive today. The stumps themselves were chopped up for firewood in the following decades; and any trees which had regrown were logged again to help rebuild San Francisco after the 1906 earthquake. The land was used for farming and ranching before, in 1939, becoming dedicated as the fourth EBRPD regional park.

But still: the redwoods regrew. The trees here are young (by redwood standards, at least) but still majestic. There's evidence of earlier abuse in the patterns of growth: it's very common to see redwoods growing in circles, around where the trunks of their ancestors once stood.

The bahiker walk follows the West Ridge Trail from the Skyline Gate trailhead (free parking here) before descending into the redwoods on the Tres Sendas trail. This section of the hike is beautiful: it's quiet in the forest, the redwoods are tall, straining towards the sun, and after the rains the creek running alongside the trail is full. We continue on the Stream Trail; wider and more developed, with a fence alongside the creek protecting the native rainbow trout habitat.

And then a pull up Prince Road to the East Ridge Trail and back to the car park; the trail is nice enough, but after the beauty of the redwoods feels a little like "just another California hillside trail".

We both really enjoyed this hike, but really wanted more of it to be in the forest and less of it on the hillsides; next time we might extend it by taking the French Trail from Tres Sendas deeper into the forest and by returning all the way on the Stream Trail.

Categories: Hiking

Wednesday, March 02, 2005

Jane Huber

Went to REI — a rather upscale outdoors/adventure store — last night to hear Jane Huber speak on her favourite spring hikes. Jane Huber is bahiker.com, the website from which we've drawn ideas, and often routes, for many hikes.

Unfortunately, finding the store was a bit of an adventure in itself; it was pouring with rain, which always seems to make for much more difficult driving here than it did in the UK. (Roads here get very shiny when they're wet, making it hard to distinguish lane markings; and city driving here is all about being in the right lane at the right time.) For future reference: REI is at the back of the Willows and isn't visible from the road.

Anyway, we arrive some 5 or 10 minutes late and the slideshow and talk is already under way; we slip in quietly and sheepishly at the back. She's not at all how I imagined her in person: I'd envisioned some lanky super-fit hiking freak, while in fact she's rather more short, squat, and easy-going.

The talk is a little too much of a breakneck tour for me; she's chosen some 35 hikes from all around the Bay Area, which means that none of them gets very much time. I'd rather have heard more detail on fewer hikes. But there are lots of ideas here. A number of hikes on Mount Tamalpais, which everyone is telling me I should visit; a number at Point Reyes; lots of county parks in San Mateo; and a big recommendation (and a wonderful picture, which I've been unable to find on her site) for Big Basin Redwoods.

And speaking of photos: they're much more effective projected than they are in thumbnail or mid-size form on her website. I'm beginning to lust after a digital camera rather than an iPod...

Heating? What heating?

Our apartment here has one heater, a wall-mounted gas unit roughly in the middle of the open-plan area. We haven't needed to use the heater at all; the weather is mild here (unlike currently-freezing Britain) and, as we're on the top floor, we get quite a lot of heat from the apartments below. (In particular, one of our closets is always pleasantly warm; I suspect it's above the heater in the apartment below.) We do also get a little residual heat from the pilot light on the heater, which does burn rather high.

So, our first monthly PG&E bill is in: and running that pilot light has cost us nearly $8. This seems a bit steep. So, today we turned the heater off altogether: we're now entirely passively heated.

I'm also finding that being billed monthly makes me more energy-conscious: I'm less cavalier about leaving lights on now I know I'll be paying for it next month. So, with that in mind, here's a bit of rough-and-ready JavaScript to calculate the average cost of leaving a light on:
W for hours/day at ¢/kWh $ month

(FWIW, kitchen lights 240W; living-room light 200W; vanity lights 120W; bathroom lights 75W; TV ~130W; PC ~150W; refrigerator peak ~750W, average maybe ~150W, depends on duty cycle.)