Category Archives: Mozilla

MoMo All-Hands: Day 3 (Data-Driven, Don’t Be Creepy, Italian-Chinese Dinner, Hipster-slamming)

At around 7:30AM, I rolled out of bed, cleaned myself up, and headed down to breakfast.

Breakfast that day was similar to the day before:  yogurt and granola.  Coffee and juice.  The cakes, however, had gotten the axe, and had been replaced by scones.

Very tasty.  A bunch of us ate breakfast out on the meeting room patio.  Once again, it was a gorgeous morning.

After breakfast, we all went inside to talk about data. Specifically, that we aim to be data-driven.  This means that if we’re making a big decision about Thunderbird, or any of the other stuff we’re working on, we should probably have some solid data to back up those decisions.  It’s a good idea; the road to bad design is paved with good intentions, and lack of data.

But how exactly are we going to get this data?  Are we simply going to monitor our users without their knowledge, like Big Brother, and study them like lab rats?  Are we going to collect reams of data about them secretly and silently in the background, without telling our users or giving them a choice?

Of course not, because that’d be evil.  And creepy.  Don’t track me, bro.

Instead, we will always ask the user if they’re interested in submitting data for study.  In general, our data collection is opt-in – and instead of tracking individuals, we aggregate the data, so that we never have a single person as a data point.  Nice.

A lot of ideas got tossed around about how we can ask the users for data, and what type of data we were interested in.  Some very interesting discussions took place regarding the Thunderbird “funnel” (the action path from visiting the Mozilla Thunderbird website, to downloading TB, to installing TB, to running TB, to making TB something commonly used).  Our funnel is pretty wide, but some website tweaks might make it even wider.  I’m excited to hear more about it.

After that, lunch.  Roasted chicken, mashed potatoes, veggies…once again, very tasty.  Cake for dessert.  We were getting pretty spoiled.

Following lunch, a bunch of us went outside to hear Andrew Sutherland talk about Wmsy – his constraint-based widgeting framework.  This was one of the talks that took place out on the patio, and the sun was blazing.  Much sunscreen had to go on, and I wish I’d brought sunglasses, because the image of the giant yellow pads of paper-on-easels that Andrew was drawing on was slowly being burnt into my retinas.  And then, sunscreen started getting into my eyes.  And yet, despite the blazing heat, the blinding sun, and the burning chemicals in my eyes, I was able to get a lot out of the talk.  Wmsy is pretty cool, and you should check it out.

After that, we went inside, and there was a bunch of GSoC talk.  Mentors talked about how it was working with GSoC students, and what kind of GSoC students we’d be looking for.  Then, a big brainstorm happened where we came up with potential GSoC projects.

[simage=767,288]

As a former GSoC student, I have to say, it’s a really worthwhile program.  I had an awesome summer doing GSoC.  Highly recommended.  Thumbs up, Google.

After that, the meetings were over.  I headed upstairs to talk to my parents and Emily on Skype for a bit, and then headed down to the lobby for dinner.  A group of us were eating at “Chow Mein”, an Italian-Chinese fusion restaurant.

It was pretty good. Fettuccine on one side of my plate, barbecue pork fried rice on the other, and some salad…a delicious and eclectic meal.  As an added bonus, while refilling our glasses, our waiter told us in excruciating detail about how he got pulled over for DUI on his birthday.  On that note, we had a fantastic dessert, and then left.

The sun was down, and we walked slowly along the beach back towards the hotel.  We stopped off at the beach-side patio to hang out a bit first.

[simage=766,288]

We raced Mai Tai umbrellas, and trash-talked hipsters.  It was probably the most hipster thing I did in Hawaii.

And speaking of hipsters (mildly NSFW):

Eventually, I made it back to my hotel room, and fell asleep.

MoMo All-Hands: Day 2 (Sunrise, The Meeting Room, Demos, Dinner at Uncle Bo’s)

Sunrise

I woke up after a night of fitful dreaming about long airplane rides, dip masquerading as hummus and missing socks.

I only had myself to blame for the socks.  Em had awesomely helped me pack two weeks worth of clothes into a carry-on bag, and the socks had been my responsibility.  Sigh.  Oh well.

It was early at this point.  Too early.  I glanced at the bedside clock…6 AM.  It’d been a long time since I’d been up this early.  And yet, strangely, I felt fully rested.

Fully rested, and excitedI was in Hawaii, baby!

I was determined to make the best of the early morning, and watch the sunrise.  So, I scrambled around, getting dressed – during which, I got a few shots of the sun starting to rise through my hotel room window.

[simage=736,288]
[simage=737,288]
[simage=738,288]

It was time to hit the pavement.  I threw on my sandals, and stepped into the elevator.  I tried not to think about my sock problem.  I figured I would spend most of my trip in sandals, so the lack of socks really wouldn’t be an issue until later on in the trip.

The hotel was pretty close to the beach, but the sun was coming up fast, and I didn’t want to miss it.  I started jogging, flew past the Hilton lagoon, and made it to the beach in time to take these shots:

[simage=739,288]
[simage=740,288]
[simage=741,288]
[simage=742,288]
[simage=743,288]
[simage=744,288]

And this video:

It was very peaceful and serene.

[simage=745,288]
[simage=746,288]

Before going back up, I took a few minutes to walk around the hotel.  There was a nice decorative fountain near the entrance, as well as a Kona Coffee shop.

[simage=748,288]
[simage=747,288]

I’m not a big coffee drinker, but apparently Kona Coffee is a pretty BFD.  Before I left home, my Mom asked me to bring a few bags back.  I didn’t have a chance on this morning though – the Kona Coffee shop was closed:

[simage=749,288]

I eventually made it back to my room to grab a quick shower and shave before the 9AM breakfast.

The Meeting Room

The hotel we were staying at was the Ilikai Hotel, which is featured in the opening to Hawaii Five-O.

The hotel didn’t want you to forget that either – they were pumping episodes of Hawaii Five-O through some flat-screens near reception, 24/7.

Along with the hotel rooms, the Ilikai was also providing a meeting room for the team for the week.  The meeting room was also where breakfast and lunch would be served.  It was a pretty awesome arrangement.

Here are some shots of the meeting room.

[simage=750,288]

We’ve got a patio outside too, in case we decide that we need to have a meeting in the sun:

[simage=751,288]
[simage=752,288]
[simage=753,288]

When I got to the meeting room, there were already a bunch of people there, and I went around and said a lot of hello’s.  Once again, a lot of names and faces flew by, and it was hard to keep them all straight in my head.

Breakfast was yogurt with granola, and what appeared to be banana bread.  Delicious.

After breakfast, David Ascher gave a talk about the mission of Mozilla Messaging, and what we’d accomplished in 2010, and what we were aiming to accomplish in 2011.  There was a nice and easy, accessible vibe in the room, and I don’t think it was just because everybody was wearing Hawaiian shirts – the whole crew just seemed to gel that way.

After the talk, we more or less figured out the schedule for the rest of the week.  That day, we’d be doing a bunch of demos.

Demos

The demos were pretty cool.  Blake did one on the account provisioning service that he’s been working on for Thunderbird:

And then showed off some more experimental work that he and a few others been doing on a project called Thunderbird Air.  Think of Thunderbird Air as a jam session for ideas about messaging interfaces.  It’s pretty cool.

Then, we got a demo of F1, MoMo’s shiny new Firefox add-on that makes sharing stuff easy. It’s pretty badass.  Here’s an early video showing off what F1 does:

After that, Andrew Sutherland gave a talk on the new widgeting library he was working on called WMSY.

Afterwards, there was a big talk about mail storage with David Bienvenu – one of the original developers of Thunderbird.

After that, it was lunch break.  Salad and sandwiches.  Very tasty.  There was also some peculiar bread that had a sweet taste and was blue/purple inside.  Very interesting.

After lunch, people just hacked on their laptops for a bit, and chatted.  Smaller discussions about other projects broke out.  People went out onto the patio for sun.  Very relaxed and casual.  Eventually, someone plugged in the XBox and the Kinect, and we watched David Ascher and Dan Mosedale do some extreme white-water rafting.

Dinner at Uncle Bo’s

Eventually, things wound down.  Old habits die hard, and the group started to fold around 5PM.  At that point, I packed up my stuff and headed back to my room.  I talked to Em on Skype.  I got ready for dinner – I’d be meeting the rest of the group downstairs at 6PM.

[simage=754,288]
[simage=755,288]

I showed up at the lobby just in time for Sancus to tell me that we were meeting at 6:30PM instead of 6PM.  That gave me just enough time to run around and try to grab a few photos:

[simage=756,288]
[simage=757,288]
[simage=758,288]
[simage=759,288]
[simage=760,288]
[simage=762,288]

I got back to the lobby just in time to meet the group as we started to head to a restaurant called “Uncle Bo’s“. Apparently, it’s pretty well known in Hawaii.  The food was eclectic, but tasty.  I spent most of dinner talking with James Burke, John Hopkins, Mark Banner and David Sifry about things like British humour, Top Gear, and trolling Nigerian prince scammers.  Good times.

Watermelon sorbet for dessert.  Delicious.

I didn’t take photos during the dinner (at this point, I still didn’t know everybody, and would have felt weird photographing them), but I know Roland Tanglao did.  Here are a few:

[simage=763,288]
[simage=764,288]
[simage=765,288]
[simage=768,288]

Stuffed, we cabbed back home.  Some of the team was headed to a patio on the beach, and I tagged along.  As some live music played, I talked school and science fiction with Andrew Sutherland and Gozer.  I also found out that Gozer is a pool shark, and we decided to find a time to hit a pool hall sometime over the week.

At some point, a wave of exhaustion hit me, and I decided to head back to the hotel.

I made my way back to my room, jotted down my daily notes, and nodded off.

Click here to go back to Part 1.

MoMo All-Hands: Day 1

A Delicious Flight

After waking up, cleaning up, and eating, I was more or less ready to go.  Blake was stopping by around 11:30AM with the airport taxi, and I had about an hour to myself.  I decided that now would be a wonderful opportunity to purchase some flying snacks from the nearby convenience store.

Moments later, I was browsing the shelves.  I grabbed some granola bars, and some raisins.  On my way out, I saw some flatbread, and was immediately reminded of the time that my friend Doug offered me some flatbread with roasted red pepper hummus on it.  And I remembered that it was delicious.  Immediately, I was hit by a craving, grabbed the flatbread, and went to go find the hummus.

Eventually, I zeroed in on the hummus section.  Unfortunately, the tub of roasted red pepper hummus that I found was about the right size for a whole family, and I thought that’d be a bit of a waste (since I wasn’t sure I’d be able to refridgerate it upon landing).  So I dug around in the shelves until I found a smaller tub, grabbed it, paid, and left.

Now, I know what you’re thinking:  “Mike – this minutia is really of no interest to me.  Am I really going to have to hear about the food you bought and ate?  Is this how these posts are going to go?”.  Just rest assured, I’m bringing this up for a reason.  The hummus comes into play later.

Blake arrived, I hopped into the car, and we were off.  We compared snacks:  Blake was packing some awesome-looking homemade banana bread with chocolate chips.

It was going to be a delicious flight.

A Newbie Goes Through Security

It’d been a little while since I’d been through airport security, and I had forgotten some of the moves.  I did my best to follow Blake’s example – I pulled out my laptop to be screened independently.  I tossed down my jacket.  I lined it all up all neat and tidy for the little luggage car-wash to scan it.

Soon, it was my turn to walk through the metal detector.  In front of me, Blake had sailed through and was already getting his stuff off of the conveyer belt.

I walked through the gate.  BEEP BEEP BEEP BEEP.

“Sir, do you have anything in your pockets?”

Oh yeah.  I had everything in my pockets.  Wallet, keys, cell-phone, belt, watch, I’d forgotten all of it.  So there I am, scrambling to void my pockets of their contents, and tossing them into a little bowl to be scanned.

Security was not impressed.

After an extremely thorough wand-scanning, I was eventually let through.  I gathered my stuff up, and hurried over to Blake.

The Storage Seat

We reached our terminal without incident.  We had an hour to kill before boarding, and chatted about the upcoming meeting, science fiction, Ricky Gervais, video games.  Boarding was a piece of cake.

Although we had booked our tickets seperately, somehow, our seats were in the same row.  There was a lone seat in between us.  The plane filled up…and filled up…and the seat remained empty.  Suddenly it dawned on me:  Blake and I were probably about to get a free storage seat between us.  Awesome-sauce.

I became so excited about the middle seat that I was starting to sweat everytime someone else came onto the plane.  One or two stragglers would saunter on, and I was sure the jig was up.  But somehow, someway, it didn’t happen.  The storage seat was saved.  It immediately became home to a host of overflow items.

Take-off

It was at this point that the captain came on the horn to tell us that there was a problem.  During the safety check, he found out his oxygen mask wasn’t working.  Maintenance would be sending a part over, and it’d take somewhere around 30 minutes to get it all sorted.

30 minutes later, we were underway, and hurtling down the tarmac.  Eventually, the seatbelt sign was turned off.  I reached for my book.  It was going to be a long flight (approx 6 hours).

That’s when the flight attendant announced that the water wasn’t running in the front bathroom.  So we were down to one bathroom.  The girl across the aisle from me groaned audibly.

Moments later, we found out that our in-flight movies were not working.  The same girl groaned even louder, whipped out her cellphone, and began texting furiously.  I was reminded of this Louis C.K. bit on Conan…

It was an uneventful flight.  Blake and I chatted a bit, and then I read, and he listened to music.  There was a Mythbusters marathon on the on-board television, so that was entertaining.  I learned today that if a diver in one of those old-school scuba suits is down 300 feet, and suddenly has his air supply cut off…the waterpressure is strong enough to compress all of his organs into his helmet like a human meatball.  Gross. Thanks Mythbusters.

Landing, and the Hummus Incident

Landing was no biggie.  The captain came on the horn again to tell us that they had to cut power the plane in order to get the bridge attached to us.  As the lights went out, I could see the light of a cellphone illuminate the face of the girl across the aisle.  Texting commenced at a furious pace.  I don’t think she was very happy with the flight.

Next, Blake and I meandered our way to U.S. security and customs.  Along the way, we helped a mother and daughter find their New Zealand flight.  While in the line-up, I realized that I was still carrying a bottle of water that I’d purchased in the Toronto airport.  And it was still more or less full.

To avoid embarrassment, I chugged it back.  The whole half-litre.  Dazed from over-hydration, I tossed all of my gear, pockets and all, upon the security conveyor belt like a boss.  I was determined to do this like a pro, and gave Blake the “I know what I’m doing this time” eyebrows.

Shoeless, beltless, pockets emptied, I passed through the metal detector like a marathon runner at the end of a race.  Not a sound from the machine.  It was glorious.

“Step over this way, sir”.

I was suddenly redirected to security, and told to empty my backpack.

As the security guard rummaged, my hummus fell out, and wobbled onto the table.

Suddenly, all eyes went to the hummus.

“Sir, what is this?”

“It’s hummus.”

“No, it’s not.”  I looked closer.  Damn it, I’d been duped by similar packaging.  It was full-blown dip, not hummus.  So much for healthy snacking.

“Oh, sorry, it’s dip.  Not hummus.  Dip.”

Pause.

“Sir, I’m going to have to ask you to stay right here.”

I had started to sweat a little.  Meanwhile, Blake was getting his shoes on, and was eyeing me curiously.

“It’s the hummus,” I said.  He mouthed “Oh”.

3 or 4 minutes later, I was shuttled over to an official looking desk, where an official looking guard was presiding over my very fraudulant hummus.

“I thought it was hummus.  You can keep the dip.  I don’t want to the dip.  You can have the dip.”  I kept saying.  I was worried that they thought I’d lied to them while calling it hummus.  Or was there some sort of dip embargo?  What the hell was going on?

“I don’t want the dip,” the tired looking employee said to me.  He had a thousand-yard stare going on.  This guy was not a fan of his job – at least not today.

“Your boarding pass says that you came in from Toronto.  They should have stopped it at security over there”.  He jabbed a finger at the dip.  “This is over 50 millilitres of liquid.  They shouldn’t have let it through.”

I made a weak attempt at humor by mentioning that the dip wasn’t exactly a liquid, and was more like handcream.  He didn’t seem amused.  I cut the crap and shut my mouth.

He then spent 5 minutes collecting all of my personal identification, and taking photos of me with the security camera.  He assured me that I wasn’t in trouble, and that, in fact, Toronto airport security was in trouble.  I remarked that I hoped nobody was going to lose their job over this.  He grunted, handed me my boarding pass, and wished me a good day.

Dip-less, I walked back to Blake, gathered up all of my stuff, and we started walking towards our departure gate.

A Chance Encounter

We had stopped by a Tim Hortons to grab some food, when Blake nudged me.

“Come this way,” he said.  I followed him back to the Tim Hortons line-up

“Mike Conley, meet David Ascher.  David Ascher, meet Mike Conley.”

So it turned out that David Ascher, CEO of Mozilla Messaging, and my new boss, was taking the same flight with his wife.  We said hello, and chatted a bit, and then headed towards our gate.

Huh.  What were the chances?

We boarded without incident.  Blake and I weren’t sitting together on this flight – I was sitting next to some charming older ladies who were slamming back the in-flight alcohol like it was going out of style.

In Hawaii

It was a hard leg of the flight.  After approximately forever, we landed.  This was at about 10PM Hawaii time, or 3AM Toronto time.  At this point, I’d been awake for about 19 hours.  I was exhausted, groggy, and probably dehydrated.

A section of the airport terminal had no windows.  It was warm out, but not uncomfortably so.  It was a bit humid.  I saw palm trees in the shadows.

Eventually, David, his wife, Blake and myself were able to hail a cab.  We whisked through the Hawaiian night.  I remember thinking that the outside part Hawaii we were driving through seemed like an interesting mix of industrial and tourist.  Kind of like if Niagara Falls and Hamilton were smashed together.

Finally, we pulled up to our hotel.  After checking in, my body had pretty much given up.

It’s funny how 19 hours of just sitting still in a chair will exhaust you.

Before reaching the elevators, we ran into a few more members of the team who’d arrived before us.  There were quick introductions (too quick – I’d have to ask for names again later on), and then we were up to our rooms.

Inside my room, I dumped by bag, plugged in my laptop, and sent a few e-mails to let people know I had arrived safely.  I prepared for bed.

As I rummaged through my luggage, something was bugging me…

“Hm…let’s see…shorts, pants, underwear, shirts…”

My eyes went wide.

No socks.

I hadn’t brought socks.

Click here to go to Part 2.

Click here to go back to the introduction.

MoMo All-Hands. In Hawaii.

It’s been a little while since I posted.  Well, I’ve been busy.

In Hawaii.

That’s right.  Hawaii.  Mozilla Messaging just sent the entire team to Hawaii for an all-hands meeting.  And, believe it or not, we got a hell of a lot done.  It’s amazing how productive people can be in shorts, Hawaiian shirts, and sandals!  No joke!

It was also an opportunity for me to meet my new teammates.  It’s a fantastic group, and a very warm welcome.  They’re smart, committed, quirky, and hilarious.  I think I’m really going to enjoy working with this team.

Anyhow, I had a great time, and learned a lot.

And I took notes.

Here’s part 1…

Day 3: Stream of consciousness

So, I just started my day off with a big bowl of Apple Cinnamon Cheerios and some fresh orange juice, c/o Mozilla Messaging.  Thanks, team.  😀

Another great thing about Mozilla is that, since its spread out around the world, somebody is awake and working pretty much 24 hours a day.  That means if I write a bunch of code and go to bed, there’s a chance that when I wake up the next morning, the code review is done and I have some feedback on my next steps.

And that’s more or less what’s happened at the start of today.  That add-ons manager grouping feature I was working on for Firefox got looked at in the night, and I got some feedback on some changes I can make.  Awesome.

So here’s the scoop:

First off, a conversation got started regarding where add-ons with pending installs or uninstalls go.  The answer:  pending installs should go into the group they’ll be in once the install is complete, and pending uninstalls should stay in the group that they were in when the install happened (in order to prevent the add-on from jumping around in the list).  That’s good – that makes my job easier, I think.

With regards to implementation, I don’t think my nifty Shwarzian Transform is gonna fly:

I don’t think that this is the right approach to take here. Instead the more straightforward way is to just make sortElements accept an array for aSortBy (and update all callers to pass one) of fields to sort by in order of preference. If the elements match by the first field then move onto the second and so on. For the non-search list views use a specially named field “uiState” and then use your function as the comparison function for that field.

(from one of my reviewers)

So this approach involves me changing a bit more code.  See, my original approach was to try to change as little as possible.  I guess that’s just me being the “new guy”, and trying not to rock the boat.  But clearly, they want me to go deeper.  I’m happy to oblige!

But there’s a bit more complication.  According to the Bugzilla page, this bug I’m working on depends on this other bug, where somebody else is also tinkering with the sorting functions.  That means I have to be uuber careful, and make sure to base my work off of their patches.

In particular, it looks like this patch is going to be altering the sorting tests, and removing the ability for Firefox users to sort add-ons by anything besides the add-on name.

So what I’m going to do is download and apply this patch, and then start basing my work off of it.  Each time the patch is updated in Bug 623207, I’ll just re-base my work off of it.  Nice.

Ok, so first of all, I wipe out my old work using hg strip (using Blake’s handy script to find the HEAD revision number of that branch).  Next, I grab the patch for 623207, and use patch to apply it.  Then, I use pnew to create a new pbranch with that change, and then create another pbranch on top of that.  That second pbranch is where I’ll do my work.  If/when the patch to 623207 gets updated, I’ll update the first pbranch, and then merge it into the second.  Awesome-sauce.

Argh.  It seems I have to recompile in order to get that 623207 patch to work.  And not an incremental compile either, since “make” doesn’t seem to do much in toolkit/mozapps/extensions.  *sigh*…compiling

Just stopped by UofT to drop off my old keys, and get my old computer wiped.  Stopped by and talked to Karen, and helped two new MarkUs students.  Kind of bitter sweet moment.  Goodbye school.  It was a long battle.  Well played.

I’ve finished a draft of my add-on grouper/stratifier.  Now I’m going to check out these tests.  Without my change, the tests in browser_sorting.js all pass.  With my patch, 3 fail.  Ok, so I think I’ve found the right tests.  Lets see whats up…

Ok, it looks like the tests were trying to call my new sorter, and didn’t know that it had to pass an Array instead of a string.  Fixed that, and all tests are passing.  Sweet.

Now let me try all of the extension tests…ok, without my patch, 10 fail.  With my patch… OH SHIT.  194 failures.  That’s a big deal.

Ok, I think I’ve fixed those tests.  But now when I run the extension tests, one of the tests seems to take forever…what’s the deal?  Turns out, this test does this periodically, even without my patch.  Hrm. So I guess I don’t have to worry about it.

After a few runs, I’ve got the same number of passing tests as there were before my patch:  only 10 fail.  Nice.

So now I have to try to write some new tests.

Suite!  Tests written.

It takes me a while to run the Firefox Mochitests on my machine.  If I were to do them all, it’d probably take at least an hour.  Running the add-ons manager tests takes about 5 minutes.  And in either case, I can’t use my machine, because Mochitest needs me to keep focus on Firefox while its running the tests.  Basically, this means if I want to run the tests, I give up my machine, and go snack on something in the kitchen.  That was cool at first, but after a while, giving up my machine for 5 minutes seemed pretty lame.

So, luckily, there’s a machine in the office called TheFlash, and, as its name suggests, it’s SUPER fast.  Like, lightning speed.  Compiling Thunderbird from scratch?  7 minutes flat.  Jeebus.  Anyhow, Blake got me an account on TheFlash, and I’ve pushed my changes to a Firefox instance over there.  Firefox is compiling, and then I’ll try out my tests over there.  Awesome.

Tests pass!  Lovely.  And Blake just took a look at my code and showed me a neat trick:

So I’ve got an Array of uiState’s, like so:

const UISTATE_ORDER = ["enabled", "incompatible", "disabled", "blocked"]

And I wanted to sort a collection of these values in order that they appear in that Array. So something like:

["disabled", "disabled", "blocked", "incompatible", "disabled", "enabled", "enabled", "blocked", "disabled"]

# Would become

["enabled", "enabled", "incompatible", "disabled", "disabled", "disabled", "disabled", "blocked", "blocked"]

(this sort of thing is useful if each of those original entries is associated with something like, I don’t know, a Firefox add-on…)

In Javascript, we use a sort command, and we pass a function to do comparisons.  Normally, I’d do something like:

function uiStateCompare(a, b) {
 if(UISTATE_ORDER.indexOf(a) < UISTATE_ORDER.indexOf(b))
   return -1;
 if(UISTATE_ORDER.indexOf(a) > UISTATE_ORDER.indexOf(b))
   return 1;
 return 0;
}

But there’s a more concise way to say this:

function uiStateCompare(a, b) {
  return (UISTATE_ORDER.indexOf(a) - UISTATE_ORDER.indexOf(b));
}

Which makes total sense.  If UISTATE_ORDER.indexOf(a) < UISTATE_ORDER.indexOf(b), then of course the difference is less than 1.  Anyhow, I thought this was a pretty neat trick.  Thanks Blake.

Alright, patch is scrubbed and ready for posting on Bugzilla….here goes!

Ok, patch posted.  Home time.