Author Archives: curtis

Seeking interesting problems to solve with code

I am a little sad to say that I am now ex-Canonical. Canonical provided me with ten years of challenges and interesting problems to solve. I am seeking new opportunities to solve interesting problems with code.

I don’t like the e-mails I am getting from recruiters. They splat skills and locations into an email without description of the challenges a position involves. I love working in Python, Ubuntu, and Cloud (Openstack, AWS, GCE, Rackspace, Joyent, MaaS), but these tools are not interesting without a problem that needs solving. For the past decade, I have been in the grand position of building web apps and workflow tools, designing them, coding them, testing them, deploying them, and maintaining them. The Juju QA team was a devops where I designed and created the build, test, and release processes. I deployed and maintained more than 40 services in public and private clouds. The Juju project is multi-OS, multi-architecture, multi-cloud, and client-server; it is awesome. I love owning and doing everything.

My resumé (Curts_Hovey_Resume) is a broad outline of what I have been doing.

Reverting Core Storage Physical Volumes

I after upgrading OS X to Yosemite, rEFInd did not start. Using the Option key while rebooting, I selected my Ubuntu Trusty partition, which booted with a warning that the MacintoshHD couldn’t be mounted.

During the upgrade, the HFS+ partition where OS X resides was converted to a logical volume of Apple Core Storage. I believe this is to support encryption, but I declined the option during the upgrade. The Disk Util app in OS X will not show this change, but the diskutil command will. The fix is trivial from the OS X terminal.

The diskutil list command will reveal which partition was convert to a logical volume on the physical disk.

diskutil list
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *251.0 GB   disk0
   1:                        EFI                         209.7 MB   disk0s1
   2:          Apple_CoreStorage                         175.6 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
   4:       Microsoft Basic Data                         70.3 GB    disk0s4
   5:                 Linux Swap                         4.2 GB     disk0s5
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS Macintosh HD           *175.3 GB   disk1
                                 Logical Volume on disk0s2

Your disk partitions for dual booting Ubuntu and OS X may be different. I know there was no logical volume before I started the upgrade. I restored the APPLE_HFS partition to the real disk0s2 with the revert option

diskutil corestorage revert /dev/disk1

When I rebooted, rEFInd presented me with choice of OS X and Ubuntu. Ubuntu mounted with MacintoshHD when I signed in. All fixed.

Migrating juju to HP Cloud’s Horizon

HP Cloud retired its old regions this month. If you use juju on HP Cloud and your account was created before this year, you may need to update your juju config and possibly complete your project setup in Horizon.

There are two changes you must make to each HP Cloud environment listed in environments.yaml. Set the region option to “region-a.geo-1” or “region-b.geo-1”, which are US West and US East respectively. The new regions do not automatically assign public IPs. The use-floating-ip option must be set to “true” to tell juju to request a public address.

use-floating-ip: true
region: region-a.geo-1

Note that juju does not yet release the public address when you destroy the machine, You need to use the nova command line tools or the Horizon console > Project > Compute > Access & Security > Floating IPs to release them. We will release a fix for “Floating IPs are not recycled in OpenStack Havana” soon.

If you haven’t used these regions before, you needs to register your public SSH keys and create a default network for each one you use. Visit Horizon console > Project > Compute > Access & Security > Key Pairs. Most people migrating just copied their public keys to the new region. Visit Horizon console > Project > Networks > Network and verify or create a default network, something like

Building trans-cloud environments with juju

The Juju QA team uses juju to build the CI services that test juju. We have built 3 CIs in fact, because juju makes it easy to move services to the cloud of our choice. Our choice is driven by which cloud provides the best combination of resources, but CI has grown beyond what one cloud can provide. We want CI in all clouds to test with the resources they provide. While juju doesn’t support cross environment relations, that hasn’t stopped the QA team from building an hybrid environment that straddles two clouds and a private network.

The steps to provision a machine on another network are codified in our add-remote-machine.bash script. The Juju QA team uses this script to add physical machines, machines in kvm, and machines launched in other clouds into our Juju environment. Once a machine is registered with a juju environment, any charmed service can be deployed to it. Adding a machine to a open network is painless.

add-remote-machine.bash juju-ci3 my-keys/juju_ci_rsa
    |                          |          |              |
  script                     env-name   ssh-key   private-ip

Adding machines on restricted networks may require firewall egress changes.

Provisioning the best resources for services

Juju provides two essential devops features:

  • A cloud-agnostic way to provision machines. Juju supports Azure, EC2, Joyent, MAAS, and OpenStack-based clouds like HP Cloud.
  • A trivial means to deploy configured services to machines. I can put Jenkins slaves and web applications into production in minutes.

The mechanism to deploy services is so valuable, that juju provides a command to add existing machines to the environment. Existing machines often have special resources not provided by a simple cloud image. Using placement, I can deploy one or more services to each machine. For example, to add a machine that I want Jenkins to use, I would issue these commands to register machine number 2 in my environment, then deploy a jenkins slave to it, and finally configure the existing jenkins master to send work to it:

juju add-machine ssh:ubuntu@
juju deploy --to 2 jenkins-slave ppc64-slave
juju add-relation jenkins-master ppc64-slave

Provisioning remote machines

The problem is that juju wants a private address when provisioning a machine. The solution to building hybrid environments composed of machines from other networks was understanding what network resources juju requires during and after provisioning. First, there are three parts to juju:

  • The juju client (juju command line or juju-gui) that issues commands
  • The juju state-server that manages the machines and services in the environment
  • The many juju agents (1 for each machine and service) that asks the state-server for tasks

During the act of provisioning (bootstrap or add-machine) the client acts as a bridge between the state-server and the remote machine. The private address is thus private to the host that the client is running on! Once the agent is running on the remote machine, it will talk to the state-server using the state-server’s private DNS name. The state-server doesn’t really know where the remote machine is, and it cannot access it.

Since I have ssh access to all the machines via their private address, I can add them to the juju environment. Even when I only know a machine’s public address, I can add an ssh rule that maps a random private address to the public host. As for helping the agent talk to the state-server, a single addition to the agent’s /etc/hosts is required to map the state-server’s public IP address to the private DNS name.

The script checks the required connectivity. It tries to verify common addresses that juju will use, such as the location of the environment’s private container, the server images, and juju tools. It is not authoritative. It will ask me to verify some connections that are not explicitly defined in the environment. It doesn’t know the network requirements of the services that will be deployed to the machine. This isn’t an issue for machines on open networks. Several of the Juju CI machines are on restricted networks, and I asked the IS department to allow egress to the required addresses and ports. We may improve the script’s verification support as we extend the environment to HP Cloud and Joyent.

As for how Juju makes CI easier, that is the subject or a future post.

Working with Juju, Ubuntu 12.04 Precise, and 14.04 Trusty

Juju 1.18.x is the first Juju that is aware of two Ubuntu LTS releases.
In the past, when bootstrapping the state-server or deploying a charm,
Juju selected Ubuntu 12.04 Precise when the serie was not specified. If
you care about the version of Ubuntu used, then you want to specify the

You can specify the series of the state-server and set the default charm
series by adding “default-series” to environments.yaml. Setting
“default-series” is the only way to specify the series of the
state-server (bootstrap node). For example, if your local machine is
Ubuntu 14.04 trusty, but your organisation only supports Ubuntu 12.04
Precise in the cloud, you can add this to your environment in

default-series: precise

There are many ways to specify the series to deploy with a charm. In
most cases you don’t need to. When you don’t specify a series, Juju
checks the environment’s “default-series”, and if that isn’t set, Juju
asks the charm store to select the best series to deploy with the charm.
The series of the state-server does not restrict the series of the
charm. You can use the best series for a charm when deploying a service.

When working with local charms, Juju cannot fall back to the charm
store, it falls back to the environment’s “default-series”. You must
specify the series in the environment or when deploying the charm. If
your environment is running, you can add “default-series” like so:

juju set-environment default-series=precise

These commands choose Ubuntu 12.04 Precise when “default-series” is set to “precise” in the environment:

 juju deploy cs:precise/mysql
 juju deploy precise/mysql
 juju deploy mysql
 juju deploy local:precise/mysql
 juju deploy loca:mysql

Restoring network to lxc and juju local-provider

I have experienced two cases where lxc containers stop working or new containers never work because they cannot join the network. My LTS container started, but without network, there were a lot of things I couldn’t do in it. In the case of Juju, I couldn’t deploy new local services. The unit agent status was stuck in PENDING.

You can verify the network is broken by fancy listing the lxc containers you started either by lxc-start or juju deploy:

sudo lxc-ls --fancy

<container> RUNNING -    -    NO

This shows that the running container doesn’t have IPV4 or IPV6 networks.

For each existing container that needs fixing, you need to install the new dhcp packages, but without a network, you cannot do it from a running container. Instead chroot can be used to update the container’s root file system.

cd /var/lib/lxc/<container>/rootfs/
sudo chroot ./
sudo apt-get update
apt-get install isc-dhcp-common isc-dhcp-client

To ensure that new containers work, you need to clear the lxc cache. The lxc image cache was built when you created or deployed your first container. The images there are probably more than a few months old.

sudo ls -lh /var/cache/lxc/precise/
sudo ls -lh /var/cache/lxc/cloud-precise/
sudo rm -r /var/cache/lxc/*

Lxc will get the new images the next time it needs to create a container. The first call will be slower to complete since it will build a fresh cache.

Restoring grub after OS X Mavericks

I had a scary moment after I updated my dual boot MacBookAir to Mavericks. Refit started Ubuntu, but grub was showing me the rescue prompt. This was a different misadventure from my upgrade to Mountain Lion; the partitions were there, but grub was lost.

I use refit to manage dual boot. I remembered from past experience that I needed to use the partition tool from the refit boot screen to sync the GPT and EFI tables. The task was done in seconds.

I knew Ubuntu was on the 4th partition (suggested by the GPT output from the sync), but to be sure I listed the partitions, then listed the 4th one.

ls (hd0,gpt4)/boot

and I saw the boot images and a grub dir. I then assumed, all my data was in place, but the MBR was lost during the Mavericks install. To start Ubuntu, I typed:

set root=(hd0,gpt4)
set prefix=(hd0,gpt4)/boot/grub
insmod normal

Ubuntu started up as normal. The grub screen was identical to my last boot. I was confident grub’s configuration was fine, I just needed to restore grub to the MBR. I opened a terminal after logging in and typed:

sudo grub-install --force /dev/sda

With hesitation, I rebooted. All was back to normal.

Managing Juju Charm Versions

It is difficult for Juju charm authors to support forked charms. dev-ops often don’t realise they are forking a charm when they add files that they want the charm to deploy. We cannot assume that the deployed charm’s revision (or the version control revision number) will ever match what the author released. I use Bazaar tags to mark the versions I support and help identify the true version of a deployed charm.

Juju uses the charm’s “revision” file to store the version. The number in this file must be incremented to deploy additions or changes to the charm. Upgrading a deployed charm requires a higher revision number. Organisations commonly create a local charm repo (managed by a version control system like Bazaar) to freeze the versions they deploy. These known version are stable; this is a best practice when working with charms that change often. The local branch will get commits that are not in the branch published at Launchpad. The revision numbers are meaningless between the two branches.

I tag my charm branches with the charm revision number. When a dev-op forks my charm to add it to the local charm repo, we can compare branch tags. For example, I tagged lp:~charming-devs/charms/precise/elasticsearch/trunk r39 as elasticsearch-29 to match the number in the revision file. I can ask the dev-op which tags the local branch has. I can quickly identify missing releases. I can ask for a diff from the tag I last released to help diagnose problems with the changes.

For example, several issues were reported about my elasticsearch charm. I had addressed the problems months before. I suggested the dev-ops upgrade to the latest version. Since their version numbers were higher than my versions, they did not upgrade. Tags are more precise. I can suggest the dev-ops merge “-r tag:elasticsearch-29”.

Another case, charms may need to change often if the application is deploys is under active development. A recent deploy of charmworld failed; the charm upgrade errored. The dev-op and I couldn’t reconcile the version numbers between what was deployed and what I released. We had to read a diff of the charm’s directories and files to discover the deployed charm was missing several releases–the charm was incompatible with the deployed code. If I had tagged my release, we could have identified the issue in minutes.

Common mistakes that broke Launchpad’s browser compatibility

At this moment, Launchpad is providing all features to Opera, Internet Explorer (IE), and many other browsers. Many features like bug listings, bug tag auto-completion, changing bug status and privacy, choosing people, and editing subscriptions were broken in many browsers. Some features were broken for years because developers mistook their inexperience for something broken these browsers.

I am summarising what was wrong with Launchpad and how to avoid repeating the mistakes of the past. Launchpad reviewers, I urge you to read this so that bad code is not merged into Launchpad’s trunk again. Launchpad engineers commonly work with Firefox and Chromium, two browsers with great support the latests technologies, These browsers are also very good at correcting mistakes in markup, CSS, and JavaScript. The lesser browsers are less forgiving; developers must fix their mistakes and on rare occasion write alternate code to make a feature work. Launchpad developers were too quick to blame the browser. They failed to recognise their own inexperience, and they failed to find the root cause of the problem.

Why Do We Want to Support More Browsers?

One user, lazarus, responded to my A tale of two travesties post asking “why bother with IE? Those 4% of users should switch to a *DECENT* browser.”

Canonical’s partners often run older releases of Firefox and Chromium. Some partners are running IE. Their staff cannot install software onto their computers, they have no choice but to use the corporate browser. The people who help build Ubuntu, who help Canonical enable Ubuntu to run on new hardware, cannot use Launchpad to do their job.

Consider users who use their phone or tablet with Launchpad. These browsers are also locked down, and they are commonly older versions of browsers. There were several bugs in the past that prevented Canonical staff from using their phones to login to Launchpad. They, even myself, had to find another computer to respond to a notification received via phone. Mobiles devices are now commonly used to work on the Net; Launchpad risks loosing users and projects who can choose another service.

Servers often do not have a GUI. We assume Ubuntu server is running headless. Servers also tend to be LTS installs that might can be 2 to 5 years old. Tasks such as reporting a bugs, updating it, and adding a comment must work in a text-based browser without JavaScript.

What is the Cost of Supporting More Browsers?

Again lazarus stated in his reply to my struggle to run IE in Ubuntu, “I’m really sick of seeing all those work-arounds just to make it work for that damn browser.”

I wrote less than 20 lines of code to Support IE, yet I removed more than than 125 lines that disabled it or other browsers. I Also removed about 200 lines of duplicate or alternate code from <noscript> elements. It takes fewer lines of code to support older and mediocre browsers than to not support them!

For every bug that was tagged as affecting IE, I discovered it also affected Opera, Konqueror, Firefox 3, and even the latest version of chromium. Fixing one bug solved an issue for multiple browsers each time. I found many bugs overlapped with or were duplicates of other bugs that were listed as a higher priority, yet remained unsolved. Understanding the root cause of a problem allows us to make a single change that fixes many things. Honestly, the most common way to fix an issue was to read the YUI documentation to learn what Launchpad was doing wrong. Thus, the root cause of IE not working is rarely IE itself…the JavaScript bugs in Launchpad are caused by inexperience.

Running other browsers can be difficult as I reported in my Travesty post. I now have a custom apache configuration that cannot be copied to other developer machines. Running Microsoft’s official IE developer images take all my available RAM. I also run the VM image from an SD card because Windows is still bloatware. Installing Konqueror and all the KDE dependencies can also be a problem if you are short on disk space.

The maintenance savings by writing good code that supports all browsers are diminished by the days or weeks it takes to install all the browsers to reproduce a bug. If I cannot reproduce a bug, I cannot fix it. For many Launchpad developers, the best way to not fix a bug in a mediocre browser is to avoid introducing the bug. This is why we use YUI as our JS library, it reconciles the differences between browsers. This is why we have code standards and reviews, to ensure that we agree the code is correct and maintainable. We want to recognise bad code before it is merged into trunk and we absolutely must avoid dangerous code,

The Last Sign of Inexperience

This example of code is dangerous and unmaintainable:

if ( {

This is the last sign of inexperience. Bugs have already been slipped past review, merged into trunk, and are probably in production preventing user from completing their task. Why is IE not using the feature? Which browser versions and YUI versions were tested? This kind of guard often has an associated comment like:

# Usual IE brokenness.

I think the comment can also be interpreted to mean: “I do not have IE installed, I do not trust it, I do not trust my own code, I do not understand YUI”.

Do not let this kind of guard merge. If one browser does not work, there are probably 5 other browsers, like those shipped with an Ubuntu LTS, that also do not work. This branch needs fixing!

Is This a Presentation Problem?

Several bugs fixed by William Grant and myself were not JavaScript bugs as was reported. They were CSS or markup bugs. These bugs were trivially fixed in minutes when shown to the right person, yet some of these bugs were reported years ago. Your chances of fixing a presentation problem with JavaScript is similar to painting a house with a hammer. If the UI for a JavaScript feature does not look right, or not render at all, consider a CSS or markup change.

Non-conformant CSS the most common cause of broken presentation. I often uses Wikipedia’s Comparison of Layout Engines when researching differences in layout. Even the latest versions of Firefox and Chromium have inherited defects from their layout engine. Firefox was showing a scrollbar because the form overlay buttons had a text-indent property set to twice the width of the page. Though Chromium did not show the scrollbar, I think Firefox was right in this case; I fixed the issue by setting a text indent that was a few characters wide. Many issues can be fixed using alternate properties or additional CSS selectors to add properties to the problem elements. For example, IE has poor support for visibility (introduced by Netscape in 1998), but has better support for display (introduced by Microsoft in 1998). IE was always showing the fields in the overlay forms that change the page. Though the form overlays were visibility: hidden, IE requires a specific selector for .yui3-lazr-formoverlay-hidden input to be display: none.

Experimental CSS can be both the cause and the solution to a display problem. We want Launchpad to look good, and we often use CSS3 to define the styles. Many CSS3 properties are not fully implemented in browsers, but there are vendor properties (ones with a dash prefix) that do support the presentation. Launchpad has many of these for Gecko and Webkit. We also need to add them for KHtml, Opera and IE. While IE does not support the CSS3 box-shadow property, it has supported shadows since 1998 and we added its vendor property to give all overlays shadows.

Invalid Markup breaks older browsers, but newer browsers are better at fixing (and hiding) markup problems. You can read about how browsers work in depth, but I think I can summarise the issue in a few sentences. When browsers discover an error while parsing the markup, they pause to fix the markup then carry on. For example, paragraphs cannot contain lists. Most browsers assume that the author meant that there is a paragraph before and after the list. If you query the DOM using JS, you may discover it does not match the source. When I switched the Launchpad test suite to use a webkit-based test browser many tests failed. Developers were ignoring test failures because they passed in Firefox. I traced the errors to existing bug reports and discovered code was creating invalid tables and Chromium fixed the markup differently than Firefox. IE is very prone to choke on malformed tables. The lesson is clear, write what you mean, or else browsers are free to reinterpret your bogus markup and topple your scripts.

Launchpad users will soon loose their last line of defence against invalid markup when Launchpad switches to Ubuntu 12.04. My squad stopped development a few months ago to learn why Launchpad’s ec2 test runner failed a test that passed on all the other test runners. The reason is because the script used bad markup that toppled the Ubuntu 10.04 version of my test browser. The new webkit library in Ubuntu 12.04 is better at correcting markup, hiding from mistakes from tests, allowing the mistakes to be released to break older browsers.

Is This a Structural Problem?

Structural problems are issues where the choice in markup is brittle or unmaintainable.

Noscript is BAD. Netscape meant well by introducing the <noscript> element, but it leads to maintenance burdens and it assumes that all scripts run perfectly. The intent is to have two implementations and do not diverge. They do diverge though, leading to differing and confusing behaviours. If the script fails to initialise, the user gets no behaviour. This situation was exacerbated in Launchpad with the use of the if ( guards that meant IE users never saw the HTML or JavaScript links to change project roles or change blueprints. Launchpad prefers, and YUI recommends, progressive enhancement; write simple markup that does not need JavaScript, then modify the page to add the scripted features. Scripts that replace or hide the HTML feature should do that as the last step; If the script fails, there is still a usable link.

Mutating parent markup while parsing is dangerous. Several widgets like the TextAreaEditor were mutating their parent element before the parent element had closed itself. Only the mad and the brave mutate the thing they are iterating over. Chromium and Firefox handled the insane situation with grace, but other browsers threw a wobbly. IE 8 could not render the bug page, it stopped at the bug description. This situation is hard to see in a review. In general the script block must be outside of the elements it changes, but several widgets enhance parent and grandparent nodes, which means the markup appears to have redundantly nested elements. Some of this madness can be averted by running the script on DOMReady. There are many scripts that load as the page is parsed; I suspect these could all be changed to run at DOMReady.

Is This a YUI Problem?

YUI also has bugs. Has this issue been reported in YUI’s bug tracker? Which version of YUI is Launchpad using? Does upgrading fix the issue? Maybe an issue needs to be reported?

There were several hacks in the Launchpad bug pages to load scripts during parsing or after the load event because DOMReady was buggy during YUI3 preview releases. Both Opera and IE had difficulty during running scripts during parse time, and running the scripts after the load event caused the page to flash. Launchpad has been running YUI3+ for almost two years, the hacks should have been removed. The code required a proper XXX comment to remind developers to update the scripts.

# XXX: 2010-03-12 bingo bug=234567:
# DOMReady is bug in YUI3 PR3. Test DOMReady again in YUI 3.0.

There was also a case where Launchpad ran a version of YUI that miswired the event handling in IE. Several if ( guards were added without a comment explaining the issue, nor a stating the bug number in YUI’s bug tracker. I do not know when when these issues were fixed, but they are fixed in YUI 3.3.

Is This a EcmaScript or DOM Problem?

Launchpad was created in the age of EcmaScript 3 (ES3). This is now the age of ES5, and Launchpad developers are using ES5 browsers like Firefox and Chromium. Browser that the developers once used to build launchpad stopped working. Launchpad stopped working with the browsers available to Ubuntu LTS such as 08.04. Launchpad developers use jslint and YUI to ensure that code works in old and new browsers.

Was the lint report ignored? Launchpad’s make lint command uses jslint to prevent known issues before they are merged into trunk. There are still a lot is issues reported in the old lazr modules that need fixing. We fixed coercion mistakes and unnested functions created in loops to address bugs in older browsers.

Which version of EcmaScript? There were a lot of failures caused by unsafe ES5 calls. William fixed many script failures in older browsers by ensuring that Y.Array() is called properly. It is very important to understand that Y.Array() returns a native array. This call is pointless:

var finklesnarks = Y.Array([]);

This call is dangerous because it creates a native ES3 array in older browsers, then calls an ES5 method:


I was the author of some of these bad calls. The safe way to use ES5 array with YUI is:

Y.Array.indexOf(finklesnarks, fnord);

Are events happening in a different order? Are links doing both script actions and standard actions? YUI docs describe event bubbling, capturing is never mentioned. I thought this meant that YUI had disabled the capture phase of event propagation, simplifying how we work with events. No, this is not the case. Firefox and Chromium still prefer capture propagation, and IE uses bubbling propagation exclusively. Actions that work in the former browsers often have secondary, and wrong, actions happening in IE. This is because Firefox and Chromium are done propagating, but IE is just starting. Most Launchpad click handlers use e.preventDefault(), which means “stop the default action, continue propagating”. IE does continue propagating and unexpected things happen. A lot of Launchpad links work more by accident rather than by design. The correct method to call is e.halt() which stops the default action and propagation. We want to use halt() most of the time. In cases where we want multiple subscribers to respond to an event, we are using a custom event.

Does YUI docs demonstrate that the code will work? This is an odd point to check, but a lot of code was merged into Launchpad trunk without regard to YUI documentation. The bug status widgets did not appear on click in some browsers because they are designed to only display if you used the left mouse button. But YUI documentation states that the button can only be known in the mouseup event…the mouse property explicitly states that it is not for use with click. Removing the unsupported check of event.button fixed a bug that has been open for 3 years.

Is This a Broken Browser Problem?

These are the cases where developers must write code to reconcile the differences between browser implementations, or choose to not support the browser.

Non-conformant surprises are cases where browsers claim do support a feature but do not. Launchpad new bug listing UI depends on history management to sort columns and show batches. History management depends on URLs, but IE’s Link.pathname is missing the leading slash so URLs were not relative from root. The fix is trivial once you see the invalid paths in Launchpad’s oops reports and then look at the code that makes URLs. As we do in Launchpad’s python code, the method that wraps the pathname ensures there is a leading slash.

Alternate API nuisances are cases where the browser doesn’t support the methods the script uses, and neither does YUI. The bug tag autocomplete feature never worked in IE, but there was code checking for it. I first refactored the method to check for the methods Launchpad prefers, then checks for the alternate methods. This was hard to fix, I spent an hour reading about how IE creates selection ranges before I could write a 5-line block to do what element.endSelection does.

Unsupported nightmares are cases where neither the browser or YUI support the method. There is one case in Launchpad were this happens. The series timelines use canvas to draw the series, milestones, and releases. It was disabled for all IE version, but IE 9 does support canvas if the page states it is HTML5 . Instead of checking for browser version, I created a method that checks if the browser can create the canvas, and if so, the series timeline is rendered. IE 8 and below do not get the interactive image. Other browsers that I have not planned for will show the canvas if they pass the check.

How do I ensure a browser falls back to working code?

At this moment, there is only one guard that prevents KHtml browsers using a feature. There might come a time to add more guards because Launchpad, YUI, and a kind of browser do not work, and no one has time to make it work. We need to know the browser version that was tested and the version of YUI, for example:

if ( < 6 && Y.version <= 3.3)

I think we want several experienced YUI developers to agree that this is the proper course before giving up though. When a new version of the browser or YUI is released, we know to check the feature. Does the guard need to be revised, or can it be removed?

Face painting and historical Web development

I spent my last two weekends working with ancient web technologies. Anne decided she wanted to update her Happy Faces web to attract more face painting business. I agreed to create a form for customers to inquire about rates and availability. The hosting service only offered Python 2.4,  CGI, and sendmail.

I really did not want to write a script that I knew others had written. I just wanted to make a pretty little form to help Anne. I found one library that almost worked.  I knew I could write a better library, and I would not trust any library without a test suite. I decided to write my own that would manage the request and response form, sending emails, and storing them if sendmail failed. I wrote a simple means to define a schema of what fields are in the form and how to validate them. The test module even provides a test web server that runs the CGIs you place in the root directory. This was a fine meditative exercise, but I would not describe it as fun.

I did have fun creating Anne’s contact form. Defining the schema for her form took minutes, and it was painless to make changes as we discussed what was optional and what the wording should be. The web page is not historical, it is very modern in fact. It uses HTML 5 form inputs and JavaScript to collect the information. The new  form inputs work in HTML 4 browsers like IE and FireFox, but HTML 5 browsers like Chromium and Safari see widgets that require less typing, less thinking about what to input.

I posted my CGI contact library on Launchpad for anyone who finds they need to work with historical technology.