Thursday, December 27, 2007

Ten in Six Months

In the last six months I have heard of ten deaths. Of course, one of them is my mother, and many of these recent announcements are not of people I know, but are, for instance, parents of friends, close friends of friends, et cetera. Today I heard the tenth, my friend and former colleague, Marion Trost.

My brother suggested I'm more sensitive to deaths given recent the loss of our mother. This is probably true, but doesn't seem to account for the significant number of people telling me they are losing the people close to them. A friend suggested I was reaching a stage of life where an older generation is dying out. This also may be true, but doesn't account for Marion, or the death of a 21-year old who has been a close friend of my housekeeper, or the death of my friend's near-40 year old best friend from cervical cancer.

There's not much to say, I'm just hoping people would slow down on the dying for a while. I look forward to a good winter.

Monday, December 03, 2007

Google Santa Monica in the LA Times.

Our local Google office was written up in the LA Times. I have a small quote, but it seems to lack a sensible context. Oh, who cares, they mentioned my dog!

Saturday, November 24, 2007

Thanksgiving

1. In advance of this Thanksgiving, I borrowed the Wii of my friends, Nick and Jerry. It took two days to earn our scar.


2. On Thanksgiving Day Beth and I served 17 guests. It should be no surprise that I thought about my mother for several days leading up to the holiday. I wanted to make some speech about Thanksgiving, either something of historical interest or perhaps a reminder of our blessings. I wrote two different speeches, but in the end I didn't use either and spoke off the cuff. I'm very happy with the result. I don't recall the exact words, but this is the part I want to share:

Before we start I'd like you to take a moment and reflect upon the blessings you have in your life. Most of you already know that my family suffered a terrible loss this year. It's important to use a day like today to remember that even when you have lost someone close, the life you had with them, while gone, is still a blessing today.

3. Making soup is one of my favorite things to do, and today I did it! After dinner, I made broth from the carcass, and today, I made turkey and rice soup. Turkey rice soup is something my mother used to make and while I don't have her recipe, I was close enough for my satisfaction. I used basmati rice instead of traditional long-grained rice. Since I like substantial soups, I added extra carrots and celery, though it turns out, I could have used less rice and more vegetables. I kept my spices to a minimum: salt, pepper, white pepper, and a little celery salt. Recalling a recent Thai meal, I also sliced fresh jalepeƱo and added it on the side.

I hope everyone enjoyed their Thanksgiving holiday.


Update: My wife says the soup makes the house smell good.

Tuesday, November 06, 2007

Code spacing and Blogger

I'm really getting frustrated with Blogger's inability to keep spacing when I provide well-indented code. It makes me want to not supply code samples. It makes me want to not post.

How do people successfully post code samples to Blogger? I could use some help. I don't feel any particular loyalty to Blogger, but making such a switch is always a pain.

Since I work for Google, I feel compelled to say: these are my own opinions and not those of my employer.

TestNG and Expected Exceptions

I've started reading Next Generation Java Testing which was just released last week. So far it's interesting enough. I've seen multiple presentations on TestNG, and read Cedric Beust's blog posts that describe the impetus for a new Java software testing approach, so the first chapter hasn't told me much I hadn't already known.

If this sounds like a lackluster introduction, I apologize. It's wonderfully written and informative so far.

Still, I've come across something that bothers me. Consider this example from the book:
public class BookingTest {
  private Plane plane;

  @BeforeMethod
  public void init() {
    plane = createPlane();
  }

  @Test(expectedExceptions = PlaneFullException.class)
  public void shouldThrowIfPlaneIsFull() {
    plane.bookAllSeats();
    plane.bookPlane(createValidItinerary(), null);
  }
}
(One Very Nice Thing about TestNG is that it's easier to read than JUnit, even if you don't know either testing API.)

My specific concern is the notion of expected exceptions in TestNG. The book explains that the expectedExceptions annotation is a reasonable replacement for the try/fail/catch pattern you find in JUnit:
public void testShouldThrowIfPlaneIsFull() {
  plane.bookAllSeats();
  try {
    plane.bookPlane(createValidItinerary(), null);
    fail("Exception expected");
  } catch(PlaneFullException expected) {
    // do nothing; exception expected.
  }
}
(Who puts semicolons in comments? I only put them in example comments. That makes them exemplary comments.)

I agree that the TestNG example is still easier to read than the JUnit example, but the problem is they're not effectively testing the same thing. Here's a more correct translation of the TestNG test using JUnit:
public void testShouldThrowIfPlaneIsFull() {
  try {
    plane.bookAllSeats();
    plane.bookPlane(createValidItinerary(), null);
    fail("Exception expected");
   } catch(PlaneFullException expected) {
     // do nothing; exception expected.
   }
 }
Did you catch the difference? The difference is in how exceptions thrown from plane.bookAllSeats() re handled. In the first JUnit example, if plane.bookAllSeats() throws any exception, the test will fail. In both the TestNG example and the second JUnit example, if plane.bookAllSeats() throws PlaneFullException, the test will still pass.

This bothered me all day. Let's say the engineer was very careful when he constructed this TestNG test. He would have known knew that plane.bookAllSeats() did not throw a PlaneFullException, so he could accept this mild semantic difference for the sake of readability. If, some time later, plane.bookAllSeats() is refactored to throw a PlaneFullException, and in addition, is accidentally broken, the TestNG test will falsely pass, and my JUnit test will correctly fail.

Here we have our problem: the expectedExceptions annotation attribute can't be used on the statement level. If I could annotate on the statement level, I could have this:
@Test
public void shouldThrowIfPlaneIsFull() {
  plane.bookAllSeats();
  @ExceptionExpected(class = PlaneFullException.class) {
    plane.bookPlane(createValidItinerary(), null);
  }
}
Semantically, you can't put annotations on the statement level, it doesn't exist in Java (though I have seen JLS proposals for this.)

Of course, I could simply use the try/fail/catch pattern in TestNG, but that's not The TestNG Way. (I want to say it's not "TestEnGee-Eee" or "TestNGish", but they both sound stupid.)

Let's analyze this test a little further. The first statement in the test is actually just more setup before calling plane.bookPlane(). I could move the set-up code to a specialized method annotated with @BeforeMethod, but given that that kind of set-up operations specialized for each test, readability reduces as the number of @BeforeMethod methods grows. Besides, it's nice to read each specific test as a sequence of statements.

Finally I realized an easy way to make this work:
public class BookingTest {
   private Plane plane;
   private boolean setupComplete;

   @BeforeMethod
   public void init() {
     plane = createPlane();
   }

  private void setupComplete() {
    this.setupComplete = true;
  }

  @AfterMethod
  public void verify() {
    if (!setupComplete) {
      throw new RuntimeException(
        "exception thrown before running critical test statement");
    }
  }

  @Test(expectedExceptions = PlaneFullException.class)
    public void shouldThrowIfPlaneIsFull() {
      plane.bookAllSeats();
      setupComplete();
      plane.bookPlane(createValidItinerary(), null);
    }
  }
In this case, setupComplete() operates as a gate. Now your test doesn't just pass if a PlaneFullException is thrown, you have to get past the setupComplete() method to be considered a successful test.

This solution works, but I don't quite love it. What about using Closures?
@Test
public void shouldThrowIfPlaneIsFull() {
  plane.bookAllSeats();
  expectException(PlaneFullException.class) {
    plane.bookPlane(createValidItinerary(), null);
  }
}

This looks both correct and concise. I love it.

Post-script

1. The authors are sensible enough to point out that there are plenty of times when using the expectedExceptions annotation attribute should be avoided, and they cover those cases. I just don't think I like expectedExceptions at all.

2. Would adding closures to the Java language obviate the need for statement-level annotations? It does here.

3. Those of you paying close attention are screaming that I missed something. Who said createValidItinerary() doesn't throw PlaneFullException?
@Test
public void shouldThrowIfPlaneIsFull() {
  plane.bookAllSeats();

  Itinerary itinerary = createValidItinerary();
  expectException(PlaneFullException.class) {
    plane.bookPlane(itinerary, null);
  }
}
4. This is yet another good argument for writing specialized exceptions for your use cases. It's somewhat unlikely that plane.bookAllSeats() and createValidItinerary() would throw PlaneFullException, but consider the difficulties if a Lazy Programmer designed the Plane API and used ArrayIndexOutOfBoundsException everywhere instead of PlaneFullException. Separating exeptions in a test method are just the beginning of that guy's troubles.

Friday, November 02, 2007

Run DMC Alert!

Run DMC on Reading Rainbow.

Oh how LeVar Burton make me laugh.

Why isn't this funny?

About two years ago I wrote a very small blog called "Just One Monkey". In it there were five posts that contained snippets from a monkey experiment. I like the idea, it's kind of cute, but it's not *funny*. I'm willing to admit the premise is bad; I'm also willing to admit it just doesn't work. The problem is that I can't tell why it's not funny.

The blog remains untouched these past two years, save the title. "Just One Monkey" doesn't seem to work, so I renamed it "Notes from a Monkey."

I have a large, loyal reader base*, so I ask you, large and loyal readers, help me understand: why doesn't this joke work?

http://notesfromamonkey.blogspot.com/

Please provide feedback in the comments section.

* In fact, my large loyal reader base comes from the future, where, for instance, someone from high school will accidentally stumble on this blog and be driven to read about my life in 2007. Thank you, dear old high school friend.

Thursday, November 01, 2007

Run DMC Alert!

It's tricky to rock a rhyme
to rock a rhyme
that's right on time
it's TRICKY!

Thanks, Mary Lucia!

Wednesday, October 24, 2007

I need a vacation

I was checking some HR information tonight on the corporate intranet, and I checked my accrued vacation time: 20 days 2 hours.

That's a month of vacation time.

I'm burnt out, and I have a month of vacation time. It's like starving in front of a pantry.

I have an intern working with me until the end of November, so I can't reasonably take a vacation until then. My wife has to work in December, so we can't do something extended until January, plus, we just can't really leave our dog for a whole month. At least, not yet.

Some quick math: let's say I wait the two months to take a vacation on January 1 and take a month of paid leave. By February 1, I'll have another five vacation days.

At this rate, I can retire on vacation time in 2110.

Friday, October 19, 2007

Pipes: damn that was easy.

As you might have suspected, I played with Yahoo Pipes today for the first time. I was really looking forward to working with it, because I've always enjoyed working with
Visio and Rational Rose. Of course I didn't expect to draw a UML diagram, but I really like the idea of entities flying around the screen, well connected to each other.

You might note that I didn't mention how much I liked working with dia, because I didn't like it. Sorry Dia. Anyway, where was I going? Pipes. Yes. As the title says: Damn. That was easy.

I built two pipes. Both read my FriendFeed feed. One only lets twitter messages through and one lets through everything else. Once I include those two feeds in Google Reader, I can separate reading Twitter messages from reading everything else.

Logically, I can continue by filtering something else into its own feed, such as people's Amazon Wish Lists, or I can filter them out altogether (I hate wishes!)

After filtering, I tried to perform some mild content mutation, but after 20 minutes, I decided to live without it, but I'm sure it's just a matter of time. Neat, neat, neat.

Thursday, October 18, 2007

Nacent FriendFeed thoughts

I received my FriendFeed invitation tonight. I'm excited!

After registering for my account, I was asked to set up my profile: registering a blog, my public linkedin profile, twitter account id, et cetera.

Then I was asked to connect to friends whose feeds I want to view. There are very few FriendFeed accounts at this time, which is reasonable, they need to manage growth. If you're my friend, go sign up for the Beta at http://friendfeed.com/account/new. Do it now. This post will be here when you get back.

Some thoughts:
  • The UI is very responsive and easy to use. There's a little bit of flakiness around the UI while setting up services, but I won't go into it here. This is not a bug report. (Update: About two minutes ago I noticed FriendFeed go practically completely limp, only to return with that very UI feature addressed! They're hard workers.)
  • There's a limit to the services you can set up. It only seems to allow me to register one blog. I have two (granted I almost never post to the other one). This specific case isn't a big deal, but a publish/subscribe API for custom services has got to be in their plans.
  • They presume a certain subset of available data from service providers. For instance, their LinkedIn service only informs you when someone changes jobs. How about when someone is endorsed?
  • It looks as if all their services get their data from unsecured public or hidden profiles, and nothing that requires passwords. This makes sense given the generally insecure nature of the web, but it limits FriendFeed's usefulness.
    • Would it be possible for FriendFeed to inform me when someone invites me to view their hidden Picasa Web album? This winds up as a subset of the authentication problem.
    • I want Facebook status updates!
  • FriendFeed lists several Google services. It's irritating that I have to register for each of them. This isn't FriendFeed's fault: each service requires a special URL. What would be nice though, is if FriendFeed grouped services in some logical way, either by organization (Google, Yahoo, etc.) or by service type (e.g. Photos, Videos, RSS, Social). This, I'm sure, will be addressed as the number of services grow. In the meantime the filter is very nice.
  • This can easily turn in to alot of data. I'd like to split my friends feed into multiple feeds. This looks like a perfect case for Yahoo Pipes.
    • Here's a thought about wanting to connect FriendFeed, Yahoo Pipes and authenticated services: let's say FriendFeed allows me to subscribe to a service that informs me when a first-degree LinkedIn contact creates another first-degree relationship. LinkedIn has a security model whereby you don't get to see someone's contacts unless you are a) logged in and b) have a first-degree relationship with that person. How can I safely pass that information into Yahoo Pipes to split apart for my RSS amusement? Looks like the internet Security Model of 1994 lives on.
  • Before I forget, FriendFeed allows you to create profiles for people you know that have not yet set up a FriendFeed account by saying, "I know Harvey. Here is his blog. Here is Harvey's Flickr Account." You know what they called this feature? "Imaginary Friends!" I love the name. Note to FriendFeed folks: I'd like to see my Imaginary Friends in the same place as my real ones. When someone for whom I have an Imaginary Friend subscription creates an account, how difficult will it be for me to reconcile them? What happens if the services I listed for my friend in their imaginary profile is not a proper subset of the services my friend lists for himself?
OK, I'm done pontificating. Sorry if I got any facts wrong, FriendFeed. Good luck!

Friday, October 12, 2007

Time moves on.


Today is Luciano Pavarotti's birthday. My father really loved listening to Pavarotti sing. He even went to meet Pavarotti on several occasions. There are photos in the "family vault" to prove it.

My father died in 1992. Since then, if I found an interesting reference to Luciano Pavarotti, I would tell my mother.

Today, Google provided a special logo for Luciano Pavarotti's birthday. My first thought was: I wish I could tell my dad. My next thought was: I can tell my mom. The one after that: I can't tell her either. My next thought: Who can I tell?

As it was said, So it goes.

In other news: Maggie is awesome. Today is my wedding anniversary. One of my very best friends is arriving to see me in five minutes. It's still a good day. Time moves on.

What's better than forgetting your anniversary?

Your wife, also forgetting your anniversary.

Happy Anniversary to you, my lovely wife! Let's forget our anniversary (and much, much more) for the rest of our lives.

Sunday, October 07, 2007

Thoughts on "Gears and the Mashup Problem"

... in which I meander through my mind while the TV is off.

Yesterday I watched a recording of a talk given at Google in the past month called Gears and the Mashup Problem. It's only 45 minutes long and worth the time. The speaker, Doug Crockford, was both interesting and funny. He is listed as "The world's foremost living authority on JavaScript". (Has JavaScript been around long enough to have a prior foremost authority that is no longer living?)

From the abstract:
Mashups are the most interesting innovation in software development in decades. Unfortunately, the browser's security model did not anticipate this development, so mashups are not safe if there is any confidential information in the page. Since virtually every page has at least some confidential information in it, this is a big problem. Google Gears may lead to the solution.
I'm not particularly interested in what leads to the solution because I write few, if any web applications. That's mostly because, as Doug said, writing Ajax applications (and subsequently, mashups) is really hard. But I do use them. Recently there has been a trend to write web applications that let you supply credentials (e.g. supply your AIM login/password, or gmail login/password, et cetera) which the service will use to access your contact list. This is a convenient and quick way to build your social network within that application. Unfortunately, it involves way too much trust. I did this just once, I supplied my login/password for one service, and have regretted it ever since. What if my password was stolen? Does trusting this service mean I am now more likely to trust a shadier, less well-established social networking site next time? The discomfort doesn't come from discovering that someone attempted to access my account illegally, but because it shows how easy it is to succumb to sacrificing trust for convenience. Every time I connect to the application to which I gave my login and password, the remnants of that trust appear. "You seem to know the following people," the application tells me. "Why not ask them to sign up for our service?" It makes me feel like someone knows my secret, like the day in high school when I had a hickey on my neck. (Do kids still do that?

Of course I changed my password immediately after I came to my senses.

Incidentally, this underscores Doug's point about the "Blame the Victim" security model, where the entire security model is the end-user's responsibility, and frankly, most people just don't understand that model.

So let's revisit this contact list vs. social networking problem. Doug suggests a mechanism through which my contact management application and social networking application can trade information through a limited conduit: neither learns each others credentials, and you give a more explicit approval: "Would you like to share your contacts from mycontacts.com with mynetwork.com?" That's definitely better, but not the ideal.

First, I need to trust that the contacts will only be used to identify if my contacts exist in my network. Is there an implicit step where mynetwork.com can use my contact list to build what I am sure is their gigantic map of everyone's relationship on the web? This, unfortunately, comes down to website privacy policies. Hopefully when you are asked to share contacts in the context given above, it should be a short step to a very clear usage policy: "These contacts will only be used to find existing matches in mynetwork.com. The relationships will not be stored. The email addresses will not be harvested." This would be much better than "To see how we use your information, please visit http://mynetwork.com/policies/privacy_policy.asp". But the truth is, at some point, you need to decide the level of trust based on criteria like the size and reputation of the data consumer, the risk of sharing such information, and your general comfort level.

Second, I don't want to give mynetwork.com access to all my contacts. I surely don't want mynetwork.com to have access to the email addresses of my niece and nephew. I don't want to scare the new woman I just asked out. (This is fictional, I am happily married, and hope to keep it that way!) This requires a contact management tool that allows you to accurately and easily categorize your contacts, and it means I get to pick and choose which contacts I allow mycontacts.com to share with mynetwork.com, either by group or by individual.) One small problem with this is that I really don't want to spend my life categorizing my contacts. If I wasn't going to organize music for my ipod, I'm surely not organizing my contacts for this. If only I could use the relationships stored on social networking site to help categorize my contacts on my contact management site. And there we have the feedback loop that requires bidirectional trust. There's the web, building on the web, building on the web.



There are some very interesting and related things associated with moving toward the next big integrated web:
  • Joel Spolsky is looking for the environment that will lead the next big leap forward for web applications.
  • Friendfeed is written by some Very Smart former Googlers, which serves as an aggregator of the several social networking services (including those where the network is secondary, like Flickr and PicasaWeb.) In this case, a trust issue remains. I haven't looked at Friendfeed yet, but I look forward to it.
  • I remember the launch of Yodlee in 1999. Back then it wasn't just a financial services aggregator (as it seems to be today), but a general purpose aggregator, an aggregator of bank accounts, credit card accounts, airline mileage accounts, car rental memberships, et cetera. Talk about trust. I haven't used Yodlee in many years, so I can't really comment on it, other than recalling a security policy that theoretically prevented Yodlee employees from accessing your trusted data. Granted, 8 years is old. It's as old as JavaScript.



Now I see that we are like the Egyptians that built the Great Pyramid of Giza. We're the Egyptians, and the huge interconnected social network is the Pyramid. (This isn't really anything new. Substitute 'World Wide Web' for 'Social Network', and you get the same thing. The underpinnings of this social network and mashup aspect is pretty much what seems to be The Semantic Web.)

Incidentally, it turns out that the Pyramids at Giza were not built by slaves, but by the Egyptian citizens themselves. Thus, "we are like the slaves that built the Great Pyramid at Giza" doesn't really fit, I can't liken us to slaves. This idea merits further study. Meanwhile, see http://www.touregypt.net/featurestories/gizavillage.htm and http://weekly.ahram.org.eg/2004/684/he2.htm

What do dogs dream of?

Oh my, my dog is dreaming that she's barking.

I can't tell if it's a bad dream or a good one.

It's so friggin' cute though!

"Woof Woof! Woof!" she dreams, but it just sounds like "weef weef! weef!"

The Slippery Slope of Television

... in which I document the history of my love-hate relationship with Television.

My mother always said that when I was a child, the only time I would actually sit still was when I was watching television. That was always true until I got a computer.

The punishment in our house for misbehaving always included loss of TV privileges. At dinner, we would watch TV, and if you were punished, you were forced to look away from the TV, and you were even called out for watching through the TV reflection in the window.

When I moved out of my parents' house, I took a TV with me. It had rabbit ears, a 13" screen, and dials for UHF and VHF. No remote control. No cable. It was all mechanical knobs and dials. I was actually very happy with seven channels plus VHF, but because I had no remote control, one night when I had the stomach flu I watched the same channel for 12 hours. It was channel 4, NBC. You are less than 35 years old if this shocks you.

I was 25 when I broke down and bought a 26" TV and a VCR, and got a subscription to cable. I still didn't watch tons of TV, but I was happy to have it. I bought my first stereo when I was 27. I didn't get it because I realized my life was missing a stereo, I got it because a friend worked for a stereo manufacturer and offered me a really great discount.

In 2000 I bought a DVD player, and only because my favorite movie was not available in VHS format.

In 2005, when my wife and I moved into our new house, we agreed to live without cable. I really enjoyed it. It was $60 per month we weren't spending, and while reception could occasionally be a problem (we often lived without CBS) we were pretty happy with it. Or at least, I was. My wife was not very happy with this. She missed cable. She kept threatening to get cable. I never said no, and I never got it for her. I figured, if she wanted cable, she could pick up the phone and do it, and that would be fine. But she never did it. I don't know why. Maybe because it just wasn't that bad, or maybe because she wanted to make me happy.

For her last birthday, I broke down and called the cable company. That's right: My wife's birthday present was a cable television subscription. I scored many, many points. This was not a thoughtless present.

Two months after getting cable, I bought a Tivo. Like the stereo, I purchased a refurbished unit for $100, which was a perfectly satisfactory price. Unsurprisingly, Tivo has changed the way I watch TV. For the last 45 days, I have watched approximately six hours of television a night. 9 of the last 14 nights I fell asleep on the couch while watching TV. This has been shocking, and a little scary.

Here's my observation about Tivo: the promise of Tivo is that you'll always have 'your favorite shows'. Truth be told, I don't think that's what Tivo does for us: pausing live TV is really awesome, and recording programs is also great, but the truth is there's still not that much I want to watch. At its essence, all Tivo really is is an insurance policy against commercials and channel surfing, and the monthly fee is the premium you pay to ensure against those two things.

Yesterday, we got a large screen TV: a Sharp Aquos 42" LCD TV. Again, I didn't get it because I felt this overwhelming need for a large screen TV, but rather, because I could get it for a good price. It's very nice, and I like it, but I don't have access to any HD channels. This started to scare me: do I now upgrade my cable box to be HD compatible? My Tivo is also not HD compatible. Do I also have to upgrade that?

Fortunately, no. I called my cable company, and they want $9 a month to upgrade my service to HD, and this would include, and I'm getting this from memory: CBS, NBC, ABC, KTLA (FOX), KCAL (CBS Local), KTTV (CW), TNT, BET, Discovery. 9 HD channels that I don't really watch to begin with. The channels we regularly watch are Bravo, Food Network, Sci Fi, Comedy Central, and a large number of movie channels (Encore, Flix, IFC, Sundance.) I'm sure HD is coming into this house, but not now. For now we seem to have finished adjusting our relationship with television.

Buying the new TV has sort of put me over the edge. I've been spending too much time in front of it. Sleeping through The South Park Movie last night was my sure sign, so for a short while, the TV stays off.

I love my TV. I hate my TV. I love my TV.

I'll proofread this later. Right now I'm taking my dog for a walk.

A final observation: The two times I bought a television occurred just after losing someone in my life. The first TV (and VCR) came about when I broke up with a girlfriend of 2 years. The second TV (and Tivo) were bought less than 3 months after my mother died. This is not a coincidence. I confess to having a sense of superior pride when I am not up-to-date with technology. Granted, both losses were very different, but I think they show that it takes some energy to not give in to consumerism, and when I suffer a loss, I either use consumerism to feel better, or I just don't have the energy to fight it.

Friday, September 21, 2007

What's better than typing on my computer?

It turns out that rubbing your dog's belly is way more satisfying than typing email.

Wednesday, September 19, 2007

I'm not into PwdHash

After reading Bob Lee's endorsement of PwdHash, I decided to give it a run. After a two-week trial period it I've decided to no longer use it.

I think it's got alot of potential, but I don't think it's for me, and the process seems to ahve some flaws. Here are my three main gripes about the supposedly improved support:
  1. I am supposed to trust that F2 translates my password. The only visual cue that my password is being translated is by watching the asterisks that represent characters in the password text box. See, the hashed password has (seems to have) more characters than the unencrypted password you supply. PwdHash replaces your password with the hashed one when you navigate out of the text box, and so, when you leave, you should see the number of asterisks grow. What if I failed to notice the asterisks change? It's possible that PwdHash could address this with a better user interface: one that displays a hovering window, perhaps.
  2. It lulls you into thinking you can use the same password on multiple sites. If I were to accidentally type my password unencrypted, it's easy to log in to my other services. This brings up my third beef:
  3. I would feel more comfortable if PwdHash let me contribute a third key to the algorithm that creates all passwords. Now, even if I accidentally forget to press F2 before entering my password, there's less of a chance that someone can get to other services. In that way, I can individualize the tool in such a way that it's mine. If someone else knows how PwdHash translates 'password' for www.gmail.com, they can find out how my password is similarly translated. I could get through this problem by making my common unencrypted password 'password_nnnnn', where nnnnn is this third key I talk about, but to do this I'm forced to make nnnnn something memorable.
Now I admit to be oversimplifying the problem to some degree, but the fact is, it just doesn't make me comfortable. I'd just prefer to eliminate the risk that a mistake on my part results in changing my password everywhere.

Tuesday, September 18, 2007

I miss Perl

Sometimes I get jealous when I read about dynamic programming, such as while reading this article by Neal Ford. I just wish I could feel that large applications could scale as well.

Don't get me wrong, I really miss coding in Perl, which resulted in code that more closely mapped to my thoughts. *sigh*.

Friday, September 14, 2007

Google Collections Library Released!

If you are programming in Java 5.0, I strongly encourage you to take a look at the Google Collections Library. I'm really impressed at the amount of work that went in to crafting this library.

This project would not have been the least bit possible without Kevin Bourrillion's hard work. Creating this massive library was his idea, and he managed to get several dozen engineers to contribute features, code reviews and tests. Kevin is also partly responsible for Google Guice.

I'm not going to bother going into any details about specific library features, I think Jesse Wilson is doing a fine enough job at that with his gentle introduction. I'm already drafting some posts to go on his blog.

(Updated)

Monday, August 13, 2007

Movie Review: Soapdish

I watched Soapdish tonight. I've seen it before: once in the theaters in 1991, and probably once or twice on cable.

It's really very funny. Sally Field is such a talented actress, that even though the rest of the cast is so talented, she stole all her scenes. On second thought, the only onewho stole scenes from Sally was Whoopi Goldberg. Whoopi had a supporting role that fit her perfectly. So basically Sally and Whoopi are the reasons to watch this movie.

This is odd, by the way, because there are other enjoyable performances by Kevin Kline, Robert Downey, Jr. and Cathy Moriarty, all of whom can really capture your attention. And their performances are that good, but I go back to Sally and Whoopi.

That is all.

Sunday, August 12, 2007

Google Reader Anchor Navigation

I am a big fan of Google Reader. I love the large number of keyboard shortcuts it provides. (Did you know the '?' key lists all of Google Reader's registered shortcuts?

I've written a greasemonkey script that registers three more keyboard shortcuts:
  • ] - Select the next hyperlink within the currently open item.
  • [ - Select the previous hyperlink within the currently open item.
  • \ - Open the hyperlink selected with [ and ].
These are particularly useful for reading sites, such as Lifehacker and ze frank's blog, that aggregates posts from many other locations. The aggregated summaries are nice, but I often like to jump to the referenced post.

I should also note that Google Reader also has the 'v' keyboard shortcut that lets you open the current item in a new window. So, these keyboard shortcuts can be considered the first derivative of 'v'.

Someone else wrote a similar script that takes a different UI approach that doesn't work for me. Plus I found it at near the end of writing this one. :)

Get Greasemonkey here before you install this new google reader navigation script.

Wednesday, August 01, 2007

Minor achievement

This past Monday I finally reached an important milestone in my life: I completed a New York Times Sunday Crossword puzzle.

I should note that this wasn't this past Sunday's puzzle, rather, it was from the week before. I should also note that by 'complete', I mean that I had three cells wrong, but I'm sure anyone who is not a weenie will be happy to include me among those that have completed one of these behemoths.

This is a nice personal achievement.

Sunday, July 29, 2007

Ethel Konigsberg, 1928-2007

My mother died last Saturday night.

That is to say, she suffered a cerebral hemorrhage, resulting in almost immediate brain death. Shortly after suffering the hemorrhage, she lost all her brain functions. She was kept on machines for a couple of days, allowing the entire family to congregate, and also to allow the New York State So-and-so board to legally declare her brain dead, and terminate the life support, at which point she ... I don't know. Died for real, I suppose.

If this sounds tragic, it is, in more ways than one. My mother was 79 years old. This may seem like an old age, but she was a vital, active person. In fact, the hemorrhage occurred mid-stride, moving from dinner to spending the evening with her boyfriend. My mother may have had a 79-year-old body, but she had a very active brain, and a body that kept her on the go. As my brother said, she had the body of a 60-year old. There was no pressing medical issue: in the last 12 years, she had been hospitalized maybe three times: once for back problems, once last month to have a stent installed, and once more, as I've described, at the end of her life. The many doctors (including those that are family friends) insisted that neither the stent nor other possible contributing factors had anything to do with the hemorrhage. The other thing every doctor said (including those that are family friends) was that she didn't know what hit her. When she died, the only ones that knew were absolutely everyone else. She died in motion.

I don't believe it was her time to die. She has a brother ten years older who, while primarily serving as my loving uncle, served as a sort of barometer to me. Since women live longer then men, and my mother was in good health, I expected unfailingly that my mother had at least ten more years of life in her. It turns out I was wrong.

It also turns out that the idea that you could die at any moment isn't just true, but is likely to happen to someone you know. I am amazed at the number of people who have told me they suffered a similar loss: "My friend died like this at 41," said the doorman of my brother's building.

Over the last four years, my wife and I have laid in bed and admitted secretly to each other about ourselves, "I'm so lucky that my mother is alive at this stage in my life. If she died, I don't know what I'd do." I guess at some point we'll pick up the pieces and start move on, but this is all so fresh, so if you asked me what I am going to do, I'll tell you: I have no idea what I'll do.

The relationship I have had with my mother in the last fifteen years, however, has been a fabulous one. We became friends as adults: this has given me a large part of my adult happiness. We talked often, and I didn't refrain from sharing things with her, so when she died, I felt like there was nothing left unsaid. When the nurse removed life support from my mother, and her body died, I sat with her. I told her who was visiting, what I was planning to do, some recent news, and some secrets that I had to keep from her. By doing that, I shifted from being hysterical to being complete. Mostly complete, that is. Grieving is a difficult process.

Then I realized there were some other final thoughts I had to share with her. I wrote those up as a eulogy, which I shared at the funeral the very next day. Now, almost a week later, I see there were other things my mother needs to know. I guess this will never end.

If you tell me she's in a better place, I'll say you're full of crap. She was in a fabulous place: full of life and happiness. She was with her friends and surrounded by love and hope. She was 79 years old, looking toward the future. The dirt isn't a better place for her.

While I'm being honest, please spare the "She's looking down from above" story. Unless you have some concrete proof, I'll take my comfort knowing she was one of the lucky few: she was happy and in motion, and she died quickly, with no knowledge, planning her next adventure.

One last happy facet before I conclude: this woman was loved, loved, loved, and the number of people that knew her and loved her was growing faster than the number of people that were forgetting her. That's not a bad way to go. Our job is to remember her.
---
If you are interested in making a contribution in the memory of my mother, please consider the Hebrew Free Burial Association, which can be found on the web at http://www.hebrewfreeburial.org. This organization gives destitute Jews a proper and dignified Jewish burial, and is an organization that was close to my mother's heart.

Saturday, July 21, 2007

Tesseract OCR, or basic PDF to text translation

Being a townhouse association president isn't as glamorous as it sounds. Sure, there's all that power from which comes an endless supply of women, and the opportunity to destroy people's lives.

Paperwork from my townhome's foundation was printed in 1974. In those olden days, I went to nursery school and nobody stored documents like these on a computer. My townhouse CC&Rs were sent to me via email, but as PDFs, mere photocopies of the original documents.

Thanks to an article on PDF-to-text translation and some patience, I managed to get my townhouse documents in text format.

Note that it's not great translation, but much better than typing it yourself.

Groklaw - Tesseract OCR How-To, by Dr Stupid; Scripts by Fred Smith

Wednesday, July 18, 2007

Zeno's Drinking Song

Repeat until out of beer.

One bottle of beer on the wall
One bottle of beer
If half of a bottle should happen to fall
A half of a bottle of beer on the wall.

A half of a bottle of beer on the wall
A half of a bottle of beer
If a quarter of the bottle should happen to fall
A quarter of a bottle of beer on the wall.

A quarter of a bottle of beer on the wall
A quarter of a bottle of beer
If an eighth of the bottle should happen to fall
An eighth of a bottle of beer on the wall.

Monday, June 25, 2007

Foolproof content assist for for-each

I recently figured out a strategy for guaranteeing that the Eclipse Java editor will infer the correct local variable while filling in one of the 'for' templates (for-each, for-each array, et cetera.) If it feels complicated, it's possibly because the refactoring keystrokes just aren't ingrained in your brain and your fingers.

After using the for- templates for a while you can get a feel for when Eclipse is likely to properly infer which variable over which you want to iterate. If it doesn't you can give it a great hint:

e.g.

List list = ... Map map = ... foreach{cursor}

{cursor} represents the cursor. Pressing ctrl-space, what will it infer?

The trick is to make it terribly obvious which variable you want foreach to choose for its completion. For instance, supplying a no-op statement that references an iterable object like this:
List list = ... Map<K,V> map = ... list; foreach{cursor}

will complete as
for (String string : list) { }

You can do really nice things with this like:
List list = ... Map<K,V> map = ... map.values(); foreach{cursor}

Now this doesn't *quite* infer correctly, so use Extract Local Variable (Ctrl-Shift-L) to make map.values a local variable:
List list = ...
Map map = ...

Collection values = map.values();
foreach{cursor}

which gets you
Collection values = map.values();
for (Integer integer : values) {
}

After that, use the Inline refactoring tool to inline the temporary variables.
for (Integer integer : map.values()) { }

Whee! Extract Local Variable and Inline are your friends.

Saturday, June 23, 2007

Rigatoni with Sausage

I lived in New Jersey for ten years, and I miss it terribly. I spent most of that time playing Ultimate Frisbee with a team that played (and still plays) in Brookdale Park. I spent eight years in Morristown and the last two were in Montclair, just a couple of miles from the park. About half a mile from the park are two locally famous ice cream parlors.

Applegate Farms not only makes fantastic ice cream, but they create a memorable family experience by serving outdoors barn-style (this also means attending their shop is slightly less attractive during winter.) They specialize in ice cream and other deserts, all of which are top-notch.

Holsten's, which is now absurdly famous, is an indoor parlor that also sells candy and has a lunch menu. I wouldn't necessarily go there just for ice cream, but if everyone wanted a meal followed by a sundae, this would be a great place to go.

There are other fantastic local ice cream shops without leaving Holstens' street (Broad Street). There's an unreal Gelato place (sadly I cannot find its name), and yet another fantastic and unassuming homemade ice cream shop called Magic Fountain next to the (ought to be) world-famous Nevada Diner.

None of this is really my point. I'm not trying to talk about ice cream and I'm not going to bring up the restaurants (but oh, how I pine for a dinner at Miele's in Verona, or absolutely anything from Casa Turano.)

My point is that baristanet posted a story where they interviewed the owners and employees of Holsten's about their newfound fame, and when I hear the young waitress speak in what I'll classify as the "Italian North Jersey" accent, all I want is to go home. That's my point. It was that, more than the video of my old neighborhood, more than the thought of satisfying my taste buds. It was the sound of their voices.

Now you will understand: one of the best parts of Miele's, besides the food (sigh), is my memory of the waitress asking "OK, who had the rigatoni with sausage?"

Friday, June 15, 2007

Maggie's Third and Fourth Day

Now before you go off thinking, "Will there be a post about days 5, 6, 7 and so on?" I promise you the answer is 'no.' But I think it's important to talk about the developmental changes in Maggie.

Maggie's third day was a much easier one. She started relaxing, and we did too. Every day, Maggie and I play tug-of-war. You can tell much about her temper these last days from tug-of-war. The first day she was frenetic, the second day she was going through the motions. Yesterday and today she was really enjoying herself. It's a good thing, this tug-of-war, because she's clearly a hunting dog, and I like knowing that there won't be an unresolved tension. She's been crapped-out tired every day, which suggests we're running her well.

Last night she came back up to the bedroom to sleep next to our bed.

As for being in the office, it seems to work OK. People love stopping by to visit Maggie. I think she is having trouble trying to find her place in the small room. I take her out, but not too much. I I'm sure she would like more space. (So would I!) We also need some decent toys and more of a cave-like space for the office. Basically, it seems to be working well.

Some other strange facts:
  • She doesn't like peanut butter, watermelon, or pizza crust, but she liked mildly roasted potatoes.
  • On the other hand, she loved the cookies my coworker Alison made. Peanut butter, milk and flour.
  • She won't eat hard treats or dry dog food (though we can mix dry dog food with a little canned food and she gobbles it up.) Someone suggested she may have dental issues. Then again, yesterday we thought she might have osteoporosis in her hind legs, but she sits just fine.
  • She doesn't mind if we leave for fifteen minutes or so, but...
  • She likes to bark a little more than we like. It's protective barking, which I can appreciate, but we would like to cut that off.

Today was the first day, when I came home, she wagged so much her butt shook. Yes-sirree, things are looking up.

Wednesday, June 13, 2007

Welcome, Maggie!

In big family news, we got a dog! She's a beautiful 8-year old named Maggie. We were told she's a Cairn terrier mix, but I'm also told that Cairn terriers tend to be much lighter than Maggie (who weighs in at 40 pounds.)

She's doing great. She's healthy (upon visual inspection). We still need to take her to a vet for a check-up.

Yesterday we had a very busy day. I picked her up at 10AM from the animal shelter and brought her home. She was so happy to be out of the shelter, and so excited to be in a home! She found the things that were her toys and scattered them all over the room. Then she ran up and down the stairs about 30 times.

I took her on several long walks around the neighborhood, including a visit to my office, which I would like her to feel comfortable with as soon as possible.

All day yesterday she wouldn't be anywhere that we weren't. If we moved from one room to another, she came with us. She slept at the foot of our bed, on the mattress made just for her.

Today, I took her to work with me once more, for a longer period of time. I practiced leaving her alone. The first time I left her was for 10 seconds. I stayed behind the door. She seemed fine, but a little scared. The second time, I left for 5 minutes, and when I returned, she was hiding in the corner. The third time, I left for one minute, and she seemed just fine. Beth picked her up at 11. By the time I got home, she was exhausted. She gobbled down her dinner, lied down, and went right to sleep. She hardly wagged her tail all day, and she slept as far away from us as she could, on the first floor by the front door. I wish she'd get up off the cold floor! Silly dog.

I think the first day, she was all caught up in the excitement of someplace new, and being out of the animal shelter, wanting to learn what was going on, and was afraid of being alone again. Today I think she is starting to realize that her home is new, and that her new family has foreign expectations.

These two days have been really exciting but also quite exhausting, but we're happy to have her in our lives.

Pictures coming soon.

Friday, June 08, 2007

How to get ahead in business

My first job after college was for a company that refused to give me business cards. I met clients often enough during my three years that I was starting to get embarrassed when I had to write my phone number on a piece of paper. I argued that the cost for business cards was worthwhile even if I paid for them myself (the cost being twenty dollars.) My presumption was that I could take half the business cards, spread them around all the local restaurants in their "drop your business card here and win a free lunch" fishbowls, and the cost would pay for itself.

Incidentally, have you ever wondered why they make fishbowls out of flimsy plastic? What kind of fish would be able to live in one of those things?

Sorry, I went off-topic. Without approval, I filled out the paperwork requesting business cards and submitted it for my director to sign, along with a note asking him how I should pay for them. I guess my director didn't feel like fighting with me any more, since he approved the order, without ever asking me to pay the twenty dollars. After scattering about a twenty cards in local eateries, I gave my resignation. Two days before I left, I got a call from my favorite local restaurant: my business card was selected among the dozen or so in the plastic fishbowl. That was the best free lunch I ever had.

The moral of the story: Always fight with your director. It may get you something for free!

Wednesday, May 16, 2007

Special Inline Editing Is Tricky

Special Inline Editing Is Tricky

I like the new feature in Eclipse 3.3 where you can perform a rename refactoring directly in the editor window. It seems like the Eclipse folks are experimenting with a new level of user-interface quality. Yay them.
There's still one tweak I'd like to see them make with this IDE. The Home and End keys still operate in their typical way. That is pressing Home navigates to the start of the line and pressing End navigates to the end of the line. Given that we're working within the context of a rename refactoring, I'd love to see Home and End have a different role, navigating to the start and end of the bound box. If you don't want that feature, use Home+Home or End+End to break the special use of Home and End.

I'm realizing this is a complicated problem, and it's easy to get an IDE feature like this very wrong. In the meantime, I'll log my enhancement request and give them something to think about.

Sunday, May 13, 2007

Launchy's Rough Start

I work on three machines nowdays: I run Linux for my office workstation, a Macbook Pro for my work-assigned laptop and Windows XP for my home computer (the one I share with my wife.)

When I got my Macbook Pro, my friend David urged me to get QuickSilver. I was reluctant to use it at first, now I can't live without it. And the way that I know I can't live without it is that I miss it terribly on my WinXP workstation. The Quick Launch toolbar is irritating -- who wants to remember what the iTunes icon looks like, and who can figure it out with six other icons on the Quick Launch Toolbar that also look like some sort of circle?

With that, I gave Launchy a chance. Launchy sounds like it might be the more sedate and incredibly more useful cousin of Clippy, the Microsoft Office pest. Unfortunately, Launchy promising start faded quickly. I launched it with a comfortable and predictable ALT-space. I typed "fire" to see if it had already located Firefox, but nothing appeared. I pressed escape to remove Launchy from view, which it quickly did (without Clippy's typical get-on-a-bicyle-and-ride-away fanfare.) A few minutes later, I pressed ALT-space again to find Launchy, but couldn't find it. Tsk-tsk. I figured I had somehow closed it. It didn't appear in the system tray, so I relaunched Launchy. Alt-SPACE, no Launchy. So then I decided the kill the task using the Process tab of the Task Manager. I found Launchy.exe. There it was, using 0% CPU and 11MB of memory. I tried to end the process, but could not. Launchy would not die. So where was it? It turns out that Launchy was sitting behind all other windows. That is, once I minimized all other application windows, I found poor Launchy, stiff and unresponsive, like a dead bee you find in the corner of your bookcase, grasping onto its last command from its master: "fire".


Fig 1. Dead Launchy.

Poor Launchy.

Generally this would be enough for me to abandon Launchy, but I'll give it another try because I'm willing to give the Open Source community a little more leeway, and I really am that desperate for QuickSilver.
Update: I had to do more than log out to give Launchy a fresh start -- the machine froze during log out. Very bad! One three-finger-salute and a log in later, and Launchy seems to have found Firefox. It hasn't completely blown its second chance. Good for us both.

Friday, May 11, 2007

Next Business Trip

This trip to JavaOne has had me reconsider what I need to make business trips a little easier. I hope these items are not bulky; we shall see.

A small power cord with at least two outlets.
Let's face it, you're always out of power. Carrying an extra laptop battery can be bulky. What I'd really like is a grounded cable that has no more than a six inch cord. It doesn't need any more than two outlets, but three would be nice.

With a diggie such as that, it's easy to get someone let me plug in to an outlet they are already using, or even better, make friends by letting them share my outlet! And if there is nobody to make friends with, I can always charge my phone at the same time as I charge my laptop.

A quick search found this ultra retractable power cord. It only has one outlet, but that's easy to fix with an add-on. Here's a four-in-one splitter that's a little too bulky for my taste. Actually, they've got much more; I'm sure I'll find something I like.

A small wireless hub
I'd love a small wireless hub with one additional network port. This gives me mobility where this is none, or share a network cable already in use (that's what the additional port is for). The only problem is weight. Even if the hub is small and light, it'll almost certainly need a bulky transformer. (Because this is for travel, I have a very low threshold for bulk.)

Throw in an extra, 12" RJ45 cable while we're at it.

Disposable earplugs
I had these for JavaOne, and they turned into a lifesaver -- since all the hotels were booked, there was little flexibility in my choice of rooms, so I was given a room next to the elevator mechanics. Throw two dozen of these puppies into a zip-loc bag and you're a happy sleeper.

In fact, I'm going to buy these in bulk (a hundred, say) and have them pre-packaged for my next several trips.

Of course, these babies are great for flights. Note that noise canceling headphones are not on this list - I have yet to find one I like, and I have yet to find one that doesn't survive my rugged use.

Another item not on this list, but I would recommend is a nice eye mask.

Small headphones
You know, the iPod variety. Not bulky. Functional. But most important, cheap. Ones that I won't feel about if they break, because the lifetime of any set of headphones I own varies independently from the amount of money I spend on them.

Travel size toothpaste
It's not just because of the DHS regulations that I want to bring travel-size toothpaste. They're more compact, and their use tends to be exhausted at the conclusion of my trip. I find that travel size toothpaste tubes last about four days, five if I am conservative. It makes sense to bring two tubes per trip, just to prevent a trip to the pharmacy.

Plastic envelopes
I'm going to purchase three of them, each sized to hold 8 1/2 x 11 inch sheets, each of a different color. I'll keep one reserved for expense receipts, and the other two for anything else I can think of. I want plastic envelopes rather than paper ones because they'll last longer.

Zip-lock bags
These are great for collecting whatever additional material you find: collected business cards, bottles of fancy shampoo (for the wife, I swear!) - I'm sure there's more.

Carabeaner
Wow, I finally found a use for conference swag. Sometimes you get extra crap that you just don't want to carry, like Yet Another Brand New Knapsack. Adding a carabeaner to your collection means hooking one to another.

Packing Plan
  • Create a small set of multiple travel packages with two tubes of toothpaste, zip-lock bags, 24 earplugs, q-tips, and whatever else I need.
  • Print out a list of singleton items that I need to include on every trip -- include things like the carabeaner, headphones, hub and power cords./network cable, you name it.

Thoughts on Quick Access

The new Quick Access feature for Eclipse 3.3M7 (aka CMD-3) is pretty slick. But I think it's not quite right.

There are two changes I would make:
  • Content Assist command completion If I type "comme" and the only commands left are matching on the first part of the phrase "comment", I should be able to complete the rest of the phrase. I guess I'm not exactly looking for the CMD-space type of completion, but the Emacs-style TAB completion.
  • Command parameterization: I'd like to be able to supply parameters to my commands. For instance, I'd like to have a command for "Show View", which would require you to follow with a parameter specifying the view name, either by its extension's name or id. I realize that Eclipse doesn't expose the ids to the users, and this becomes a sort of power-user feature. I'd say this is also a bit like Emacs.
You can see this is a short distance from scripting (a la, as you would guess, Emacs), which is what I really want.

Man I need to review Eclipse Monkey.

Thursday, May 10, 2007

Cribbage is awesome again

I really enjoy Cribbage. I've done a little bit of reading about strategy and so on, but basically I just like to throw the cards down and make lots of noise. My particular favorite is a variant four-player Cribbage invented by Patrick Bunch.

Rules for Traditional Four-Player Cribbage
I'm going to assume you know how to play two-player Cribbage, but you don't know how to play four-player Cribbage. Unless otherwise specified, the rules are just like two-player cribbage.

There are two teams of two players each. Teammates sit across from each other. As with traditional Cribbage, one player is the dealer. The dealer shuffles, and the cards are cut by the player to the dealer's right. The dealer deals five cards (instead of six) to each player. Each player discards one card (instead of two) to the crib. This results in four cards for each player, and four cards for the crib.

The player to the dealer's left leads the first card, and play proceeds to the left. Play proceeds like traditional Cribbage.

Cards are then scored in this order: Left Pone, Dealer's Partner, Right Pone, Dealer, Crib.

Deal moves to the left. Play proceeds.

Four-Player Cribbage, PBunch Style
Patrick introduced this variant that we'd no longer play without: In the space after the deal and before the discard to the crib, each player takes a card from his hand, and passes it across the table to his partner. A player may not pick up the passed card until he has passed a card himself. After both teammates have passed cards to each other, they can look at what they got, and discard accordingly.

So take a moment and consider some of the benefits:
  1. Every player is given an extra opportunity to make his hand work.
  2. If your hand is weak, but you have a 5, 6, 7 or 8, you can give it to your partner. In fact, we've observed that a tendency to break apart pairs in a mediocre hand can more often result in an overall benefit.
  3. Partners who pass the same card to each other can pause to see who will dump their passed card to the crib, preventing a free pair to the opponent, or ensuring an easy pair (or fifteen) for themselves.
  4. You can learn a little bit of information about your partner's hand by what he passes you.
    • Mind you, this isn't Bridge, so there's only so much you can learn.
  5. Scores tend to be a little higher than traditional four-player Cribbage, so games go a little faster.
Zach's Double Cribbage
This is a variant of the PBunch rules. Each player gets six cards. They pass two to their partner. Now, instead of dumping a card to a crib, players dump one card into one crib, and another card into a second crib, owned by the pones! This eliminates most of the advantage for being the dealing team, and you can save good cards for yourself.

The order of scoring is Left Pone, Dealer's Partner, Right Pone, Dealer, Pone's Crib, Dealer's Crib.

I haven't played this variant, so I can't really tell you if it's any good, but it seems a little too crazy for me. My one thought is that this tends in slightly lower-scoring cribs, but there are more of them. We shall see.