How I tweaked that HTML table

My last post contains an HTML table that is a modified version of the big table on the "Closing the Gap on Autism" page. Here, mainly for my own future reference, is how I generated the modified table. There are probably ways I could have done it smarter or quicker.

  • Generate a sorted CSV file
    • Select the table contents in Safari and copy-paste them to a Numbers spreadsheet.
    • Sort on state, city, and ZIP, in that order. I was thrown off by the fact that Numbers doesn't have a menu item with the word "Sort" in it. I learned from the Help documentation that what I wanted was "Reorganize".
    • Format the ZIP column to be five digits, padded on the left with zeros. Otherwise the leading zeros will be omitted when the file is exported.
    • Export to a CSV file.
    • Pipe the CSV file through uniq to remove duplicate entries.
  • Convert the CSV to an HTML table
    • This CSV Converter page does the job nicely. I noticed Excel has an option to export directly to HTML, which would have been a nice shortcut except what it generates is horrifying.
  • Clean up the HTML
    • Paste the HTML into Sublime Text.
    • Get rid of the spaces that the CSV Converter inserted before many of the closing ">" characters. This wasn't important; I just didn't like looking at the extra spaces.
    • Replace tabs with spaces. I couldn't get find-and-replace to work with tabs, and was too lazy to try harder than I did.
    • Use regex plus global find-and-replace to convert the store numbers into links to the Gap web site. Because there were sometimes two store numbers, I used two find-and-replace passes to generate the store links. I manually cleaned up one case where three store numbers were given.
    • Use another regex find-and-replace to fix phone numbers with spaces in them.
    • Use another find-and-replace to remove the extra spaces from "St ." and "Ave .".
    • Replace "&" with an ampersand.

There are a whole bunch more punctuation fixes I could have made, but I decided not to bother. I allowed myself to fix one typo, and corrected "Loehmen"s" to "Loehman's".

I added a bit of CSS before posting to WordPress. You can tell I'm not a CSS expert — mainly I wanted to draw the borders.

Closing the Gap on Autism

This weekend, Autism Speaks and The Gap are partnering in a charity discount event called Closing the Gap on Autism. Here's an excerpt from the email I got about this; it explains the event more clearly than the copy on the web site:

This weekend, Friday, September 28 – Sunday, September 30 donate $5 to Autism Speaks at participating Gap stores and receive a special 25% off discount on all regular priced items on Gap, GapBody, GapKids, babygap & Gap Maternity merchandise.

It’s so simple: buy your special $5 coupon in-store and you get $25% off your entire purchase. If you spend $20, it pays for itself!

The coupon is only available in-stores.

The web site shows a list of participating stores, but it seems to be sorted only by state and not city. As a result, the New York, NY stores (for example) are not all grouped together.

Here is that same list, sorted by city and state, and with links to the individual stores' web pages so it's easy to check on their hours and find them on a map. Note that for some reason some of the stores have two store numbers listed, only one of which is valid. In these cases, one of the store links won't work but the other should.

[Update: I've now sorted the list by ZIP as well as city and state, so, for example, all the 10011's are together.]

[Update: I've also removed duplicate lines. This is clearly an obsessive thing for me — I'd be surprised my improved list of stores actually makes a difference for anybody.]

If you spot an error, please let me know.

[Update: I've moved the list of stores to its own page.]

Don't break Emacs

One of my favorite Mac OS features is support for basic Emacs keystrokes for editing and navigation. If you're unfamiliar with this feature, start editing some text in a Cocoa app like TextEdit or Mail, and try ^A, ^B, ^D, ^E, ^F, ^K, and ^T, to name just a few. This functionality is built into standard Cocoa text controls like NSTextField and NSTextView.

Occasionally I come across a web site that intercepts keystrokes that would normally be Emacs keystrokes. For example, a site might implement a rich text editor and use ^B to mean "bold", which is a familiar shortcut for Windows users, but means "move one character backward" to Emacs users. I wish these web sites would detect the platform they're running on and use familiar Mac shortcuts — in this case, Command-B — which would have the double benefit of being naturally discoverable for Mac users and not overloading an Emacs keystroke.

Native apps can "break Emacs" too. I just reported a bug in Sublime Text where ^K (kill to end-of-paragraph) doesn't work in the text field in its Save dialog. I suspect this is because, for some reason, Sublime Text explicitly maps ^K to an item in the Edit menu instead of falling back on the default Cocoa behavior.

In July I filed Radar 11964801 on iTunes because ^D (forward delete) doesn't work in the Search field — a bizarre edge case if I ever saw one. ^D isn't mapped to any menu item in iTunes, nor is it documented as a keyboard shortcut for either Mac or Windows. I really wonder what causes this bug. My Radar was marked as a duplicate of 11306235, so there's at least one other picky nerd out there.

Here's how picky I am. Suppose there was a magical "Mac OS, PC Edition" that could run on any cheap PC hardware. Suppose for some perverse reason the "PC Edition" lacked the Emacs feature but was identical to Mac OS in all other respects. I wouldn't even consider it. I'd still pay more for Apple hardware, although I would certainly consider recommending the "PC Edition" for less nerdy friends and relatives.

And so, while I realize these Emacs breakages are trivial-beyond-trivial in the grand scheme of things, I'd still like to register this tiny plea to developers targeting the Mac: please don't break Emacs.

OMQuickHelp plug-in

OMQuickHelp is really cool:

This plugin allows you to use Dash instead of Xcode's own documentation viewer when using option-click (or the equivalent keyboard shortcut) to view the documentation for the selected symbol.

This is much more convenient than the "method-aware" service I provide in AppKiDo. You don't have to select any text — just Option-click anywhere on the symbol you want to look up. To install the plug-in, just build the project and restart Xcode.

If you want the search to be done in AppKiDo instead of Dash, find these lines in OMQuickHelpPlugin.m:

BOOL opened = [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"dash://%@", searchString]]];
if (!opened) {
    return NO;
}

Replace the lines above with these lines:

NSPasteboard *pboard = [NSPasteboard pasteboardWithUniqueName];
 
[pboard declareTypes:@[NSPasteboardTypeString] owner:nil];
[pboard setString:searchString forType:NSPasteboardTypeString];
 
if (!NSPerformService(@"Look Up in AppKiDo", pboard)) {
    return NO;
}

Again, build the plug-in and restart Xcode. Replace "AppKiDo" with "AppKiDo-for-iPhone" if that's your pleasure.

Note that searching with Dash or AppKiDo is not exactly like Xcode's default Option-click behavior. Normally, Xcode shows you the documentation for whatever the compiler thinks the symbol you selected is. This is unambiguous; there is at most one relevant documentation entry. For example, if you Option-click "view" in the following code, you'll see the docs for NSViewController's view method.

// Yes, this is absurd. It's just for purposes of discussion.
[[NSViewController new] view];

Dash and AppKiDo are different in that they do purely substring-based searches, using no semantic information. Searching for "view" in either app will return a whole bunch of results containing "view". You will have to pick through the search results to find the one you want.

It may be worth occasionally picking through multiple search results if this means you can use your preferred search tool. It may even be useful to see the other search results, which may include related symbols you weren't aware of. And you can always use Xcode's Quick Help inspector (Option-Command-2) to see the same documentation that Option-click would normally have shown before you installed OMQuickHelp.

[Edited.]

Disparate types for the same value

I noticed that the "contents" property of SCNMaterialProperty can be any of fivesix things:

  • NSColor
  • NSImage
  • CALayer
  • CGColorRef
  • CGImageRef
  • [Update: Michael Tsai points out that it can also be an NSArray of six images.]

The three classes — NSColor, NSImage, and CALayer — are about as unrelated as you can get within the Cocoa class hierarchy. Their only common ancestor is NSObject. It's true they all implement NSCoding, and two of them implement NSCopying, but these are such common, generic protocols they hardly count as relating the three classes in a meaningful way.

The two CG pointer types — CGColorRef and CGImageRef — are not toll-free bridged to any of the classes, although they are C-based counterparts to NSColor and NSImage.

I wonder if this property sets a record for the greatest number of disparate, specific types a value is allowed to have in Cocoa. I'm talking about formal Objective-C types, disregarding semantics. Offhand I can't think of an example with more than two.

For example, CALayer itself has a "contents" property which can be either a CGImageRef or, as of Mac OS 10.6, an NSImage. Another example is buttons and cells, which at least unofficially allow NSAttributedString for their titles even though the API specifies NSString. (I don't know if this is officially documented.) Bear in mind that NSString and NSAttributedString are not related by inheritance.

Note that in all the examples above, there is only one conceptual "type" for the value in question, whether it's "graphical contents of a rectangle" or simply "a string".