It’s been six years, but I can finally quiet the clamor of faithful Mucoshave fans the world over.
To help dispose
Of that which grows
Beneath your nose
Just use what flows
Mucoshave
Americlecticintellectica
It’s the thirtieth anniversary of The Brick Prison Playhouse.
It’s understandable. First there’s the confusing name of the place: it’s neither a college nor merely a high school. Second, when you’re in the habit of telling stories from high school, and some of them take place in 1978 and some take place in 1984, unless you’re diligent about the seventh-through-twelfth disclaimer sooner or later someone is going to do the mental arithmetic and wonder.
As a junior, late in 1982, a few friends and I felt the urge to write and perform a collection of short one-act plays. With faculty help we ended up founding The Brick Prison Playhouse (so called because the school’s appearance earned it the affectionate nickname “the brick prison”), a repertory group for performing student-written plays, as opposed to the existing repertory groups that performed established plays and musicals.
Our first performances took place on February 10th and 11th, 1983. They were a success and a lot of fun. After the last performance the entire playhouse group trekked through Central Park in a light snowfall to the Upper West Side apartment of our friend Michael, where we had a memorable cast party — and ended up snowed in. The only reason I know the exact dates is because it was the great New York Blizzard of 1983.
The next morning, I had to make it back to Queens, but transit had been only partially restored throughout the city. Exiting Michael’s building I was amazed to discover that Broadway was navigable only via a shoulder-high snow trench, just wide enough for two pedestrians to squeeze past each other. Through this narrow channel I worked my way downtown to where working buses and subways could be found — with my also-Queens-bound friend Steve in tow, on crutches with a broken ankle!
(Steve was the best writer in our group. The most talented actor among us was Andrew. I’m pleased to report that today Steve is a professional writer and Andrew a professional actor.)
On the radio program Fresh Air the other day, I heard an interview with the journalist Chris Hayes. In it, he mentions that he grew up in New York City, attended a school from the seventh through the twelfth grades, and performed in a student-written play in the eighth grade. From this I concluded (correctly) that Hayes is a Hunter alumnus, and that The Brick Prison Playhouse still exists!
It occurs to me this is the second blog post in a row where I lay claim to an unacknowledged legacy. Well, acknowledged or not, this one’s an agreeable legacy to have, and the Brick Prison Playhouse’s near-mention on Terry Gross’s widely heard radio show is a nice little brush with fame on this, its thirtieth anniversary.
Doctoring the coffee after brewing added a good twenty or thirty seconds to the total coffee preparation time, a substantial increase over the time needed by the machine. But the machine’s user waits idly for seventy-four seconds; why not put that time to better use?
Occasionally a line would form of coffee addicts needing their fix. Most had the same routine: when one brew cycle was finished, the next person in line would place his or her cup in the machine and press the button. Seventy-four seconds later they’d withdraw their cup, add sugar, carry it over to the cooler, take out the half-and-half, and add that; then leave.
Doctoring the coffee after brewing added a good twenty or thirty seconds to the total coffee preparation time, a substantial increase over the time needed by the machine per se. But the machine’s user waits idly for seventy-four seconds; why not put that time to better use? After several months it dawned on me to change my routine. As soon as the previous user’s cycle ended, I pressed the start button without putting a cup in the machine. Instead, during the first thirty or so seconds of grind-and-brew time, I put sugar and half-and-half into my empty coffee cup, then placed it in the machine. By the time the machine was finished, I was all ready to go, about 25% faster than everyone else.
In hindsight it was an obvious optimization to make, and in an office full of bright, busy engineers I was surprised that I was the only one I had ever observed making it. I did occasionally get some appreciative glances from others on seeing my technique in action, and finally within the past year I’ve noticed my method catching on. It’s gratifying to be a trendsetter, but frustrating to be unacknowledged. At least I can tell you about it.
He’s may king’ll list
Shaking it wise
Khan a fine tout who’s
Gnaw tea and ice
Sand two glosses car mint to town
He seize hue in yours leaping
He no swan euro ache
He no sieve you’ve bin batter could
Soapy good fur could nose ache
Ewe bed err war shout
Ewe bed err knock rye
Ewe bed err notch out
I’m telling you eye
Sand two glosses car mint to town
(Previously.)
My kids know the truth about Santa Claus. Do you?
It happened on my birthday, of all days, a year ago. The boys were seven-and-a-half and nine-and-a-half. For a few months prior, whenever Santa Claus came up in conversation, whichever boy was speaking would cast me or my wife a sidelong glance and say pointedly, “a.k.a. Mom and Dad!” and the conversation would continue without further comment. So the bubble had already burst, they just lacked official confirmation — which notably they didn’t explicitly seek until we were sitting all together in the living room, getting ready to watch my birthday movie selection. When they did, I asked if they really wanted to know the truth. Archer, who is younger, just barely did, in my judgment. Jonah was burning for it.
So I opened the Wikipedia page about the real St. Nicholas and talked about him for a bit, and how he became renowned as a gift-giver. He was an ordinary man, so of course he died; but the gift-giving idea lived on.
Today, around Christmas every year, the spirit of St. Nicholas takes hold of parents everywhere. So although there’s no guy with a magical sleigh, and other parts of the story certainly are made up, still, in a very real way — and I told them this is honestly exactly what I believe — there is a Santa Claus, and Santa Claus is the idea of giving, and he/it really does travel around the whole world in a single night! He just needs us parents to do his work for him. You’ve heard of Santa’s elves? We’re it.
The boys seemed pretty happy with this explanation. Jonah, for his part, was happy merely to have Santa Claus officially debunked. I repeated my point about the reality of Santa Claus, and Archer said, “I half-believe you and I half-believe Jonah.” “Making up your own mind. I love that,” I told him.
Soon after that we let the boys see Batman Begins, despite some concerns about age-appropriateness. There’s the scene where Bruce Wayne decides he has to have a costumed alter ego:
“As a man, I’m flesh and blood. I can be ignored. I can be destroyed. But as a symbol? As a symbol I can be incorruptible. I can be everlasting.” The point being that if Bruce Wayne is ever injured or killed (or grows too old, which is the premise of Batman Beyond), someone else can don the suit and take over as Batman. In a way this is exactly what happened with St. Nicholas — the Bruce Wayne of gift-giving. Now that was a Santa explanation the kids could relate to.
It’s National Computer Science Education Week! That must mean it’s time for part 2 of my How (And Why) To Program series. Today I will discuss a tricky but powerful concept in computer science: recursion.
Briefly, recursion means accomplishing a task by performing it in terms of smaller versions of the same task. For example, each morning I execute my “drive to work” routine, which is really my “drive from point A to point B” routine, where point A is home and point B is work. To do that, I first do “drive from point A to point B” where point A is home and point B is the Golden Gate Bridge (which is about halfway to work for me), followed by “drive from point A to point B” where point A is now the Golden Gate Bridge and point B is work. Each of those steps, of course, can be decomposed into smaller “drive from point A to point B” tasks.
One classic example for illustrating recursion in computer code is the Fibonacci sequence — the mathematical sequence in which each number is the sum of the two before it. You might already see the weakness in that definition: what can the first and second numbers in the sequence be, if they don’t have two numbers before them that can be added together? This is a key feature of recursive functions: at some point they reduce the problem into parts so small that they reach the “base case,” where the recursive rule breaks down. It happens that the base case of the Fibonacci sequence says the first two numbers are 0 and 1. From there, the recursive rule takes over to give the numbers that follow: 1, 2, 3, 5, 8, 13, 21, 34, and so on.
Let’s look at a “function,” which is the computer programming equivalent of a recipe: you give it some inputs, and it gives you an output, the result of processing the inputs in specific ways. Our function is called fibonacci and it takes one input, or “argument”: a number, which we’ll call n. The result of fibonacci(n) will be the nth number in the Fibonacci sequence, where the first two numbers — fibonacci(0) and fibonacci(1) (recall that in programming, lists and sequences of things are almost always numbered beginning at zero) — are 0 and 1.
As before, code samples are presented in the Python programming language, though the same concepts we’re discussing apply to most other programming languages too.
def fibonacci(n): if n == 0 or n == 1: return n else: return fibonacci(n-1) + fibonacci(n-2)
We start with “def fibonacci(n),” which simply means “define a function named fibonacci taking one argument called n.” The body of the function follows. First it checks for the base case: does the caller (whoever is invoking this function) want one of the first two Fibonacci numbers? If so, the function simply “returns” (or hands back to the caller) the value of n, since by coincidence the value of fibonacci(n) is n when n is 0 or 1.
If it’s not the base case, the function returns a different value: the sum of invoking fibonacci first on n-1 and then on n-2. Those recursive calls give the two prior Fibonacci numbers. For instance, if we invoke fibonacci(9), then n is 9 and fibonacci(n-1) is fibonacci(8), which is 21; and fibonacci(n-2) is fibonacci(7), which is 13. Adding those together gives 34, which is the correct result for fibonacci(9).
Enough about the Fibonacci sequence. It’s a contrived example and, though it explains recursion pretty well, it doesn’t demonstrate the real-world applicability of the technique. (It also happens that, for reasons I won’t go into here, recursion is a terribly inefficient way to compute Fibonacci numbers compared to other possibilities like iteration.)
A few days ago, my Mensa Puzzle-a-Day Calendar presented this riddle:
The letters of a certain three-letter word can be added in sequential order (though not necessarily with all three letters together in the same place) to each of the letter strings below to form common, uncapitalized English words. You don’t need to rearrange any of the letters below. Simply add the three needed letters in sequential order. What is the three-letter word, and what are the nine new words formed?
1. alp 2. wl 3. marit 4. ealus 5. urneman 6. cke 7. disintedl 8. traectr 9. epard
(To illustrate the puzzle: the letters of what three-letter word can be inserted in both “hoyde” and “ckear” to produce common English words? The answer is “new,” to produce “honeydew” and “neckwear.”)
Staring at the puzzle for a while, I was unable to solve it. So I sat down and wrote a program to solve it for me. How’s that for real-world applicability?
Once again I relied on the file /usr/share/dict/words (or sometimes /usr/dict/words, or /usr/lib/dict/words) that is a standard feature of some operating systems; it’s simply a list of many common English words (and many uncommon ones, plus some frankly questionable ones), one per line. Reading that file, I produced two sets of words: one set of all the words, and one set of all three-letter words. Here’s how that looks:
three_letter_words = set() all_words = set() wordlist = open('/usr/share/dict/words') for word in wordlist: word = word[:-1] all_words.add(word) if len(word) == 3: three_letter_words.add(word) wordlist.close()
(Very similar code is explained in detail in part 1 of this series.)
With those two word sets in hand, and the nine letter-strings from the puzzle, this was my strategy: try all possible ways of inserting the letters of all the three-letter words in each of the letter-strings. For any three-letter word, if none of its combinations with a given letter-string produces a valid word, remove the three-letter word from further consideration. In other words, beginning with all possible three-letter words, we whittle them away as they become disqualified. In the end, the only three-letter words left should be ones that combine, one way or another, with all of the nine letter-strings to produce valid words.
So, for example, the three-letter words “see” and “era” both can be added to the letter-string “alp” to produce valid words (“asleep” and “earlap”). But the three-letter word “new” can’t be, so after running through all the three-letter words on the letter-string “alp,” “see” and “era” will still be in the set three_letter_words, but “new” won’t be.
Here’s how that strategy looks:
for string in ("alp", "wl", "marit", "ealus", "urneman", "cke", "disintedl", "traectr", "epard"):
This starts a loop that will run nine times, once for each letter-string, giving each letter-string the name “string” on its turn through the body of the loop.
three_letter_words_to_discard = list()
This creates an empty list called three_letter_words_to_discard. It’s empty now but as we progress we will fill it with words to remove from the three_letter_words set.
(If you’re wondering why I sometimes use lists for collections of things, and sometimes use sets, gold star! The answer is that they are two different kinds of data structure, each one good at some things and bad at others. A set is very fast at telling you whether a certain item is in it or not; a list is slow at that. On the other hand, a list keeps things in the same order in which you added them; a set doesn’t do that at all.)
for three_letter_word in three_letter_words:
This starts a nested loop. It’ll run through the complete list of three_letter_words each of the nine times that the outer loop runs.
combinations = combine(three_letter_word, string)
Here we presume there’s a function called combine that takes the current three-letter word and the current letter string, and produces the complete list of ways that the letters of three_letter_word can be interspersed with the letters of string. For example, combine(“abc”, “def”) should produce the list [“abcdef”, “abdcef”, “abdecf”, “abdefc”, “adbcef”, “adbecf”, “adbefc”, “adebcf”, “adebfc”, “adefbc”, “dabcef”, “dabecf”, “dabefc”, “daebcf”, “daebfc”, “daefbc”, “deabcf”, “deabfc”, “deafbc”, “defabc”]. That’s where recursion is going to come into play. We’ll get to writing the combine function in a moment.
good_combinations = list() for combination in combinations: if combination in all_words: good_combinations.append(combination)
With the list of combinations in hand, we now look through them to see which of them are valid words, if any. We set good_combinations to be a new empty list where we’ll accumulate the valid words we find. We loop through the combinations, testing each one to see if it’s a member of the set all_words. If one is, we add it to the list good_combinations.
if good_combinations: print three_letter_word, "+", string, "=", good_combinations else: three_letter_words_to_discard.append(three_letter_word)
After the “for combination in combinations” loop, we check to see whether good_combinations has anything in it. (“If good_combinations” is true if the list has something in it, and false otherwise.) If it does, we print out the current three-letter word, the current letter-string, and the list of valid words they make. If it doesn’t, then three_letter_word goes into our list of three-letter words to discard.
for word in three_letter_words_to_discard: three_letter_words.remove(word)
After the “for three_letter_word in three_letter_words” loop, this small loop does the discarding of disqualified three-letter words.
Why not simply discard those words from three_letter_words in the preceding loop, as we run across them? Why save them up to remove them later? The answer is that when you’re looping through the contents of a data structure, it’s a bad idea to add to or remove from the data structure. The loop can get confused and lose its place in the structure. It may end up running twice with the same list member, or skip a member entirely. It’s safe to make changes to the membership of the data structure only after the loop finishes.
Finally, after the outermost loop has finished, it’s time to see which three-letter words remain in our set:
print three_letter_words
And that’s all! All except the tricky part: the combine function. Here is how it starts:
def combine(string1, string2):
It takes two strings. We’ll give them generic names, string1 and string2, so as not to assume that either one is a three-letter word. As you’ll see, often neither one is.
Now, how to approach writing a recursive function? It’s usually a safe bet to start with the base case, the conditions under which combine isn’t recursive. The recursive step will involve passing shorter and shorter strings to combine, so the base case is when one or both of the strings is empty. Obviously if either string is empty, the result should be the other string — or more precisely, the list containing the other string as its one member (since we’ve already stipulated that the result of combine is a list of strings). In other words, combine(“”, “def”) should produce the list [“def”] — which after all is the result of interspersing the letters of “” among the letters of “def” — and combine(“abc”, “”) should produce [“abc”].
So here’s the body of combine so far. It’s just the base case:
if len(string1) == 0: return [string2] elif len(string2) == 0: return [string1]
(Recall that “elif” is Python’s abbreviation for “else if.”)
Now for the case where string1 and string2 are both non-empty; the recursive case. The key to writing the recursive step of a function like this is figuring out (a) how to make the problem the same but smaller, and then (b) what to do with the result of computing the smaller solution.
One way to make the problem smaller is to lop off the first letter of string1. So if combine were originally invoked with the strings “abc” and “def,” the recursive call would invoke it with “bc” and “def.” Presuming combine works correctly — which is the counterintuitive assumption you must always make about the recursive step in a function like this — we’ll get back the list [“bcdef”, “bdcef”, “bdecf”, “bdefc”, “dbcef”, “dbecf”, “dbefc”, “debcf”, “debfc”, “defbc”]. None of those belongs in the result list of combine(“abc”, “def”); but if we now restore to the beginning of each of those strings the same letter we lopped off, we get [“abcdef”, “abdcef”, “abdecf”, “abdefc”, “adbcef”, “adbecf”, “adbefc”, “adebcf”, “adebfc”, “adefbc”]. This is halfway to the complete answer: it’s all the strings in the result list that begin with the first letter of string1. We only need to add all the strings in the result list that begin with the first letter of string2, and we’re done. We do this by treating string2 the same way we just treated string1: we lop off its first letter in another recursive call to combine, then paste it back on to each string in the result. Continuing the example, this means calling combine(“abc”, “ef”), which produces [“abcef”, “abecf”, “abefc”, “aebcf”, “aebfc”, “aefbc”, “eabcf”, “eabfc”, “eafbc”, “efabc”]. Sticking the “d” back onto the beginning of each of those strings gives [“dabcef”, “dabecf”, “dabefc”, “daebcf”, “daebfc”, “daefbc”, “deabcf”, “deabfc”, “deafbc”, “defabc”], and adding this list to the list from the first recursive call gives the complete solution.
In Python, the first letter of string is denoted string[0]. The rest of string, without its first letter, is denoted string[1:]. So here’s the complete version of combine, with the (double) recursive step added in.
def combine(string1, string2): if len(string1) == 0: return [string2] elif len(string2) == 0: return [string1] else: recursive_result1 = combine(string1[1:], string2) recursive_result2 = combine(string1, string2[1:]) result = [] for string in recursive_result1: result.append(string1[0] + string) for string in recursive_result2: result.append(string2[0] + string) return result
This is the crazy magic of recursion: at each step, you simply assume the next-smaller step is going to work and give you the result you need. All you have to get right is the base case and the way to process the recursive result, and — well, look:
hol + alp = ['alphol'] has + alp = ['alphas'] sae + alp = ['salpae'] her + alp = ['halper'] see + alp = ['asleep'] eta + alp = ['aletap'] era + alp = ['earlap'] soe + alp = ['aslope'] yin + alp = ['alypin'] pus + alp = ['palpus'] een + alp = ['alpeen'] kas + alp = ['kalpas'] ecu + alp = ['alecup'] ist + alp = ['alpist'] doh + alp = ['adolph'] pal + alp = ['palpal'] cul + alp = ['calpul'] ped + alp = ['palped'] Moe + alp = ['Malope'] clo + alp = ['callop', 'callop'] gos + alp = ['galops'] tid + alp = ['talpid'] yum + alp = ['alypum'] pon + alp = ['palpon'] hin + alp = ['alphin'] joy + alp = ['jalopy'] hol + wl = ['wholl', 'wholl'] sae + wl = ['swale'] soe + wl = ['sowel', 'sowle'] joy + wl = ['jowly'] joy + marit = ['majority'] joy + ealus = ['jealousy'] joy + urneman = ['journeyman'] joy + cke = ['jockey'] joy + disintedl = ['disjointedly'] joy + traectr = ['trajectory'] joy + epard = ['jeopardy'] set(['joy'])
Bob Glickstein
[address]
[phone number]
[e-mail address]
13 Oct 2012
PayPal, Inc.
Attn: Litigation Department
2211 North First Street
San Jose, CA 95131
To whom it may concern,
I am a PayPal user at the e-mail address above. I do not agree to the Agreement to Arbitrate as delineated in your Amendment to the PayPal User Agreement and Privacy Policy dated Nov 1st, 2012. By this letter I hereby reject it per the opt-out procedure described in section 14.3 (e). Kindly exclude me from the Agreement to Arbitrate.
I further request that you consider dropping the arbitration clause altogether, for all your customers, as a matter of principle. Hand-wringing about frivolous lawsuits notwithstanding, citizen access to the public court system is one of the things that makes America great. I invite you to read my fuller thoughts on the matter at www.geebobg.com/2008/09/20/the-sue-s-of-a/
Timely written acknowledgment of this request sent to the above address would be greatly appreciated.
Sincerely,
[signature]
Bob Glickstein
Happy birthday to Beatlemania! The Beatles’ first single, “Love Me Do,” was released on this date fifty years ago. And happy birthday to James Bond! Dr. No, the first movie in the world’s longest-running film franchise, also opened today, also in 1962.
Earlier this year we observed the fiftieth anniversary of John Glenn’s historic orbit of the Earth, and the fiftieth anniversary of Kennedy’s landmark “we choose to go to the moon” speech.
In 1962, Stan Lee and the other adolescents at Marvel (I use the term affectionately) created Spider-Man, Thor, and the Hulk. Fifty years later, those creations are still relevant enough to star in their own brand-new blockbuster films.
The films Lawrence of Arabia, To Kill a Mockingbird, and The Music Man are fifty years old too. The famous escape from Alcatraz happened fifty years ago. The Seattle Space Needle opened to the public. Polaroid introduced its instant color film. Rachel Carson published her world-changing book, Silent Spring.
I don’t recall celebrating so many fiftieth anniversaries last year, do you? Something about 1962 appears to have been so special that we are still celebrating its achievements and events.
It wasn’t all good. People everywhere braced for global annihilation during the Cuban Missile Crisis, fifty years ago this month. Marilyn Monroe OD’d. But there was enough nostalgia for 1962 that, years later, George Lucas set the events of American Graffiti in that year, and it’s also when the action in Animal House takes place.
What was it about 1962? Fifty years from now, what events or achievements of today will people still be celebrating?
In 1996, some friends and I started our own software company, Zanshin. But by 1999, suffering from a lack of focus and a tendency toward overengineering, we had still not managed to produce a salable version of our world-changing software. Luckily for us we got a consulting gig for Amazon.com (unrelated to my involvement with the Internet Movie Database). That contract went so well that after a few months of it, in early 2000, Amazon offered to hire us all. We would have to close Zanshin and move up to Seattle. Andrea and I, newly married, got as far as scoping out Seattle neighborhoods. We were leaning toward accepting Amazon’s offer. Zanshin clearly was going nowhere, and Amazon had interesting work for us.
We had a Zanshin company meeting to talk it over. Some of us wanted to accept, some wanted to keep trying with Zanshin. We had the frank discussion about our plans and lack of progress that we should have been having all along. In the process, we brainstormed some exciting new ideas. In the days that followed we fleshed those out. The uninspired daily grind that working at Zanshin had become took on a new feeling of hopefulness. My co-worker Steve, who had also been in favor of the Amazon offer, gave a stirring speech about continuing on our own.
When it came time to give Amazon our final decision, we voted unanimously to turn them down. Knowing I’d previously been the strongest vote in favor of the Amazon offer, my co-worker Greg asked if I was sure. I replied, “I’m like the arrow that springs from the bow. No hesitation.”
It was a line spoken by Michael O’Hare as Jeffrey Sinclair in Babylon 5. I have used that sentiment a few times since then as a way to gauge my readiness for something — starting a family, for instance. If I can’t say that line with conviction I know I’m kidding myself.
Today came news that Michael O’Hare died. Nerds all over the web are paying him tribute for his role in a beloved space adventure, but his legacy is a little more personally meaningful to me. His memorable reading of that one line has attended every important decision of my life since he spoke it.