Archive for December, 2007

Free stuff on Amazon: Now four at a time

Friday, December 28th, 2007

This week, rather than having one free song listed on the front page of the Amazon MP3 Store, they have four free songs listed on their Special Deals page.

Interesting how two of the songs (“100 Days, 100 Nights” and “Holiday Twist”) both sound like they're from the 1960s, but they're actually brand-new from this year. Also interesting how Los Straitjackets (“Holiday Twist”) have now had a free song on both iTunes (“Sleigh Ride”) and Amazon.

(And yes, I know that iTunes link doesn't work. I don't know why; it turns up in the search results.)

Google sure is fast nowadays

Wednesday, December 26th, 2007

I created a page on the Adium wiki at 07:07 PST, and Google had it indexed by 08:01. This screenshot is of a search for “darcs patch bundle binary”.

The times shown in the screenshot are in EST; I created the page at 07:07 PST, and found it among those search results at 08:00 PST.

Dammit, Panda Express!

Sunday, December 23rd, 2007

They have adulterated my beloved Fried Rice.

Panda Express Fried Rice used to contain five things:

  • Rice (duh)
  • Bits of fried egg
  • Carrots, diced
  • Peas
  • Chopped celery (unthrilling, but tolerable)

Today, I bought some fried rice, and look what they've added:

  • Chopped red peppers
  • An orange unidentifiable fruit/vegetable chunk; either of another pepper of some kind, or of an underripe tomato
  • Exactly one slice of carrot (crinkle-cut), in addition to the diced carrots [Edit: When I went back to it to finish off the second half of it, I found another slice.]
  • Fucking broccoli

Don't mess with my rice!

I can only hope that this was simply the result of having some spare parts that they needed to use up, and that another batch of fried rice (or another Panda Express) would not provide such contamination.

UPDATE 2008-01-06: I had lunch at the Costa Mesa store today, and they did not befoul my fried rice in this way. Good to know.

Free stuff on Amazon: Bonus free download

Sunday, December 16th, 2007

If you went to the Amazon MP3 Store on Wednesday and are like me, you stopped scrolling at the free download.

Keep scrolling—I did (just today), and found that there's a second free download this week. Here's the direct download link. Be aware that it's a rap song with some naughty words in it.

The iPhone flashlight

Thursday, December 13th, 2007

If you should have an urgent need for a flashlight, but have only an iPhone or an iPod touch with you, fear not. Now you have an iPhone flashlight.

More Darcs win: Selective recording

Wednesday, December 12th, 2007

Darcs lets you choose which changes you want to include in a patch (commit). For example:

darcs rec                                                   %~/ASL test apps/aslsearch(0)
move ./aslsearch.m ./aslsearch.c
Shall I record this change? (1/?)  [ynWsfqadjkc], or ? for help: y
hunk ./aslsearch.c 1
-#import <Foundation/Foundation.h>
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <vis.h>
-#include <asl.h>
-
Shall I record this change? (2/?)  [ynWsfqadjkc], or ? for help: n
hunk ./aslsearch.c 29
-       NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-
Shall I record this change? (3/?)  [ynWsfqadjkc], or ? for help: y
hunk ./aslsearch.c 75
-       [pool release];
Shall I record this change? (4/?)  [ynWsfqadjkc], or ? for help: y
hunk ./aslsearch.c 194
+       fprintf(stderr, "key: \e2\80\9c%s\e2\80\9d\noperator: 0x%x\nvalue: \e2\80\9c%s\e2\80\9d\n", key, operator, value);
Shall I record this change? (5/?)  [ynWsfqadjkc], or ? for help: n
hunk ./aslsearch.xcodeproj/project.pbxproj 10
-               8DD76F9A0486AA7600D96B5E /* aslsearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* aslsearch.m */; settings = {ATTRIBUTES = (); }; };
+               8DD76F9A0486AA7600D96B5E /* aslsearch.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* aslsearch.c */; settings = {ATTRIBUTES = (); }; };
Shall I record this change? (6/?)  [ynWsfqadjkc], or ? for help: ?
How to use record...
y: record this patch
n: don't record it
w: wait and decide later, defaulting to no

s: don't record the rest of the changes to this file
f: record the rest of the changes to this file

d: record selected patches, skipping all the remaining patches
a: record all the remaining patches
q: cancel record

j: skip to next patch
k: back up to previous patch
c: calculate number of patches
h or ?: show this help

<Space>: accept the current default (which is capitalized)
hunk ./aslsearch.xcodeproj/project.pbxproj 10
-               8DD76F9A0486AA7600D96B5E /* aslsearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* aslsearch.m */; settings = {ATTRIBUTES = (); }; };
+               8DD76F9A0486AA7600D96B5E /* aslsearch.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* aslsearch.c */; settings = {ATTRIBUTES = (); }; };
Shall I record this change? (6/?)  [ynWsfqadjkc], or ? for help: f
hunk ./aslsearch_Prefix.pch 5
-#ifdef __OBJC__
-#      import <Foundation/Foundation.h>
-#endif
-
Shall I record this change? (10/?)  [ynWsfqadjkc], or ? for help: y
hunk ./aslsearch_Prefix.pch 8
+#include <unistd.h>
Shall I record this change? (11/?)  [ynWsfqadjkc], or ? for help: n
What is the patch name? Switched source file from Obj-C to pure C
Do you want to add a long comment? [yn]n
Finished recording patch 'Switched source file from Obj-C to pure C'

(Before you mention the UTF-8 sequences that Darcs called out as invalid ASCII: Yes, I know.)

And an answer: What to do if your table view shows the whole array in every row

Sunday, December 9th, 2007

Before writing my previous post, I had asked some people on IRC for help, including David Smith, who is a fellow Adium developer. He remembered a solution, but uncertainly. One thing he said, though, proved relevant: “You have two NSTableColumns; which one is it [NSTableView] creating the content binding from?”

David was referring to the content binding of NSTableView, which I had dismissed as an artifact of an earlier design of NSTableView, or perhaps a simplified path for those people who had only one column in their table view. (I saw the mention in the docs that the table view binds it automatically to the value of one of its columns' value bindings, but didn't make any connections then.)

This latter explanation made the content binding incompatible with my app, since I had two parallel arrays of NSStrings (one array contained keys, and the other contained values). So I continued looking for a solution, and eventually gave up and wrote the post.

After I published it, Scott Anguish posted a comment on it:*

you can't have simple arrays of strings as the content of an array controller. it doesn't work. You need to have an array of objects of some sort that have an attribute, even if they're just NSDictionaries with a single attribute called "string".

I don't believe that NSArrayController has a special case for NSString, but Scott's comment got me thinking. I added a category to NSString that added a -selfString method, then added that name as the model key path in the table columns' value bindings. I was wondering, you see, whether this would be enough to satisfy NSTableColumn and NSArrayController.

It still didn't work. At this point, I had the idea to fire up F-Script Anywhere and have a look around. I did that, and was digging down to the table columns when I noticed this:

That's FSA's object browser, showing the table view. So the table view's content binding was bound to the keys array controller, with a model key path of lastMessageKeys.

That's why the keys were showing up fine—they were in the array that was in the table view's content binding. The values array was a different array with a different array controller, so NSTableView threw up its hands and simply showed the entire array's description.

This is the point that Scott came close to: NSTableView expects you to have one array of model objects—no more. My parallel arrays of NSStrings do not qualify, because only one of the array controllers can be the value of the table view's content binding.

So what role do the columns play? Well, each row in the table view (and by that, I mean *the whole row*) corresponds to one of those model objects. The value in each column is then determined by the model key path in the value binding of the corresponding NSTableColumn.

Thus, all the NSTableColumns' value bindings must be bound to the same array controller and the same controller key, and each column should be bound to a different model key path. Your columns' value bindings should look like this:

Column “Foo”Column “Bar”
Bind to: Your one array controller
Controller key: arrangedObjects (or whatever)
Model key path: fooModel key path: bar

In my case, of course, this required creating a new model class for a key-value pair, to replace the parallel arrays of NSStrings. This is a good thing, since it brings conceptual purity to my design. Remember, Cocoa is designed around MVC; I didn't have enough M in my app, which was the problem.

So, in summary, here's the fix for an NSTableColumn that shows the entire array in every row:

  1. Replace your evil parallel arrays with a model class, and a single array of instances of that class.
  2. Delete all but one of your array controllers, since you now have only one array. Update the remaining controller's model key path to point to your new array (I assume you renamed it).
  3. Bind all of the table columns to your new One True Array Controller, distinguishing the columns only by the model key path, which identifies which property you want the column to show for each model object.

Many thanks to both David and Scott for their help in discovering the root of the problem.

* Scott posted his comment on the previous post with no last name; he identified himself in a comment on this post.

I have a question

Saturday, December 8th, 2007

See also the follow-up: And an answer: What to do if your table view shows the whole array in every row.

Normally, on this blag, I give answers.

This time, I have a question.

Here's my problem:

I have a window containing a table view. The table view has two columns, labeled “Keys” and “Values”.

Each column's value binding is bound to an NSArrayController; each array controller's contentArray binding is bound to a property of my application delegate; each property's value is an NSArray of NSStrings.

The Keys column correctly has one of its strings in each row. The Values column incorrectly has its array in every row. This is the problem that has stumped me.

The object class is NSString in both array controllers. There's no Core Data in this app.

I have 12-tuple-checked the bindings in IB; they are the same between the two array controllers and between the two table columns.

The accessors are automatically generated by my accessor-generator services. Even so (having added some debug logging previously), I double-checked them, and they are the same.

I have logged the contents of both arrays in my setters. Both arrays are arrays of strings, and both contain the same number of strings.

This problem manifests on both Tiger and Leopard.

Here are screenshots of my Bindings Inspectors:

The array controllers' contentArray bindings are bound to the app delegate's lastMessageKeys and lastMessageValues properties. There is no value transformer in use. The options that are turned on are Conditionally Sets Editable and Raises For Not Applicable Keys; the options that are turned off are Always Presents Application Modal Alerts, Deletes Objects On Remove, Handles Content As Compound Value, Selects All When Setting Content, and Validates Immediately.

The table columns' value bindings are bound to the array controllers' arrangedObjects properties. There is no value transformer in use. The options that are turned on are Allows Editing Multiple Values Selection, Conditionally Sets Editable, Creates Sort Descriptor, and Raises For Not Applicable Keys; the options that are turned off are Always Presents Application Modal Alerts, Conditionally Sets Enabled, Continuously Updates Value, and Validates Immediately.

Each screenshot has two Inspectors superimposed on each other, with the upper Inspector set to half opacity; the result is that pixels that are the same look normal, whereas pixels that differ look ghostly. For your ease of reading, I knocked out the parts that differ and staggered them, so you don't have to try to make out ghostly text.

Any suggestions?

A possible solution to the stolen-focus problem

Wednesday, December 5th, 2007

Jeff Atwood posted an article today titled Please Don't Steal My Focus, about dialog boxes coming up while you're typing.

The problem, in a nutshell, is that these dialog boxes steal keyboard focus. Sometimes it's for a text field; sometimes it's just for Full Keyboard Access (i.e., a button gets the focus—usually, these are alert boxes). Regardless of what control gets keyboard focus, it gets it by stealing it from your app, which is a problem if the user is typing when that happens. Most likely, either some text will go to the wrong place, or the dialog box will beep for every keystroke; either result will annoy the user.

We've had the same problem for a long time in Adium: we'll throw up a dialog box, but the user is typing a message, and notices that half his message isn't in the inputline. We believe we've fixed most of these, but we still get complaints about this problem from time to time.

Currently, we solve the problem by simply ordering the dialog front without making it key. This works for most people, but it doesn't help people who really do need Full Keyboard Access, since you have to click on the dialog box to dismiss it (or make it key) if it isn't key. We (by which I mean Mac programmers, not just Adium) need a better solution.

I propose an addition to NSAlert. Here's how it would work:

  1. From the creation of the NSAlert instance, it watches for key events.
  2. When any key goes down, the alert resets the timer (if one is present) and sets a flag.
  3. When all keys are up, the alert creates and starts the timer (with an interval of, say, a couple of seconds).
  4. If you tell the alert to show, it checks the flag. If the flag is clear, it simply performs makeKeyAndOrderFront: like usual. If the flag is set, it only orders front, and it sets a second flag.
  5. When the timer fires, the alert clears the first flag, and if the second flag is set, makes itself key.

From the user's perspective, this results in the alert waiting a couple of seconds for them to pause in their typing before it takes keyboard focus.

Does anybody know of an existing free implementation of this, or plan to write it themselves?

Blog spam count: 2007-10

Tuesday, December 4th, 2007

Spam comments blocked by Negative Turing Test in October 2007 (and November 1–3):

20,221

Blast from the past

Monday, December 3rd, 2007

The NeXT keyboard had volume and brightness keys.

This casts Apple's recent keyboards in a whole new light for me.

(Image courtesy of Patrick Gibson. I cropped and spotlit it using Acorn.)

I originally saw this keyboard on Wikipedia, but Patrick was nice enough to take a better photo—thanks!

I think somebody mixed up their phishing emails

Sunday, December 2nd, 2007

From: Bank Of America Security Dept. Subject: IMPORTANT: Security Issues [Incident: 0409252]. Body: You have just received a virtual postcard from a family member!
What is this, scamming for victims with ADD?

From svn to darcs: Listing unknown files

Sunday, December 2nd, 2007

If you're an svn user looking at darcs, you may wonder how to find unknown files—that is, files that you've created in your working directory, but haven't yet told your VCS about (with svn add or darcs add). In svn, the command is svn st, but in darcs, the procedure is not obvious.

The darcs command that most seems like what you need is darcs whatsnew, or, as I type it, simply darcs what. Like svn st, this shows you all files that have been added, removed, or modified; it also includes a diff, so not only is it your substitute for svn st, it's also your substitute for svn diff. But it doesn't show you unknown files.

Until you use the -l (that's a lowercase L) option.

darcs what -l changes the output greatly, as it's in a completely different format: one similar to that of svn st. The format is actually that of darcs what -s (summary mode); the difference is that -l also lists unknown files.

There are some differences between darcs what -l and svn st. Some of these differences are:

  • darcs uses fewer columns than svn: It has one status column, whereas svn has six.
  • darcs uses ‘a’ to indicate an unknown file, whereas svn uses ‘?’.
  • darcs uses ‘R’ to indicate a file that you've removed, whereas svn uses ‘D’ to indicate a file that you've deleted. (svn supports remove and rm as synonyms for its delete command, but darcs does not support delete nor rm as synonyms for its remove command.)