Wednesday, November 24, 2010

Tenneseans, I hope there's no disaster, but if there is, you're welcome.

 In 2005, there was a hurricane which forever changed New Orleans. But not only that, it woke up many people who were in the business of ensuring that poor people affected by those disasters had access to funds and services to which they were due by their government, their employers, et cetera. My wife was one of those people. As far as I can cobble together, disaster legal services was a much more organized and effective years before that, and it went in to a bit of a decline. Until we met Katrina.

So my wife, a former disaster legal aid attorney, asked if there was a way I could help coordinate communication between different groups. "Something like a listserv." I still find it adorable that she calls it a listserv. So I set up a mailing list so people around the country could share information. Nothing much, really, but it helped get people together.

I have come to find out that the Memphis Bar association has a nice condensed disaster relief legal assistance reference guide for volunteer attorneys. Stuff like this:
Q. 7 I received my check for rental assistance, but there are no places to rent. 

If you are eligible for housing assistance from FEMA but are unable to find a rental house or apartment within a reasonable commuting distance of your damaged home, please contact FEMA at 1-800-621-FEMA (3362) or visit a nearby Disasater Recovery Center. FEMA will evaluate your situation, and, if appropriate, may authorize a travel trailer or mobile home.
Going back to the title page it says:
With special thanks to the following contributors:

...
Robert Konigsberg
I didn't do much, but it's nice that it helped.

Thursday, November 11, 2010

Replacing my Mac Keyboard with a Logitech Internet Navigator

(Second in my Luddite Internet Technology Series)

The Caps Lock key on my Mac keyboard was not responding so I pulled out the first keyboard I could find lying around: the Logitech Internet Navigator keyboard. You know the type: the one with buttons labeled "Search", "Shopping", "Favorites". It probably came with a machine I bought long back when. But you know what? I love it.

It has some nice features I came to expect from my Mac keyboard: volume controls, and media play/rewind/pause buttons. All those work as you would expect. There's also a little scroll wheel on the keyboard which I don't really need since I have a scroll wheel on my mouse. Even the "Sleep" button brings up the sleep dialog box. The only thing missing is a replacement for the eject button. (Update: downloading the Logitech Control Center for OSX did the trick. Now the only thing missing is a USB port.)

The only change I had to make for it to work well with OSX was to swap the behavior of the Command and Option keys (Pressing Command was sending Option and vice versa.) So thankfully the OSX keyboard settings allow me to reprogram the function of those keys, so I implemented a modifier swap. (Update: Once I installed the Logitech Control Center, the keys were swapped once more, Restoring original behavior of keyboard modifiers did the trick, effectively making this paragraph "Remember to install the Logitech Control Center and do nothing else."

As for general keyboard behavior, the keys have a nice tactile feel, you don't feel like you're constantly hitting the bottom of the keyboard tray as you do when using the Mac keyboard. It comes with a keypad on the right side, which I've come to expect with all my keyboards. The keys are slightly more smooshed together. But hey, nothing is going to do it for me quite like my IBM Model M. I just wish in this case that for "IBM Model M" the M stood for "Macintosh."

In retrospect, the keyboard and mouse that came with my Mac Pro were probably the first two such peripherals that I have ever thrown out due to mechanical defect. Oh, and their earbuds. And on the other side of that is Logitech: with the exception of one piece of hardware, I've never been disappointed with their products, and as of today I'm no longer disappointed with that one exception.

It's nice to be able to bring a 2002 peripheral with so many silly buttons to just work naturally with a modern OS. Back in 2002, all those buttons were pie in the sky. Today they're launching my apps.

Sunday, November 07, 2010

Making a Table of Contents for Sites with Google Apps Script

At work I was building a document using Google Sites. While building them, the section headings were given their own numbers, like so:

Introduction
Part 1: Apples
  Introduction
  1.1: Fuji
  1.2: Macintosh
  1.3: Cameo
  Summary
Part 2: Pears
  Introduction
  2.1: Bosc
  2.2:D'Anjou
  2.3:Warden
  Summary

Yes, of course there's already a gadget you can use to create a table of contents for your page (Menu > Insert > Table of Contents). It's a rather nice gadget, but because I've intentionally numbered some sections and not others, there's a mental mismatch.

As you see, the Table of Contents generator gave section numbers to everything, so depending where you look, 2.2 is either Fuji apples or Bosc pears.

I didn't want to remove the section headings, and there was no real way to remove them via the Table of Contents gadget.

If you're not familiar with Google Apps Script, it's as you think: a scripting engine for Google properties. It's particularly powerful for scripting spreadsheets, and. as of October 22, you can process Google Sites with Google Apps Script.

Before going any farther, let me show you what I generated with Google Apps Script:

I'm no HTML Picasso, but it's not bad. Not bad at all. The links work, thanks to Google Sites automatically injecting <a name> tags with every <h[1-6]> tag.

The code

Let me share the code with you. First, here's how it's invoked:

function run({
  createToc(
    'https://sites.google.com/site/sitename/source-page',
    'https://sites.google.com/site/sitename/destination-page');
}



Yes, so you can specify a page from which to read and generate a second page with the table-of-contents included. (Side note: This actually gives me lots of ideas about workflow -- envision if the source URL was a private site where drafts were written, you could use Google Apps Script as a way to push from a staging area to production.)

OK, the code. It's mostly processing XML and generating HTML.

// I do not warrant this code in any way.
// If you break something important, don't come crying to me.
// Actually, check your Sites revision history first.
// Then go cry.

// Load content from fromUrl. Find the table of contents, and stick it in the document
// Save at toUrl.
function createToc(fromUrltoUrl{
  var page SitesApp.getPageByUrl(fromUrl);
  var content page.getHtmlContent();
  var doc Xml.parse(contenttrue);
  var root doc.getElement();
  var toc=[];
  parse(tocroot);

  var prefixDiv "<div id='kberg-toc'>";
  var postfixHtml "</div><div id='kberg-toc-coda'/>";
  var codaDiv "<div id='kberg-toc-coda'/>";

  var html prefixDiv tocToHtml(tocpostfixHtml;

  var index content.indexOf(prefixDiv);

  var newContent;
  if (index == -1{
    var "<div dir='ltr'>";
    index content.indexOf("<div dir='ltr'>"x.length;
    Logger.log("3: " index);
    var outdex index;
    newContent content.substr(0indexhtml content.substr(outdex);
  else {
    var outdex content.indexOf(codaDiv);
    newContent content.substr(0indexhtml content.substr(outdex codaDiv.length);
  }
  var newpage SitesApp.getPageByUrl(toUrl);
  newpage.setHtmlContent(newContent);
}

// Recurse through the XML, finding <h[1-5]> tags.
function parse(tocelement{
  var name element.getName().getLocalName().toUpperCase();
  if (name == "H1" || name == "H2" || name == "H3" || name == "H4" || name == "H5"{
    var level parseInt(name.substring(1));
    var anchorChildren element.getElements("a");
    var anchorText (anchorChildren.length 0)
        anchorChildren[0].getAttribute("name").getValue("";
    
    var item {
      level level,
      anchor anchorText,
      description element.getText(};
    toc.push(item);
  else {
    for each (var child in element.getElements(){
      parse(tocchild);
    }
  }
}
     
// Convert the table of contents entries into HTML.
function tocToHtml(toc{
  var html =
      "<div style='width: 250px; background-color: #e8e8e8;'>\n"
      "<br/><b>Contents</b><br/><br/>\n"
  for each (var entry in toc{
    var html2 indent(entry["level"]"<a href='#" entry["anchor""'>" +
        entry["description""</a><br/>\n";
    html html html2;
  }
  html html "<br/></div>";
  return html;
}

// Given an indentation level, return (2 * (level - 1)) non-breaking spaces.
function indent(level{
  var "";
  for (var 0level 1i++{
    "&nbsp;&nbsp;";
  }
  return x;
}


Final Thoughts

The remaining issue is triggering this script. Google Apps Script does have an event notification mechanism (e.g. run this script when the spreadsheet opens) but right now, Google Sites only has a time-based trigger (e.g. run this script every n minutes/hours.) To be honest, if an onSave trigger was written, would createToc(url, url), which would save the TOC to itself, trigger another onSave event? No big deal, if it results in a no-change, I could tweak the code accordingly.

But the lack of an onSave trigger makes this just slightly usable for me. Having this run every two minutes is too frequent for when the site isn't updated. I don't know the plans for the Google Apps Script team and/or the Google Sites team, but this is a good use case for onSave.

I wonder how hard it would be to hide the default TOC renderers' section numbers with clever CSS, or just write my own Google Gadget...

Tuesday, November 02, 2010

My new iPod Nano 6g

I wear out equipment pretty quickly. In fact I'm surprised my Nexus One has lasted for almost a full year without a major scratch. But iPods, well, those I wear out pretty quickly. And in the last two years I've really started to listen to podcasts and audio books, and so my iPods have been well loved.

My last one, the iPod Nano 4g had one newer feature that I really relied upon: sleep mode. I'd put something in the dock, and set it to sleep in 30 minutes. By then I'd be fast asleep. It was a good, reliable pattern.

Then my Nano broke. I pulled out a 2G Nano which worked, well, it worked OK but didn't have the sleep function. I'm still not ready to go all-out with my Nexus One. The battery life isn't quite ready for it, and, let's face it, I break stuff like that, and I'd rather keep it around for phone calls.

So I ordered the iPod Nano 6G.

In short, I just love it. Engadget has a review that covers the iPod's features; feel free to read that for something thorough.

The good:
  • The new UI is snappy and easy to use. The replacement of a the scroll wheel with a touch screen makes for easy interaction. I didn't have to learn how things worked, I figured it out naturally. It's meant to look like iOS, but isn't iOS. For instance, if my research is right, you can't write apps for it.  Given that there are five, pages for apps in the home screen and only fifteen apps, there seems to be natural room for expansion in future firmware updates.
  • Radio! When I showed this to my wife, she brought out her iPod envy. It's got a sufficiently workable radio receiver.
  • Pedometer. Nice feature, it's even gotten me to walk more. Allegedly you can publish your pedometer data to some Nike service, but I'm not particularly interested.
  • Sleep Mode is still there. Given that they removed so many other features (see below) I was glad to see the sleep mode was still there. It took a while to find it (it's in the Clock application.)
  • Also, When it's showing a clock face, it feels a bit like a pocket-watch. A very lightweight back-lit faux-analog pocket watch, but a pocket-watch nonetheless.
The bad:
  • Clumsy buttons. The use of more hard buttons on the iPod Nano feels like a bit of a cop-out, and even on my smaller hands, they're a bit hard to fumble with.
  • No video playback. Not even for video podcasts.  I don't mind much, they're clearly drawing a line between iPod and iPhone (or iPod touch.)
  • No games, no video camera, no contacts, no notes. I don't care about most of those, well, except for games, but I can always fall back on my phone if needs must.
  • Clumsy access to the dock connector. The headphone jack is so close to the dock connector that you have to remove the headphones before disconnecting the iPod. It's an irritating usability fumble, but understanding given the tiny form factor.
  • Tiny Engraving. I opted for engraving the device with my email address in case it gets lost. It's difficult to read the engraving without a magnifying glass. I'm guessing it's a 6-point font for a 20-character message.
The fact that they've removed features that might make someone more likely to purchase an iPod touch makes this feel much like the IBM PC Jr (a little nod to my fellow dinosaurs.) In some ways, it's like the PC Jr (replace chicklet keyboard with clumsy buttons.) Sure, they want you to buy an iPod Touch, but I'd rather have the lightweight device, and I already have a large bulky video-playing computer.

In short, this is great as a companion lower-power-consuming audio device.

Thursday, October 28, 2010

Plot Predictions for Avatar 2 and Avatar 3

Barron's reports that James Cameron has been given the go-ahead to produce two sequels to Avatar, to be released in 2014 and 2015. Here's my prediction of the critical plot points for next two films. These are not jokey predictions, I'm going for gold.

Avatar 2: The Na'vi are slowly rebuilding their home world. Sully is struggling to find his place on Na'vi, not only on this new world, but in his new body. The RDA returns, with a larger army, but also mega-avatars that are bigger and stronger. Also the technology is much better; the projection devices are portable. They're prepared, and ready to do business. In order to provide key defensive support to the Na'vi, which is shown to us as a threat to the now pregnant Neytiri, Sully is led by a yet-unknown Na'vi spiritual leader who restores Sully's original human (and paraplegic) form. Sully realizes this was a mistake, and manages to become a mega-Navi himself to, along with several new friends, destroy the mega-avatars. Sully fully accepts his Na'vi identity.

Avatar 3: Neytiri and Sully have their baby. Sully is also now an established leader among the Na'vi, but now things are turning political, and frankly, irritating. This was not what he expected in this new world! Sully's struggle is now with Neytiri. A couple of domestic fights and Sully turns all these negative feelings inward. There are some Na'vi who dislike the way Sully wants to lead the Na'vi, some of whom have strong spiritual powers. One of them feigns friendship and dupes him into a mystical event that creates a spiritual clone of the new mega-Sully, made only of his anger and fear. It also saps him of the power that makes him strong and confident, leaving him being less than half of himself. Sully needs to learn to trust in himself before the evil Sully can destroy Pandora ... which of course he does.

Come back here in 2016, tell me if I'm wrong.

(Credit: Louis Gray's share on buzz)

Thursday, October 14, 2010

On Teaching Ultimate Frisbee to Children

In September I started teaching co-ed Ultimate Frisbee to local middle school children. I spend three hours a week every Sunday assisting the coach, an impressive woman who balances teaching skills against just having fun, and somehow manages to corral the 30 boys and girls into doing drills and wearing pinnies.

And I don’t know if you’ve seen middle school children recently, but it's scary to be an isolated adult surrounded by 30 kids you've never met. What if they don’t listen to you? What if they don’t like you? So I laid back, helped the coach, and focused on very basic things: throwing, catching, one-on-one attention and congratulating good effort.

I saw a girl look dejected on her first day. I asked her what was wrong but I already knew: the boys weren't throwing to her, and when the disc was at her feet, another boy on the field would tell her to not pick it up so he could throw it. There wasn’t too much I could do about getting the boys to throw to her; that’s a problem anyone who's played any co-ed sport can understand (though I explained to both sides that you're less likely to score when you only look to throw to your friends). But when the Frisbee is at her feet?

“Just ignore them and pick it up!” I said.

Two weeks later during a pick-up game the Frisbee fell at her feet. She turned to get away from it when I yelled “Pick it up!”

She threw to another girl for a goal.

Another boy had the opposite problem.

“Nobody on my team picks up the Frisbee, and I have to pick it up every time!” he complained.

Apparently he didn’t like being forced to put the disc in play. OK. Simple advice, of course. Don’t pick it up! Someone else will eventually get it. He picked it up twenty minutes later.

“Hey! I thought you weren’t going to do that anymore.”

A third child is quite a good player. He likes making farther-distance throws, but long unfocused throws have a low-percentage chance of being caught. So his skill isn't translating into completed passes. I suspected his problem was a lack of focus and a desire to huck the disc (colloquial for winding up and letting go), so after his third low-percentage throw I spoke with him.

“The next throw you make, I don’t care how far it goes, I want it to connect.”

He looked shocked. But sure enough, his next throw was a good high percentage throw. But it was blocked! Someone on the other team was on the ball and blocked it. He turned to face me and yelled “It wasn’t my fault!”

“I know, I know. Good throw!” I yelled back.

His next two throws were excellent short-distance throws that found their targets.

The thing I had to remember is that kids that age are more emotionally delicate than they let on, so negativity has no place there. And I have to hand it to them: none of the kids call each other bad names, and nobody gets chastised over making mistakes.

This past Saturday the kids had their first scrimmage of the season against another team. I helped by motivating the team with non-stop encouragement and high-fives. Near the end of the game, I caught a player from the other team defending by blocking an area with his arm. A potentially illegal move, and an un-spirited play! I got angry! What a little punk! I let the anger dissolve and spoke with the other team’s coach so he would know to help the boy understand the non-contact rule. The coach explained. “Sure thing. But so you know, he’s only been playing for two weeks.”

I was relieved that I waited before speaking and awful at how poorly I read the situation.

After the game I approached the boy.

“Hey, nice game! You played well!” I said.

“Really?” he asked. He spoke with a soft voice. Such a boy!

“Sure! Did I hear you have only been playing for two weeks?”

“Yes.” Again with the soft voice.

“Well I wouldn’t have known. You play like someone who knows what he’s doing. Keep it up!”

“Thanks,” he said.

I am looking forward to next Sunday.