Essays

Get online as safely as possible while traveling

Friday, January 29th, 2010  

I’ve backpacked all over the world, and a friend embarking on a similar trip asked for my advice about how to stay safe when using internet cafés and youth hostel terminals. This advice might be helpful to other budget travelers, so here it is.

It’s important to understand that you’re putting yourself at significant risk every time you use a computer that’s not your own (and sometimes even when you’re using your own computer). The safest way to access the internet while traveling is to only use your own computer or smart phone. But budget travelers can’t always afford to carry a computer or a smart phone. The risk of theft of an expensive laptop or smart phone is much higher when traveling, especially when staying in shared rooms in hostels. And, as every backpacker knows, every single pound (or kilogram) you carry counts tenfold when you have to run a mile to catch a train. Traveling with your own, trusted internet device is often not feasible.

Another option is to just never go online while backpacking, but this often is not feasible either. The internet has become a tremendous source of tourist information plus an amazing tool to meet and coordinate with other travelers. And the long-term traveler must go online from time to time, to check their bank balances, pay off credit cards and mobile phone bills, and communicate with loved ones. The only alternative to this is the telephone, which requires staying up late or getting up early, and navigating an expensive and foreign telephone system.

All this adds up to the uncomfortable fact that you sometimes absolutely must get online in the next few days, and your options for doing so range from mildly to completely insecure.

The general idea is to first categorize your online activities by how secure they need to be, then, make an educated guess about the security of each computer you use, and use that as a guide for what you are willing to do online on that computer.

Step 1: Categorize your activities

Reading WikiTravel, finding hostels, or getting bus or train schedules doesn’t need a safe connection. If someone steals your password to a social network or CouchSurfing, the worst thing that can happen is that they use your account to say weird things to your friends, and you’ll have to reset your password or (worst-case) create a new account. Not that serious, in the great scheme of things. This, of course, assumes that you use different passwords for your different accounts, which is a good idea.

Checking your email needs to be a bit more secure, since with access to your email, anyone can impersonate you or steal your accounts on sites that use that email address. And lastly, making reservations with a credit card or logging in to your online banking are high risk, since with your credit card or bank details, you can be out of a chunk of money quickly.

Step 2: Categorize the available computer

Since I’ve never seen a single internet café running anything but Windows1, and since I’ve seen only one youth hostel with Linux computers2, I’ll only talk about judging the security of Windows computers.

The more professional internet cafés and hostel computers require you to log in, and usually you can tell if you’ve been logged in to a temporary, sandbox account, or if it’s the same account that every user gets logged into. If it’s the same account that every user uses, you’ll see personal files left on the desktop, in the trash, in the documents folder, and in the browser you’ll see browsing history and bookmarks and toolbars and plugins installed, etc, etc. If it’s a sand-boxed account, it should look like a pristine, clean install of Windows.

If it’s a Windows computer that you can just sit down at, don’t trust it. If there’s lots of random software visibly installed and files lying around, this means it hasn’t even been cleaned up recently. Use it to do research, but don’t type your passwords on it, and certainly don’t ever log in to online banking or type in your credit card details.

Sandbox accounts are much less likely to have malware installed, because only the owners/administrators, or someone who used an exploit to get administrator access, could have installed malware. If it’s sand-boxed, I generally feel ok logging in to my email, but I’m still wary about using it to log on to my online banking. In a pinch you could use Mint just to check bank balances, since it has read-only access to your financial information. Oftentimes I find myself making hostel reservations with my credit card on computers like this, but I’m never very happy about it.

Then there are places like EasyInternet, where users don’t have access to the filesystem, CD drive, or USB ports, you’re not allowed to download and run any programs, and where the entire Windows installation–not just the user account–appears to be wiped over the network each time the user is logged out. You can tell that the entire Windows OS is being wiped because the computer as soon as you log out, and the startup process indicates that it’s booting over the network. These kinds of computers are the safest. These are the only places where I feel comfortable logging in to my online banking. There’s still a chance that someone administering the café is capturing your passwords, but there are probably only a few people who have enough authority to do so.

I also judge hostel computers to be more secure than internet cafés. Internet cafés are open to the general public, including locals who would have the time, and the motivation, to regularly visit the café, install malware, gather collected data. Hostel computers are generally just used by hostel visitors, which would mean a traveler installing malware would have much less time to install and troubleshoot the data-collection process, no chance to reinstall it when it gets removed, and they’d have to gather the collected data remotely. You still have to worry about a member of the hostel staff installing something malicious, but again, there’s fewer staff members, so a smaller chance that it’s been compromised.

If the computer has Firefox3 installed, I usually take that as an indication that they aren’t total morons about security. Even better if it’s set to the default browser. Installing Firefox yourself, and using it, protects you against malware in Internet Explorer, but not against malware installed on the system.

If you know anything about Windows, you could check the version of Windows it’s running and see how recently it’s had security updates installed, which would give you an even better idea how security conscious the administrators are.

Other tips

If you can’t get to a secure computer and absolutely must access your bank account, most ATMs will let you check your balance and make transfers (and watch out for ATM skimmers). And staying up late or getting up early to call your bank, while a hassle, is much better than finding yourself stuck in a foreign country with cancelled credit cards and not much cash.

Always make sure you’re using SSL. If your bank doesn’t use SSL, switch to one that does. Gmail and most of the other major email providers allow you to log in using SSL. Use it. Don’t make credit card reservations if the site doesn’t support SSL. And don’t do any of this if the browser on the computer you’re using doesn’t support SSL.

The last step in staying secure while traveling is to change all your passwords and pin numbers as soon as you are back at your home computer again. That way, if anything did leak, it’s rendered useless.

Those are my white-hat, benevolent-hacker notes about internet while traveling. Soon, I’ll post some true black-hat tales of hacking internet café to get free, or cheap, internet.

  1. No love for Mac OS X. 
  2. High praise for Hostel Ruthensteiner, Vienna, Austria, running some sort of sand-boxed KDE, and where I felt almost as safe as on my home computer. 
  3. I’ve never seen Safari or Opera in the wild, and Chrome was released after my most recent trip. 

A surprising interface

Saturday, January 2nd, 2010  

This quote from an ex-Apple employee about the rumored Apple tablet has got me thinking:

You will be very surprised how you interact with the new tablet.

What could this mean? There are not many interfaces that would be “very surprising.”

A virtual laser keyboard would be surprising. But like a real keyboard, those keyboards aren’t very mobile; they require a flat surface, which you normally don’t have on the move. And a virtual keyboard doesn’t really seem like Apple’s style.

Voice control, or at least good speech recognition to complement keyboard input, is also a serious possibility. It’s something Apple has been interested in for a long time (via DF). A world where airports, subways and coffee shops are filled with people dictating emails and blog posts to their mobile devices is a little terrifying, but then again we already live in a world where people are have intimate personal conversations on their mobile phones in public.

A significantly expanded set of multi-touch gestures is the most likely. Taking advantage of the larger surface of a tablet screen to allow two-handed gestures seems like a natural choice. And handwriting detection would actually not be that much of a surprise from the company that brought us the Newton. Both of these are hinted at in recent patent filings.

While the article I link to in the previous paragraph compares Apple’s patent to the interface in Minority Report, the interface that article talks about requires the user’s fingers to be touching a surface, not in the air. A true Minority Report-style interface, where you gesture in the air to control the device, would be quite surprising. Being able to control a device without actually touching the screen (and getting finger marks on it) would make the tablet more attractive for full-screen uses like watching movies and playing games. This interface is a ways off still, though.

New font, code named Xenonsequitor

Thursday, December 10th, 2009  

This design started out from imagining that the dotless ı was the primitive i, and the dots on i and j were diacritics. I was traveling in Turkey and Hungary at the time, and the other diacritics flowed naturally.

Feel free to let me know what you think, good or bad. I’m also looking for a name, if anyone has any suggestions.

Ten ways to build an unmaintainable web application

Wednesday, September 30th, 2009  

Old-school hackers had a long tradition of ensuring job security by building applications so unmaintainable that only the original authors could work on them. But in these days of web applications, unmaintainability has fallen by the wayside. Instead, design fads like CRUD, REST, MVC, DRY, and KISS, have eliminated the average programmer’s job security.

Here are ten quick tips for achieving maximum unmaintainability in your web application. Following them will ensure that, in thirty years, a web programmer like you will be as valuable as a fifty-eight year old COBOL programmer contracting at $200/hr for a Fortune 500 company that still hasn’t migrated off of PL/1. You too will be able to live on a dairy farm in Pennsylvania, grow a beard down to your navel, and work in your underwear. And you’ll never have to learn anything new, work with anyone else, or start another new project.

  1. Mix it up. Put some JavaScript into external files, but be sure to intersperse JavaScript into your HTML, some of it in <script> tags. Cram multiple JavaScript statements into onclick and other event attributes — the longer, the better. Do the same with CSS; put some into external files, some in <style> tags, and also put some critical CSS into complex style attributes. And remember to put most of your <script> and <style> tags in the middle of the page content, instead of in the <head>, so that they will be difficult to find.
  2. Make everything dynamic. Generate JavaScript and CSS in your HTML templates. Think of it as another type of eval. Generate HTML server-side using templates and browser-side using JavaScript. What’s harder than working around a obscure IE layout bug with weird markup tweaks? Making sure both your server templates and your JavaScript HTML generation work around the same bug with the same HTML black magic.
  3. Abstraction, Shmabstraction. Pass lots of data from the server to the browser, store it in hidden form fields in the page, and then pass it back, unchanged, when submitting the form. That way, when the back-end data model changes, you get to rewrite part of the interface too. Allow data-model or server implementation details to creep into the interface implementation. Is the database sharded? Is the cache dirty? Does this row use a composite key? No need to have the server abstract these details, just pass that information to the JavaScript and let it sort everything out. That way, a sysadmin or a DBA can break the UI just as easily as a web designer can.
  4. Keep your data unstructured. Make sure all communication between the browser and the server is just a flat list of key/value parameters. Some of your parameters will be data to store, others will be modes or flags that affect the behavior of the service you’re hitting, and still others will be modifiers to display messages or affect the behavior of the UI. Keeping your data unstructured ensures these different types of parameters will collide. Often.
  5. Commit to a platform. Don’t waste your time checking to see if your pages work in all browsers (at least not until you’re totally done). Better yet, develop only in a single browser and don’t even bother to find out whether the features you’re relying on even exist in other browsers. Nothing is more fragile than an application that’s tightly tied to a single platform.
  6. Trust the browser. Rely soley on JavaScript input checking for some data — don’t check input on the server-side. Store sensitive data in hidden form fields. Put authorization checks in the JavaScript rather than on the server. Parameters like authorized=1 just scream out for URL hacking, and storing them in hidden form fields is only slightly harder to hack.
  7. Trust the server. Rely soley on the server to check, store, and generate only valid data in some places. That way, a DBA can change a single column constraint or data-type, and parts of the UI start to fail.
  8. Don’t use DOCTYPEs. That way you’ll never be sure what rendering mode different browsers are going to use to render your content.
  9. Ignore the cascade. Don’t bother to understand what the C in CSS stands for.  Just keep overriding styles until a page element looks the way you want. That way, your styles will be fragile and will break unexpectedly when an intern changes something a reasonable person would expect to be unrelated.
  10. Don’t use classes or ids. Instead, always write JavaScript and CSS that finds nodes based on tag name, name, alt or title attributes, or by their position in the DOM. That way when anything in the page changes, the hierarchy, the attributes, or when the site is translated into another language, things break. If you do end up using class or id, be sure to make a separate class for every node in your document and assign the same id to several different nodes.

If, however, you want to write flexible code that can react to and evolve with the ever-changing needs of its users, even after you have left the project in the hands of a clever but inexperienced hacker, you should probably avoid these techniques, and read up on some of those lame new design fads instead.

Special thanks to all the programmers whose code has illuminated these techniques over the years. My job may not be as secure as yours, but at least my code, and my conscience, are clear.

Some impossible objects before breakfast

Wednesday, July 29th, 2009  

Lately I’ve been playing with rapid prototyping, also known as three-dimensional printing. It’s a (relatively) new fabrication method that allows creation of shapes that would be impossible to create by moulding. It allows for creation of things like interlinked rings, objects trapped inside other objects, or complex voids.

Shapeways, a Netherlands-based website, offers high-quality, relatively cheap rapid prototyping, and a place to host your own selection of models. As a website, Shapeways is no RedBubble — the interface and marketplace tools leave much to be desired. The ratings and sorting can be gamed, it’s trivial to figure out the markup on another user’s model from its price, there’s no way to replace a published model with an improved one, and the site has encoding and markup issues. But what’s a few flaws when you own the category?

The free version of Google SketchUp has been satisfactory for rendering thus far, and its user interface is leaps and bounds ahead of the bizarre interface of Blender. I’m sure Blender has a superior feature set, but what good is power when you can’t figure out how to use it? Meshlab and AccuTrans3d have both come in handy for checking surfaces and converting between formats.

On to the models! Click on the pictures to see more views of each.

Trapped Outside

Trapped Outside is a model of Boy’s Surface with a sphere trapped in the space cut out by the one-sided surface. Boy’s Surface an immersion of the projective plane, which means it is a Möbius strip with a disk glued to its edge. It is a non-orientable surface with no edges and no pinch points.

Trapped Outside

Trapped Outside was fairly easy to create using Google SketchUp. It’s just a few circles extruded along each other here and there.

Hollow Knotted Gear

The Hollow Knotted Gear, inspired by Oskar van Deventer’s Knotted Gear, consists of two interlinked knots; a trefoil knot (in green) and its dual, a 3,2 torus knot. The green trefoil forms a rectangular cross section and a triangular hole. The blue knot forms a triangular cross section and a rectangular hole. The two knots gear perfectly together, and can move around each other, but only if they are both moved simultaneously.

Hollow Knotted Gear

After many failed attempts at getting various applications to render this complex extrusion properly, I wrote a small Python program to calculate the surface for me and output VRML. Then, after much more trial and error, I used AccuTrans3d via Wine to convert the VRML surface to a DAE file for uploading to Shapeways, and to a 3DS file for examining in Google Sketchup (and to take screenshots).

There are a few more of my designs on Shapeways right now, and even more rattling around in my head just waiting to be prototyped.

A tiny fix to the jQuery hint plugin

Monday, July 27th, 2009  

Here’s a tiny fix to Remy Sharp’s excellent jQuery Text box hints plug-in. Without this fix, jQuery’s val function will return the hint text if the text box hasn’t been filled out by the user yet.

Here’s the patch:

@@ -20,7 +23,7 @@
       $win = $(window);

     function remove() {
-      if ($input.val() === title && $input.hasClass(blurClass)) {
+      if ($input.realval() === title && $input.hasClass(blurClass)) {
         $input.val('').removeClass(blurClass);
       }
     }
@@ -41,4 +44,17 @@
   });
 };

+
+$.fn.realval = $.fn.val;
+
+$.fn.val = function (value) {
+  var i = $(this);
+  if (value === undefined) {
+    return (i.realval() === i.attr('title')) ? '' : i.realval();
+  } else {
+    return i.realval(value);
+  }
+}
+
+
 })(jQuery);

And here’s the full plugin with the patch applied:

/**
* @author Remy Sharp
* @url http://remysharp.com/2007/01/25/jquery-tutorial-text-box-hints/
*
* better val() method added by Matt Chisholm, 2009/07/27
* http://glyphobet.net/blog/essay/878
*/

(function ($) {

$.fn.hint = function (blurClass) {
  if (!blurClass) {
    blurClass = 'blur';
  }

  return this.each(function () {
    // get jQuery version of 'this'
    var $input = $(this),

    // capture the rest of the variable to allow for reuse
      title = $input.attr('title'),
      $form = $(this.form),
      $win = $(window);

    function remove() {
      if ($input.realval() === title && $input.hasClass(blurClass)) {
        $input.val('').removeClass(blurClass);
      }
    }

    // only apply logic if the element has the attribute
    if (title) {
      // on blur, set value to title attr if text is blank
      $input.blur(function () {
        if (this.value === '') {
          $input.val(title).addClass(blurClass);
        }
      }).focus(remove).blur(); // now change all inputs to title

      // clear the pre-defined text when form is submitted
      $form.submit(remove);
      $win.unload(remove); // handles Firefox's autocomplete
    }
  });
};

$.fn.realval = $.fn.val;

$.fn.val = function (value) {
  var i = $(this);
  if (value === undefined) {
    return (i.realval() === i.attr('title')) ? '' : i.realval();
  } else {
    return i.realval(value);
  }
}

})(jQuery);

My identity is not for your profit

Saturday, July 18th, 2009  

OkCupid is one of the best-designed websites out there. It’s addictive, captivating, easy to use, and pretty. But since it’s free and completely funded by advertising, the ultimate design goal of the site must be to get users to visit more pages, view more ads, and click on some. And this design goal can be taken to extremes that are at odds with the goal of providing quality matching. Consider this screenshot:

why-im-not-on-okcupid-anymore

This was from the unauthenticated view of my (now-disabled) OkCupid profile. The black text in the bottom half of this screen-shot was my somewhat snide response to OkCupid’s seventh-grade reading level getting-to-know-you question. And at the top is a plug for a different user and an ad for a book that has absolutely nothing to do with me or my tastes1.

The last thing that any OkCupid user should want is for readers to be distracted from their profile like this. And I really didn’t want some site co-opting my identity and interspersing advertisements and links to generate more page views into the middle of it. Even if it was to support a free site. So, OkCupid, you have joined the ranks of other online dating sites that just don’t cut it. Thanks, but no thanks.

  1. A Summer Affair’s plot summary on Amazon makes it sound like an upscale romance novel with a helping of East Coast affluence-porn thrown in. 

Bring on the patches

Sunday, May 31st, 2009  

Zed Shaw’s recent Python Neglect article raises a few points that are unquestionably valid: easy_install and mx.DateTime suck big time, and it sounds like the email tools have some serious problems. But I would like to hear better explanations from him about:

  • What the datetime module (introduced to replace mx.DateTime and fix shortcomings with the time module) is missing? It’s always handled everything I’ve thrown at it.
  • What is wrong with optparse? Usage? Functionality? Implementation?

I also just plain don’t understand his complaint about del versus remove. I think mystuff.remove(mything) and del mystuff[4] do exactly the same thing, so what’s the problem? That del exists?

His promise to provide patches will be an interesting test of the Python community’s ability to judge patches on their objective merit, not by their contributor, since Shaw seems to have a tendency to ruffle feathers1.

And a “WSGI for templating,” and efficient state machines with generators? Sounds exciting.

  1. This is the pot calling the kettle black here. 

Hacking the Constitution

Tuesday, May 26th, 2009  

A vote for the President of the United States is actually a vote for an “elector” who pledges, but is not legally obligated, to vote for a specific candidate in the Electoral College. Forty-eight states then allocate all of their electoral votes to the popular vote winner in that state. This means that a candidate receiving the most votes nationwide is not necessarily the one that receives the most electoral votes and becomes President. If the popular-vote loser many states by small margins, and loses some of the others by large margins, they can win the electoral vote, despite losing the national popular vote.

This winner-takes-all system of allocating electoral votes also has the side effect of making a few “battleground” states the primary focus of election campaigns. Candidates descend on these states, funneling money and advertising into them, and tailoring their campaigns to win over voters there. Voters, of either party, in the remaining “spectator” states are effectively disenfranchised, and the small percentage of voters in the battleground states elect the president.

This isn’t even how the electoral college was intended to work. The framers intended that the electoral college would usually fail to choose a clear winner, instead nominating the most popular candidates for election by Congress. This hasn’t happened in over two hundred years.

Programmers have a term for something that’s neither operating as originally intended nor guaranteed to do what their users ask it to do. The Constitution is buggy.

Yet the Constitution is notoriously hard to change. A programmer might use the term legacy.

How would a programmer fix this? Find a way to hack1 a bug fix into the legacy system.

What should the goal of the fix be? We should elect the president in the same way that every governor, mayor, senator, representative, city council member and dog-catcher2 is; by popular vote. If popular vote is good enough for every single other elected office in this country and in many other democratic countries around the world, it should be good enough for the President of the United States of America.

How do we change the Constitution? Turns out we don’t have to. The founders left the allocation of electoral votes up to the states:

Each State shall appoint, in such Manner as the Legislature thereof may direct, a Number of Electors…
-U.S. Constitution

The appointment, and mode of appointment, of electors belong exclusively to the states
-U.S. Supreme Court

And the fix? The National Popular Vote Plan allocates all of a state’s electoral votes to the national popular vote winner. It only goes into effect once enough states pass it to command a majority of electoral votes. The electoral college won’t go away, but it will become obsolete. In programming terms, this plan ensures a buggy legacy system will never (again) get fed the kind of data that triggers the bug.

The National Popular Vote plan has been making its way through state legislatures for the last few years. I’ve brought it up in conversation a few times recently (because of my Visualizing the National Popular Vote plan project), and I’m surprised how many people don’t know about it. There should be a huge grass-roots movement behind this plan to re-enfranchise the electorate, but even smart, well-informed, thinking people haven’t heard of it. So please, if you agree with me and think the National Popular Vote Plan is a good idea, forward this page or NPV’s website to your friends, bring it up at parties, or support it with a donation. And if you don’t agree with me, forward this page or NPV’s website to your friends, bring it up at parties, or… well I guess I can’t expect you to support it with a donation.

Let’s get rid of this obsolete, broken, idiotic electoral college system once and for all.

  1. Note to non-technical readers: Among programmers, hack generally means a quick, clever, “outside-of-the-box” solution to a difficult or intractable problem. That is the sense in which I am using the term hack here. If you think the National Popular Vote plan is about subverting or circumventing the constitution, you have misunderstood it. 
  2. My thanks to Hendrik Hertzberg, National Popular Vote’s bulldog, in whose writings in the New Yorker I first heard about this clever plan. I believe the inclusion of dog-catcher in this list is due to him but I cannot find the exact quote. 

Visualizing the National Popular Vote plan

Tuesday, May 26th, 2009  

This graphic visualizes the progress of the National Popular Vote plan (more about the politics of this plan in Hacking the Constitution).

The existing visualization on National Popular Vote’s website was flawed enough to inspire this attempt at fixing it. They use a national map with states colored according to the plan’s progress. Using geographical visualization conflicts with the plan’s intention to make the states as entities less influential, and with the plan’s success depending on the number of electoral votes, not the geographical size or population of the states1. And even though the steps in passing the plan suggest a spectrum, the colors are seemingly random.

Plus NPV is a good cause that deserves more attention. And as a vocal Flash critic, I should put my money where my mouth is and implement a cross-browser, scalable, interactive, vector graphic to show that it can be done without Flash.

Visualizing complex data well is challenging, and this is no exception. The plan will likely be adopted slowly over many years, so the graphic must be designed to expand. The technology must also be future-proof; I don’t want to have to re-implement the graphic, convert it to a different format, or get access to future versions of software, or the operating systems that software must run on, just to keep supporting it. This pretty much rules out Flash and Sliverlight.

These constraints make SVG2 and JavaScript a good choice. SVG support is still nascent in Gecko and WebKit3 (and even Opera supports it), but the standard is pretty usable and I expect it to gain more adoption over time. All of the rendering code is in JavaScript. I’d put money on JavaScript interpreters remaining readily available ten years from now. I unfortunately have no ability (or desire, for that matter) to test this in IE with Adobe’s SVG plugin; if you try it, email me the results.

There are many different entities involved in the process: fifty states, each with two legislative bodies and a governor, and a total of 538 electoral votes; and many different events: passing the first body of a legislature, passing the second, bills passing the same body subsequent times, being signed into law, being vetoed, vetoes being overridden, and (hopefully never) laws being repealed.

The data comes from disparate sources; most comes from NPV’s website, but I had to search for the vetoes. The data is not just linear; it overlaps and interacts. A veto affects two of the charts but not the third, and a repeal would affect all three. The three charts have an order; a bill cannot pass both houses before it passes one, and cannot be signed into law before it passes both.

To include all this data, a visualization would either have to be interactive or poster-sized. This one is interactive; you can mouse over vertexes in the charts and get more information about the events they represent. You can quickly and easily find out:

  • The exact progress of NPV at any time since its introduction.
  • Who, what and where for any NPV-related event.
  • All NPV-related events that have occurred in any particular state.
  • How significant each state’s contribution to the electoral vote tally has been.
  • Firsts, lasts, largests and smallests.

As with many real-world data visualizations, unexpected patterns emerge. Most activity is clustered in the winter, spring and early summer, when legislative bodies are in session. The only things that happen between August and December are vetoes. This cycle will likely become much more obvious once the graphic spans a few more years.

Hawaii’s legislature overrode their governor’s second veto, and The Governator has twice robbed the plan of California’s 55 electoral votes. Neither of these facts is obvious from the current graphic. If the plan is ever repealed, the graphic would need to show that too.

As I said in Hacking the Constitution, the the National Popular Vote plan deserves a lot more attention and support, so forward this page or NPV’s website to your friends, bring it up at parties, support it with a donation, or include the graphic on your web page.

  1. If a geographical design were used on a visualization of the progress of this plan, it should at least be a cartogram
  2. The HTML <canvas> element might also have been a viable option, but I already knew SVG. 
  3. For a good time, try resizing the font in Safari 3.