Archive for May, 2008

Vote! How to Detect the Social Sites Your Visitors Use

Wednesday, May 28th, 2008

One of the great things about the web is the relative ease with which one can set up a new service. In social bookmarking alone with have Del.icio.us, Digg, Facebook, Fark, Mister-Wong, Newsvine, Reddit, Technorati, Slashdot, and StumbleUpon, to name a few. That’s great for competition, and that’s great for users, but it’s not so good for bloggers and content creators.

What are you to do if you want readers to promote your content? Kevin Rose, of Digg, put it succinctly: “Encourage your visitors to submit their favorite stories directly to Digg [with a Digg badge].” Not everyone uses Digg. You have to decide on which bookmarking site, if any, to dedicate your precious screen real-estate. It’s a hard choice. If you choose poorly your reader won’t vote—it’s not a single click coupled and out-of-sight means out-of-mind—and your content losses its chance to make it big. You have to choose your horse wisely.

On the other hand, if you take the bird-shot approach, it overloads your reader with branded badge after branded badge. It turns your page into the village bicycle. Not pretty.

So many social bookmarking sites!

Nobody seems to have solved the problem yet. Lifehacker, for instance, uses a single Digg badge on their long articles, but they also list a couple of the top social bookmarking sites on every post. Wired takes the total shotgun approach, and they own Reddit.

There has to be a better way.

If you could detect which social bookmarking sites your reader uses, on a per-reader basis, you could display only the badges they care about. But you can’t know that because the browser secures the user’s history, right?

Wrong.

I know that you visit: . It’s a bit scary, I know. I’ll come back to how I know in a second. We can use this information to only display one or two badges that we know the reader uses. It solves the which-badges-to-display problem.

SocialHistory.js

Today I’m releasing SocialHistory.js, code which enables you to detect which social bookmarking sites your visitors use. Here’s an example of how to use it:

<script src="http://aza.googlecode.com/svn/trunk/SocialHistory/SocialHistory.js"></script>
<script>
  user = SocialHistory();
  var visitsDigg = user.doesVisit("Digg");
  var visitsSlashdot = user.doesVisit("Slashdot");
  var listOfVisitedSites = user.visitedSites();
</script>

SocialHistory.js cannot enable you to see all of the user’s history. It has to ask, 20-questions style, if the user has been to a particular URL: It’s hit or miss. SocialHistory.js has a big list of the most popular social bookmarking sites which it checks against. To see the list of sites, you can do:

user.checkedSites()

SocialHistory.js can also check other sites. For instance, if you want to see if your reader has visited any of the blogs I write, you’d do the following:

moreSites =
  {
    "Aza": ["http://humanized.com/weblog", "http://azarask.in/blog"]
  };
user = SocialHistory( moreSites );
alert( user.doesVisit("Aza") );

How Does It Work?

How does SocialHistory.js know? By using a cute information leak introduced by CSS. The browser colors visited links differently than non-visited links. All you have to do is load up a whole bunch of URLs for the most popular social bookmarking sites in an iframe and see which of those links are purple and which are blue. It’s not perfect (which, from a privacy perspective, is at least a little comforting) but it does get you 80% of the way there. The best/worst part is that this information leak probably won’t be plugged because it’s a fundamental feature of the browser.

Vote For Me, Where You Care

Enjoy cleaner, more aware pages. Gone are the medieval days of badge spamming!

P.S. Yes, I do feel a bit dirty for using this information leak. At least I’m using it for a modicum of good. My cleaner half raises the cup to hoping that Dave Baron can stop the leak in Firefox by vanquishing bug 147777.

What If… It Was Easy To Write Firefox Extensions

Friday, May 23rd, 2008

Writing extensions is labor intensive. Even as a veteran web developer, I feel trepidation at the thought of diving into the boiler-plate code, wading through the XUL world, and restarting Firefox uncountable times. There are tools out there to mitigate some of these problems—like Ted Mielczarek’s Extension Wizard, and Mark Finkle’s FUEL—but they feel like fresh frosting on a stale, left-out-since-last-Thursday birthday cake.

Developer extroadinare, Atul Varma, said it best: “I hereby classify restarting Firefox during development as a ‘barbaric measure’”. Of course, restarting Firefox to install extensions is like-wise barbaric.

As a simple learn-to-write-extensions project, I decided to make a Gmail notifier. All I want it to do is and notify me—in a humane way—when a new email came in. As I dug into the the extension world, I found myself day-dreaming: What incredible places could the web go, as an open platform, if extending the web was as easy as writing for the web? What if my knowledge as a web developer was all I needed to extend Firefox? What if writing a Gmail notifier was as easy as:

function gmailNotifier() {
  var url = "http://mail.google.com/mail/feed/atom";

  ajaxGet(url, function(rss) {
    var firstEntry = $(rss).find("entry").get(0);

    var newEmailId = $(firstEntry).find("id").text();
    var subject    = $(firstEntry).find("title").text();
    var author     = $(firstEntry).find("author name").text();
    var summary    = $(firstEntry).find("summary").text();

    if( newEmailId != globals.lastEmailId ) {
      var title = author + ' says "' + subject + '"';
      displayMessage(summary, title);
    }

    globals.lastEmailId = newEmailId;
  });
}

function onStartup() {
  globals.lastEmailId = null;
  setInterval( gmailNotifier, 15*1000 );
}

Well, it isn’t that easy. Yet. *wink*

Intuition, and the Monty Hall Problem

Thursday, May 22nd, 2008

Statistics is hard. It’s one of those fields, where your intuition seems to take you gently and seductively towards safety, and then you wake up in a bathtub full of ice, missing a kidney. Interface design is often the same way (but, for once, that’s not what I’m writing about). When we say that we find something “intuitive” it means that we have seen something like it before—we are saying that it is familiar. The thing with statistics is that similar looking situations can behave very differently.

The first time I had this point driven home was when I was presented the Monty Hall problem. Posit: You are on a game show and three doors stand before you. Behind two of the doors lies nothing, behind one door is a pile of cash. The game begins by you picking one of the doors. The host (Monty Hall) then opens one of the two remaining doors, revealing one that is empty. Then it’s your choice: Do you stick with the door you originally picked, or do you switch to the other door? Does it matter?

Intuition says is that it doesn’t matter. It’s 50%-50%. It’s the same as throwing a coin—the money is in either one door or the other. This kind of thinking will lose you a kidney. You’ve been tricked by “intuition” to not got suckered by the gamblers fallacy, only to get suckered by something new.

It’s best to switch doors. In fact, switching doors will make you win twice as often as staying. While I’ve been able to prove that for a long time—by enumerating all possible outcomes and counting&mash;it never really clicked in my head why it’s true. It never became familiar. It never became intuitive. Until a couple days ago. Here’s the explanation the occurred to me (in the shower, as always) that made it all make sense:

The chance that you pick the right door on the first choice is 1/3: there are empties and one prize. Conversely, that means that there is a 2/3 probability that prize is in one of the other two doors.

3 closed doors.

If you could open the other two doors, see which ones contains the money, and take it, you would have clearly do that. That’s twice as good as getting to open only one door! Well, when Monty opens one of those doors that doesn’t contain the prize, he’s effectively giving you that ability: there is still a 2/3 probability that the prize is behind the set of doors you didn’t pick.

It’s obvious, now, that switching will give you a 2/3 chance of winning. By opening a door that doesn’t contain a prize, Monty has effectively concentrated that 2/3rds probability into the one remaining door.

This way of looking at it makes it really easy to calculate similar problems. For example, take the 5 door case: you pick a door, Monty opens 3 empty doors, and you have to choose if you should switch. Your first pick has a 1/5 chance of getting the prize, which means that there is a 4/5 chance that it is in the set of doors you didn’t pick. Monty opens 3 of those 4 doors, which means that 4th unopened door takes that full 4/5 probability. Thus, switching is 4 times more likely to win than is staying.

What happens if Monty only opens two doors, instead of three? Should you switch? It’s easy to figure out. You still have 1/5 chance of getting the door on your first pick. The other doors still have a 4/5 chance of having the prize. He opens two, which means that 4/5 probability is spread equally over the remaining two doors. Thus switching will give you a probability of half of 4/5ths, which is a 4/10ths probability of winning. That’s better than 1/5 chance of winning, so switching is better.

What’s the moral of the story? That intuition is malleable and that statistics is hard, until you find the right way of framing the problem. And that’s a general rule.

Geolocation Redux and a JS Library

Thursday, May 22nd, 2008

After the excellent feedback I got on my last geolocation blog post, I’ve updated the proposed geolocation API. More importantly, I’ve also created a pure Javascript library which you can use to start playing around with geolocation before we actually get it into the browser. This library provides exactly the same API as would be provided by the browser. Although it can’t offer GPS-quality data, it does provide a decent city-level geolocation based on your IP. You can get the library here, and there’s also a no-frills demo.

For quick hacking you can just include the following in your head tag.

<script src="http://azarask.in/projects/geolocation/MockGeolocation.js"><script>

The best way to get a feel for the API is to see some examples:

var g = new navigator.GeolocationRequest();
g.request( function(geolocation){
  alert( geolocation.longitude + ", " + geolocation.latitude );
})

This is the same example as we saw last time; it alerts the user’s current location. What’s new is that I’ve spec’ed out the object passed to the callback (I’ve borrowed some of the great work done for the GoogleGears Location API):

interface Geolocation {
  readonly double latitude;         // in degrees
  readonly double longitude;        // in degrees
  readonly double altitude;         // in meters, or null if no data.
  readonly double accuracy;         // in meters
  readonly double altitudeAccuracy; // in meters, or null if no data
  int timestamp;                    // time of the location read, in seconds since
                                    // the epoch
}

Everything here should be self-explanatory. As a commenter mentioned last time, it’s important to know when the last location reading occurred. Without it, for example, it would be impossible to reliably calculate the current speed of the browsing device. (Knowing such data gives developers all sorts of fun—we could have an onDrunkDriving DOM event for when the browser detects your moving at 60MPH and weaving!).

Let’s move on to something a bit more complicated.

var g = new navigator.GeolocationRequest();
g.request({
  error: function(e){ alert( e.message ); },
  success: function(location){
    alert( location.altitude + "+/-" + location.altitudeAccuracy );
  },
  desiredAccuracy: g.defaultAccuracy
})

Here’s the new stuff:
error takes a callback whose argument is an object. The only attribute the object must have is message, a human readable explanation of the error. The error object may have other attributes, as dictated by the particulars of the location-giving device.

desiredAccuracy is a string which can take one of three values: “exact”, “neighbourhood”, and “city”. In order, “exact” means to return a geolocation as precisely as possible, “neighbourhood” means to return a geolocation good to 1km, and “city” means to return a geolocation good to 10km. It’s unnecessary to include a “country” option because there are more accurate ways of knowing what country a user is browsing from than with a highly fuzzed lat/long (e.g., IP-based geolocation).

defaultAccuracy is a read only property of the GeolocationRequest object that contains the user’s globally-set preference for yielding location to content providers. If the user has opted to give all websites city-level access to their location, then a website requesting city-level information won’t cause the browser to prompt for permission. In the above example, the request is asking for the highest accuracy location that won’t prompt the user for permission. defaultAccuracy is null if the user has opted out of providing geolocation information.

That about wraps it up for the API. Full interface documentation is available.


Why not on window.navigator?

It’s tempting to attach the GeolocationRequest object to window, but it makes more semantic sense to place it on the navigator object (and, unfortunately, not just for the pun). The navigator object contains meta information about the browsing agent—browser version, os, language, etc—and geolocation information is just that. Looking at it from the other side, the window object should contain information that is tied to the current tab/window. Geolocation is independent of what tab/window you are looking at (unless, of course, you have an extremely large screen), and so should not be attached directly to window.


Geocoding API

I’m somewhat on the fence about whether to include geocoding as part of the fundamental GeolocationRequest API. The information is useful to web developers, and it is a boon to not require an extra Ajax call to perform geocoding. However, it’s going beyond the scope of the fundamental language of geolocation. To quote Arun Ranganathan, our standards hero here at Mozilla:

When coining new browser primitives exposed at the same level as DOM stuff, we essentially go with the simplest thing that developers can do that won’t break the web and that are possibly exposed on the given device. You’ll notice that there’s plenty of scope for more nuanced APIs on top of our primitive stack, and this has contributed for much of the boom on the web for third party encapsulations around basic browser primitives (Dojo, Prototype, jQuery, etc.)… latitude/longitude is the basic thing we should expose. These can be used with other services and providers (example: Google Maps) to obtain address information or proximity information based on latitude and longitude.

That aside, we don’t really have to choose. By designing the API right, we can upgrade to include geocoding at a later date, without breaking any code. Let’s see it in action:

var g = new navigator.GeolocationRequest();
g.request({
  error: function(e){ /* Handle error. */ ); },
  success: function(location){ alert( location.address.city ); },
  desiredAccuracy: "neighborhood",
  requestAddress: true,
  addressLanguage: "en-US"
})

You can get the library for the address-enabled API here. The address object interface is:

interface Address {
  // Any of the below can be null, if not known.

  readonly string streetNumber; // street number
  readonly string street;       // street address
  readonly string premises;     // premises, e.g. building name
  readonly string city;         // city name
  readonly string county;       // county name
  readonly string region;       // region, e.g. a state in the US
  readonly string country;      // country
  readonly string countryCode;  // country code (ISO 3166-1)
  readonly string postalCode;   // postal code
}

The full specification is available, if you are interested in such sundry documentation.


Interface

Based on a number of good suggestions from the last post, this is how I’m thinking the security UI should look:
Geolocation Security Mockup

Geolocation in Firefox and Beyond

Wednesday, May 7th, 2008

In preparation for her keynote on the at the Web 2.0 Expo, Mitchell and I recently chatted about the “mobile web” misnomer. The misnomer is that there is going to be, long term, such a thing as a separate mobile web. There should only the one web (to rule them all), with different views into it, depending on the particular limitations or abilities of the device you are using.

One place I see the desire to separate the two webs is in geolocation. Location is often billed as the next killer-app of the mobile world, and people generally assume that it is a feature that will be bound to mobile devices. Yet, there are compelling reasons to have location information available to laptops as well: it is nice to have contextually relevant information available to me while working at a new coffee shop, traveling, or when farblonjet. At the core of the one-Web vision is the continuity of experience across all of my devices.

One of the symptoms of the the mobile-only location information is that to make something location aware, you have to deal with the large overhead of compiling an old-style application and porting it to all desired platforms. Then you have to figure out how to import the bits of the web you want into that application. It’s a pain.

What’s the solution? Adding geolocation to the browser, irrespective of whether it is on mobile or the desktop. That way writing a location-aware app is just writing a web-app with a little bit of new javascript magic.

I’ve been thinking about an API/spec, basing it on the work already done by Doug Turner and Ryan Sarver at locationaware.org. Here’s how it’s looking.

Simple call:

var geolocator = new navigator.GeolocationRequest();
geolocator.request(function(location) {
  alert( location.latitude + ', '+ location.longitude + ", " + location.accuracy );
});

That should be pretty obvious. The only bit that needs explanation is accuracy, which is a measure of how accurately the system is determining your location. Accuracy can be an enum with the these meanings: “exact”, “neighborhood”, “city”, “state”, “country”. I’ll come back to the reasoning behind doing it this way. However, it is worth thinking about also having an attribute location.errorInMeters (If you have thoughts on this, comment away!).

Complex call:

var geolocator = new navigator.GeolocationRequest();
geolocator.request({
  success: function(location) { /* We've got the location! */ },
  error: function(err){ /* There was an error getting location. */ },
  accuracy: "neighborhood"
});

Accuracy is the desired accuracy for the request. It’s there to make it easy for users and developers to see eye-to-eye on privacy and reliability. By putting accuracy into understandable, semantic, and quantized levels, we make it fast to understand what a web-app is trying to request. This way, if the user has globally allowed web sites access to their location at the neighborhood level, then any location request at the neighborhood or less-accurate level won’t cause the security/privilege UI to be invoked. And when the the request invokes the security/privilege UI, it can let the user know, in human-terms, what level of location information is being requested.

Here’s a quick mockup of the security UI. I haven’t put to much thought into ways of making this nicer yet, although I’d love something that gave a more visually compelling message of how much information you are giving out to websites.

Geolocation Security Mockup

I should be releasing a mock library for starting to play with this API soon. After that comes the real thing.

Blogging and Hiring

Tuesday, May 6th, 2008

I’ve been very quiet since joining Mozilla. Too quiet. I’ve been catching my breath and getting up to speed. It’s time, however, to start blogging again. I’ll be blogging here, but I’ll be mirroring the posts on the Humanized blog for a while. Be warned that the new blog has a temporary look, meant to be replaced soon by the awesome work of Naz Hamid. I should also point out that Atul has already begun talking about his experiences at Mozilla on his blog. You can also follow the sundry happenings of Jono and Andrew on their respective blogs.

The open source world is the world’s largest and arguably, the world’s best engineering department. It lacks a comparable design department. One of my goals in coming to Mozilla was to work on bridging this gap between the engineering world and the design world. I’ve only begun to think about the problem, and I hope to begin some conversations about the topic soon. An exciting aspect of working for Mozilla is that almost all of your design work can happen out in the open. There are none of those we-take-your-ideas-and-lock-you-away-from-the-sun policies that many other companies shackle their employees with. I hope to start sharing those design processes as well.

Which brings me to: We are hiring! Mozilla is looking for some top-notch UI/UE/UX/IA/IxD/HCI/TLA people. There are few places in the world where the user-to-employee ratio is roughly 1.2 million to 1. Getting to help shape the future of the web is hard work, but it’s easily worth it. If you are interested, send me an email at azzcsa@mozilla.com.