Book Report: The Non-Designer's Design Book

An introduction to layout design. There are general principles; there was also more detailed advice on designing brochures, business cards, and other stuff I don't care about. But the general principles seem like stuff I could apply.

  • Proximity Keep related things together
  • Alignment Create strong lines through alignment. Use alignment to "connect" far-apart page elements.
  • Repetition Re-use elements
  • Contrast Why use a small difference when you can use a big one?

Families of type. Don't use two typefaces from the same family--they'll be similar enough such that they won't work for contrast. That rule of thumb of using sans-serif vs. serif for headers vs. body text comes from this general principle.

  • Oldstyle Times, Palatino, Baskerville, Garamond
  • Modern radical thick/thin transitions more likely to hit at 90deg than at the slanty-pen Oldstyle look. Bodoni, Times Bold
  • Slab serif Thicker lines. Clarendon, Memphis, New Century Schoolbook. Readable for extensive text, but they make the page look dark.
  • Sans serif Be careful with varying-weight fonts like Optima--they don't combine well with other sans-serif, but also don't combine well with serif fonts
  • Script
  • Decorative

Labels: ,

Site: Yet more Library Book Cart graffiti photos

I uploaded more library book truck graffiti photos (scroll down to the section marked February 2009 for the latest greatest). Can you find the palindrome? I knew you could.

Labels: , ,

Book Report: Exploiting Online Games

This book is about hacking online games. Unfortunately, they started out talking about plenty of stuff which I already had read about. Cheating happens. E.g., people in shoot-em-up games use video drivers that don't fill in the walls, just draw "wire frames"--and thus they can see bad guys through walls. Stuff like that. The economics of MMORPGs, of selling stuff. I guess I heard about this stuff from Slashdot and comp.risks? I dunno. By the time they actually start talking about how to exploit games, I wasn't paying attention any more. And it seems like they assume you have access to some software library that only they have access to? Maybe if I'd kept paying attention, I would have learned some things about reverse-engineering.

Labels: , ,

Link: AllMyData

I occasionally backed up my files. But it was always ad-hoc: zip up an archive of some files, upload it to my web server. Done by hand when I got around to it (not often).

Then there was the time when I upgraded my OS and it all went pear-shaped. I knew it was risky, so I zipped up an archive of my files, encrypted it (there was some private info in there), and uploaded it. Then the upgrade took a lot longer than I thought--partway through, it became apparent that I needed to send away for installation discs. And I lost the Post-It with the password I'd used to encrypt my files. And I couldn't remember the password. So that was a few months' of data lost forever.

Gone, daddy, gone.

So it was time to re-think my backups.

I'm starting to buy music online. If I send too much data back-and-forth to my website, I get charged for it. And there's a disk space quota besides. So, as I accumulate more music, I can't keep on using my web-site to hold my backup files.

So it was really time to re-think my backups.

Where could I keep these files? I could get an external hard drive. Of course, a lot of the problems that could wipe out my PC could also wipe out a hard drive sitting next to my PC. I have a teeny-tiny apartment. A small dog could destroy most of my electronics in about a minute. So, I was thinking about off-site backups. Backing up my data to "the cloud," as it were. Every year or so, there's a flurry of rumors that Google will launch a "G-drive". Two years of rumors and it ain't happened. I didn't want to wait for that. (Yes, you know where I work. No, I can't comment on unannounced thingies, nor do I even know half of the stuff that's brewing at work.)

I lurk on a mailing list about "capabilities" in computer security. This guy named "Zooko" keeps posting there about this online storage service he works on. Wow, an online storage system sounds like exactly what I need. Zooko seems reasonably sharp.

At some point, I follow up by learning more about this online file service, I find out that their CEO is Peter Secor. I worked with Peter Secor back in the day at Geoworks. Peter was pretty competent back then; no reason to think he's less competent now.

So I signed up for an account at $100 a year for "unlimited" storage--where "unlimited" means "as much as I can upload/download".

If you just look at the website, you'll think "Wait, this is for Windoze losers and Macintosh freaks. There's nothing here about Unix weenies." But my previous research had clued me in to the existence of's Tahoe, an open source program which would, among other things, allow me to send my files to/from's service.

What I didn't have was a program that would do something rsync-like every so often. So I threw together some quick-and-dirty Python that could run in a cron job.


# Back up files to servers.
# Use a random order: I don't trust myself to write
# a program that doesn't fail partway through.  But
# if we run a few times, with a different order each
# time, we should back up most files OK.

import datetime
import simplejson as json
import os
import random
import subprocess
import tempfile

# The trees of files to upload.  Those with 'crypt': True get gpg-encrypted
# before upload.  (The rest are uploaded plain, unencrypted.)
    { "path": '/home/lahosken/keep/' },
    { "path": '/home/lahosken/seekrit/', 'crypt': True },

# Something like tahoe:/2008/home/lahosken/keep/path/to/file.txt
REMOTE_ROOT = 'tahoe:' + str(

TMP_DIR = tempfile.mkdtemp()

def EnumerateLocalDirs(start_path):
    retval = []
    for (root, dirs, files) in os.walk(unicode(start_path)):
        if files: retval.append(root)
    return retval

def MakeRemoteDir(local_dir_name):
    print "MakeRemoteDir", local_dir_name
    p = subprocess.Popen("tahoe mkdir '%s'" % REMOTE_ROOT, shell=True)
    sts = os.waitpid(, 0)
    path = ""
    for pathlet in local_dir_name.split("/"):
        path += pathlet + "/"
        remote_dir_name = REMOTE_ROOT + path
        remote_dir_name = remote_dir_name.replace("'", "'\\''")
        p = subprocess.Popen("tahoe mkdir '%s'" % remote_dir_name, shell=True)
        sts = os.waitpid(, 0)

def SyncFile(local_path, root):
    print "SyncFile", local_path
    local_path = local_path.replace("'", "'\\''")
    if "crypt" in root:
      encrypted_file_path = os.path.join(TMP_DIR, 
      p = subprocess.Popen("gpg -r -o %s --encrypt %s" %
                           (encrypted_file_path, local_path),
      sts = os.waitpid(, 0)
      p = subprocess.Popen("tahoe cp '%s' '%s'" % 
                           (encrypted_file_path, REMOTE_ROOT + local_path),
      sts = os.waitpid(, 0)
      p = subprocess.Popen("tahoe cp '%s' '%s'" % 
                           (local_path, REMOTE_ROOT + local_path),
      sts = os.waitpid(, 0)

def MaybeSync(local_dir_name, root):
    print "MaybeSync", local_dir_name
    remote_dir_name = REMOTE_ROOT + local_dir_name
    local_file_list = os.listdir(local_dir_name)
    remote_dir_contents_json = subprocess.Popen(["tahoe", "ls", "--json", remote_dir_name], stdout=subprocess.PIPE).communicate()[0]
    remote_dir_contents_dict = { "children" : [] }
    if not remote_dir_contents_json:
        remote_dir_contents_dict = json.loads(remote_dir_contents_json)[1]
    for local_file_name in local_file_list:
        local_path = os.path.join(local_dir_name, local_file_name)
        if not os.path.isfile(local_path): continue
        if "crypt" in root and local_file_name.endswith(".rc4"): continue
        if not local_file_name in remote_dir_contents_dict["children"]:
            SyncFile(local_path, root)
            remote_mtime = remote_dir_contents_dict["children"][local_file_name][1]["metadata"]["mtime"]
            local_mtime = os.stat(local_path).st_mtime
            if local_mtime > remote_mtime:
                SyncFile(local_path, root)
                # print "Skipping", local_dir_name, local_file_name, "already there"

def main():
    p = subprocess.Popen("tahoe start", shell=True)
    sts = os.waitpid(, 0)
    for root in LOCAL_ROOTS:
        local_dirs = EnumerateLocalDirs(root["path"])
        for local_dir in local_dirs:
            MaybeSync(local_dir, root)

if __name__ == "__main__":

Things can still go wrong with this system. I use gpg to encrypt my private stuff. My gpg key is on... my computer. It's also on a piece of removable media. Remember that hypothetical small dog I mentioned earlier, how easily it could mess up a hypothetical external hard drive at the same time it was destroying my computer? My removable media is not quite right next to my computer, but... things could still go wrong with it. Since my previous backup-recovery failure was due to me losing the encryption key, I'd like a stronger, foolproofier solution here.

Still, this is better than what I had before. I sleep easier now.

Labels: , ,

Book Report: Growing a Business

This is a book about running small businesses. The title says "growing", but it might as well have said "evolving". Hawken is thoughtful and wise, reminding the reader not to take on too many problems at once, to treat people well, to... I'm not running a small business, but there was still some good advice in here, a lot of it is about running your life.

Labels: , ,

Book Report: American Shaolin

Yestere'en, I watched the Chinese New Year's parade. I'm not into parades, but I visit a fair number of parades. Why show up an event I'm not into? A non-trivial fraction of my friends are photographers; they like to photograph parades; I like to hang out with my friends; thus my attendance logically follows. I'm not a photographer but I need something to keep me busy at these things. A few years ago, I started waving.

People in parades wave at the crowd. People on floats wave. Politicians riding in open-top convertibles wave. Beauty queens wave demurely. Banner-carriers wave. Small children, stumbling along in procession, wave adorably. Their parents, walking alongside, wave proudly. Sometimes, a few folks in the audience wave back. I always wave back. I smile and wave. Parade traffic is bursty; sometimes the parade stalls. Most folks in the audience who wave back at the parade stop waving when this happens; it's not easy to keep waving that long. Also, it's kind of awkward to keep waving at the same set of folks for a long time. I keep waving. I'm no stranger to awkwardness. A few years back, I wouldn't keep waving--I didn't have the endurance to keep going. But I got better, you know?

I kept practicing, parade after parade, year after year. I learned how to wave so that it's not so tiring. I learned a few different ways to wave; by "mixing it up," I can avoid straining my shoulder. At first my friends were embarrassed to be next to the big goofy waving guy. But there are advantages. Peter Tang, reviewing his photos from last night, pointed out that he got pretty good photos of the beauty queens, getting good shots of their faces. "They kept looking right at us--because you kept waving."

Gavin Newsom, mayor of San Francisco pointed me out last night: "He's got the wave down." Gavin Newsom, has marched in plenty of parades and has no doubt seen plenty of wavers. I don't agree with Newsom on many things, but I trust his judgment in this regard.

Late in the parade, the audience had thinned out. And most of the audience that was still there was tiring out. But I was still going, still waving, unflappable. A girl in the parade yelled at me: "Hey, you! You're the only one waving!" I'm not sure if she meant it as a compliment, but by golly I was pleased that I was still strong enough to maintain unwavering waving.

After the parade, I still had some strength left in my arms. I realized that I could have kept going. I'd only waved back at folks who'd waved. But now I thought: Next year, could I keep waving through the whole parade? This would involve waving at folks who wouldn't wave back, who'd be indifferent, who wouldn't appreciate it: martial artists, marching bands, perhaps even gaps in the parade devoid of people. This would be about four hours of waving.

Four hours is a lot. But I'd already progressed so far. And my only practice had been at parades. What if I trained? What if I practiced? We can teach our bodies to do great things if we practice.

I forget where I was going with this train of thought. Oh, right, physical training. Totally on topic for the book: American Shaolin.

A young man from Topeka dropped out of university to travel to the hinterlands of China and study martial arts at Shaolin Temple. This is his memoir. There is life in China. There is life in the martial arts community. There is a hint of life in a temple community. There are jokes. It starts with an insightful quote from Snow Crash about how young men think they can train to become the world's toughest ass-kicker. So you know that Matt Polly is well-versed in the classics.

This book is a good read. Apparently, this book was a best-seller last year. Probably you already heard of it. If you were going to read it, you probably read it before I did. But just in case, I'll point out: it was a fun read, it was well-written. Check it out.

Labels: , ,

Puzzle Hunts are Everywhere, even San Jose

I like The Game. I like the puzzles, but in between puzzles, I like hopping into a van and zipping around, visiting interesting places. Even though... all too often we don't really linger at the interesting places. Hop out of the van, grab the puzzle, hunker down, solve the puzzle, hop back in the van. Today, I visited a friend in San Jose. He was kinda close to a train station, but not super-close. So I had a bit of a stroll--and went through three game sites.

I hopped out of the train at the San Jose train station. Though I just-five-seconds-ago in the previous paragraph mused that teams don't always linger at Game-ish spots, this is not true of that train station. I remember spending a lot of time searching that station for a clue during the Midnight Madness: Back to Basics Game. We searched high and low; I watched an electronic announcement display for way too long. Today, after I disembarked from the train, I walked out of the station quickly. I looked up at the electronic display--and looked away quickly, still feeling somewhat embarrassed.

Next stop was the gardens at the Rosicrucean Temple. I'd been here before Jesse Morris for BATH3. We were on GC, and we visited NeilFred (and, uhm, maybe someone else who I'm blanking on?) who was guarding a puzzle there. It would have been a good opportunity to see the Rosicrucean Temple--but I was too focused on the game to think of playing tourist. Today, I played tourist--and found out that I'd already seen most of the temple gardens after all. Uhm, it had taken us a while to find NeilFred. Apparently, we traversed a non-trivial fraction of the gardens in the process. I did find one new thing today--a sundial. The Rosicrucean temple has a sundial. There's a tall tree next to it. The shadow of the tree obscures the shadow of the sundial. Wow, for a secret society that claims to have origins dating back hundreds of years, the Rosicruceans don't always plan things well.

Next, I went to the San Jose Municipal Rose Garden, just a couple of blocks away. We'd picked up a puzzle there for The No More Secrets Game. We didn't really appreciate the Rose Garden then. We just hopped out of the van, grabbed a puzzle, brought it back to the van, solved the puzzle, and drove away. Even if we'd been in the mood to linger... the park was locked up. The park was locked up because it was well after dark--not exactly a prime rose-appreciating situation. Today, the park was open! And it was daytime! And I was in the rose garden! But it turns out that winter isn't rose season, so the rose bushes were just these stemmy things. But there was also a public restroom, so don't think that I totally failed to appreciate this park.

Labels: ,

home |