Bug 1415957 - Remove MozMill from TPS. r=tcsc
authorEdouard Oger <eoger@fastmail.com>
Thu, 09 Nov 2017 15:34:06 -0500
changeset 696230 c60bbbbc53d3b798cec0b578ea3c4b7e41f720bd
parent 696229 6fe2a24e51cad359aa5d42f8792b434f61a38bb6
child 696231 0489e522ece134137434a449539228dad4849678
push id88670
push userluca.greco@alcacoop.it
push dateFri, 10 Nov 2017 10:12:18 +0000
reviewerstcsc
bugs1415957
milestone58.0a1
Bug 1415957 - Remove MozMill from TPS. r=tcsc MozReview-Commit-ID: HyBXrNqhzIf
.eslintignore
services/sync/tests/tps/.eslintrc.js
services/sync/tests/tps/mozmill_sanity.js
services/sync/tests/tps/mozmill_sanity2.js
services/sync/tests/tps/test_mozmill_sanity.js
services/sync/tests/unit/test_doctor.js
services/sync/tps/extensions/mozmill/chrome.manifest
services/sync/tps/extensions/mozmill/install.rdf
services/sync/tps/extensions/mozmill/resource/driver/controller.js
services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
services/sync/tps/extensions/mozmill/resource/driver/mozmill.js
services/sync/tps/extensions/mozmill/resource/driver/msgbroker.js
services/sync/tps/extensions/mozmill/resource/modules/assertions.js
services/sync/tps/extensions/mozmill/resource/modules/driver.js
services/sync/tps/extensions/mozmill/resource/modules/errors.js
services/sync/tps/extensions/mozmill/resource/modules/frame.js
services/sync/tps/extensions/mozmill/resource/modules/l10n.js
services/sync/tps/extensions/mozmill/resource/modules/stack.js
services/sync/tps/extensions/mozmill/resource/modules/windows.js
services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js
services/sync/tps/extensions/mozmill/resource/stdlib/arrays.js
services/sync/tps/extensions/mozmill/resource/stdlib/dom.js
services/sync/tps/extensions/mozmill/resource/stdlib/httpd.js
services/sync/tps/extensions/mozmill/resource/stdlib/json2.js
services/sync/tps/extensions/mozmill/resource/stdlib/objects.js
services/sync/tps/extensions/mozmill/resource/stdlib/os.js
services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js
services/sync/tps/extensions/mozmill/resource/stdlib/strings.js
services/sync/tps/extensions/mozmill/resource/stdlib/utils.js
services/sync/tps/extensions/mozmill/resource/stdlib/withs.js
services/sync/tps/extensions/tps/resource/tps.jsm
testing/tps/tps/testrunner.py
tools/lint/eslint/modules.json
--- a/.eslintignore
+++ b/.eslintignore
@@ -329,17 +329,16 @@ testing/talos/talos/tests/kraken/**
 
 testing/web-platform/**
 testing/xpcshell/moz-http2/**
 testing/xpcshell/node-http2/**
 
 # Third party services
 services/common/kinto-http-client.js
 services/common/kinto-offline-client.js
-services/sync/tps/extensions/mozmill
 
 # toolkit/ exclusions
 
 # Not part of the default build
 toolkit/components/help/**
 
 # Intentionally invalid JS
 toolkit/components/workerloader/tests/moduleF-syntax-error.js
--- a/services/sync/tests/tps/.eslintrc.js
+++ b/services/sync/tests/tps/.eslintrc.js
@@ -1,33 +1,27 @@
 "use strict";
 
 module.exports = {
   "extends": [
     "plugin:mozilla/mochitest-test"
   ],
 
   globals: {
-    // Globals specific to mozmill
-    "assert": false,
-    "controller": false,
-    "findElement": false,
-    "mozmill": false,
     // Injected into tests via tps.jsm
     "Addons": false,
     "Bookmarks": false,
     "EnableEngines": false,
     "EnsureTracking": false,
     "Formdata": false,
     "History": false,
     "Login": false,
     "Passwords": false,
     "Phase": false,
     "Prefs": false,
-    "RunMozmillTest": false,
     "STATE_DISABLED": false,
     "STATE_ENABLED": false,
     "Sync": false,
     "SYNC_WIPE_CLIENT": false,
     "SYNC_WIPE_REMOTE": false,
     "Tabs": false,
     "Windows": false,
     "WipeServer": false,
deleted file mode 100644
--- a/services/sync/tests/tps/mozmill_sanity.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-Components.utils.import("resource://tps/tps.jsm");
-
-var setupModule = function(module) {
-  module.controller = mozmill.getBrowserController();
-  assert.ok(true, "SetupModule passes");
-};
-
-var setupTest = function(module) {
-  assert.ok(true, "SetupTest passes");
-};
-
-var testTestStep = function() {
-  assert.ok(true, "test Passes");
-  controller.open("http://www.mozilla.org");
-
-  TPS.Login();
-  TPS.Sync(ACTIONS.ACTION_SYNC_WIPE_CLIENT);
-};
-
-var teardownTest = function() {
-  assert.ok(true, "teardownTest passes");
-};
-
-var teardownModule = function() {
-  assert.ok(true, "teardownModule passes");
-};
deleted file mode 100644
--- a/services/sync/tests/tps/mozmill_sanity2.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var setupModule = function(module) {
-  module.controller = mozmill.getBrowserController();
-};
-
-var testGetNode = function() {
-  controller.open("about:support");
-  controller.waitForPageLoad();
-
-  var appbox = findElement.ID(controller.tabs.activeTab, "application-box");
-  assert.waitFor(() => appbox.getNode().textContent == "Firefox", "correct app name");
-};
deleted file mode 100644
--- a/services/sync/tests/tps/test_mozmill_sanity.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/*
- * The list of phases mapped to their corresponding profiles.  The object
- * here must be in strict JSON format, as it will get parsed by the Python
- * testrunner (no single quotes, extra comma's, etc).
- */
-
-var phases = { "phase1": "profile1",
-               "phase2": "profile2" };
-
-/*
- * Test phases
- */
-
-Phase("phase1", [
-  [RunMozmillTest, "mozmill_sanity.js"],
-]);
-
-Phase("phase2", [
-  [Sync],
-  [RunMozmillTest, "mozmill_sanity2.js"],
-]);
--- a/services/sync/tests/unit/test_doctor.js
+++ b/services/sync/tests/unit/test_doctor.js
@@ -161,17 +161,17 @@ add_task(async function test_repairs_ski
   let engine = {
     name: "test-engine",
     getValidator() {
       return validator;
     }
   };
   let requestor = {
     async startRepairs(validationInfo, flowID) {
-      assert.ok(false, "Never should start repairs");
+      ok(false, "Never should start repairs");
     },
     tryServerOnlyRepairs() {
       return false;
     }
   };
   let doctor = mockDoctor({
     _getEnginesToValidate(recentlySyncedEngines) {
       deepEqual(recentlySyncedEngines, [engine]);
deleted file mode 100755
--- a/services/sync/tps/extensions/mozmill/chrome.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-resource    mozmill                 resource/
-
deleted file mode 100755
--- a/services/sync/tps/extensions/mozmill/install.rdf
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-
-   <Description about="urn:mozilla:install-manifest">
-     <em:id>mozmill@mozilla.com</em:id>
-     <em:name>Mozmill</em:name>
-     <em:version>2.0.8</em:version>
-     <em:description>UI Automation tool for Mozilla applications</em:description>
-     <em:unpack>true</em:unpack>
-
-     <em:creator>Mozilla Automation and Testing Team</em:creator>
-     <em:contributor>Adam Christian</em:contributor>
-     <em:contributor>Mikeal Rogers</em:contributor>
-
-     <em:targetApplication>
-       <Description>
-         <em:id>toolkit@mozilla.org</em:id>
-         <em:minVersion>10.0</em:minVersion>
-         <em:maxVersion>38.*</em:maxVersion>
-       </Description>
-     </em:targetApplication>
-     <em:multiprocessCompatible>true</em:multiprocessCompatible>
-   </Description>
-</RDF>
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/controller.js
+++ /dev/null
@@ -1,1139 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["MozMillController", "globalEventRegistry",
-                        "sleep", "windowMap"];
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-var EventUtils = {}; Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
-
-var assertions = {}; Cu.import('resource://mozmill/modules/assertions.js', assertions);
-var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
-var elementslib = {}; Cu.import('resource://mozmill/driver/elementslib.js', elementslib);
-var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
-var mozelement = {}; Cu.import('resource://mozmill/driver/mozelement.js', mozelement);
-var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
-var windows = {}; Cu.import('resource://mozmill/modules/windows.js', windows);
-
-// Declare most used utils functions in the controller namespace
-var assert = new assertions.Assert();
-var waitFor = assert.waitFor;
-
-var sleep = utils.sleep;
-
-// For Mozmill 1.5 backward compatibility
-var windowMap = windows.map;
-
-var waitForEvents = function () {
-}
-
-waitForEvents.prototype = {
-  /**
-   * Initialize list of events for given node
-   */
-  init: function waitForEvents_init(node, events) {
-    if (node.getNode != undefined)
-      node = node.getNode();
-
-    this.events = events;
-    this.node = node;
-    node.firedEvents = {};
-    this.registry = {};
-
-    if (!events) {
-      return;
-    }
-    for (var key in events) {
-      var e = events[key];
-      var listener = function (event) {
-        this.firedEvents[event.type] = true;
-      }
-
-      this.registry[e] = listener;
-      this.registry[e].result = false;
-      this.node.addEventListener(e, this.registry[e], true);
-    }
-  },
-
-  /**
-   * Wait until all assigned events have been fired
-   */
-  wait: function waitForEvents_wait(timeout, interval) {
-    for (var e in this.registry) {
-      assert.waitFor(function () {
-        return this.node.firedEvents[e] == true;
-      }, "waitForEvents.wait(): Event '" + e + "' has been fired.", timeout, interval);
-
-      this.node.removeEventListener(e, this.registry[e], true);
-    }
-  }
-}
-
-/**
- * Class to handle menus and context menus
- *
- * @constructor
- * @param {MozMillController} controller
- *        Mozmill controller of the window under test
- * @param {string} menuSelector
- *        jQuery like selector string of the element
- * @param {object} document
- *        Document to use for finding the menu
- *        [optional - default: aController.window.document]
- */
-var Menu = function (controller, menuSelector, document) {
-  this._controller = controller;
-  this._menu = null;
-
-  document = document || controller.window.document;
-  var node = document.querySelector(menuSelector);
-  if (node) {
-    // We don't unwrap nodes automatically yet (Bug 573185)
-    node = node.wrappedJSObject || node;
-    this._menu = new mozelement.Elem(node);
-  } else {
-    throw new Error("Menu element '" + menuSelector + "' not found.");
-  }
-}
-
-Menu.prototype = {
-
-  /**
-   * Open and populate the menu
-   *
-   * @param {ElemBase} contextElement
-   *        Element whose context menu has to be opened
-   * @returns {Menu} The Menu instance
-   */
-  open: function Menu_open(contextElement) {
-    // We have to open the context menu
-    var menu = this._menu.getNode();
-    if ((menu.localName == "popup" || menu.localName == "menupopup") &&
-        contextElement && contextElement.exists()) {
-      this._controller.rightClick(contextElement);
-      assert.waitFor(function () {
-        return menu.state == "open";
-      }, "Context menu has been opened.");
-    }
-
-    // Run through the entire menu and populate with dynamic entries
-    this._buildMenu(menu);
-
-    return this;
-  },
-
-  /**
-   * Close the menu
-   *
-   * @returns {Menu} The Menu instance
-   */
-  close: function Menu_close() {
-    var menu = this._menu.getNode();
-
-    this._controller.keypress(this._menu, "VK_ESCAPE", {});
-    assert.waitFor(function () {
-      return menu.state == "closed";
-    }, "Context menu has been closed.");
-
-    return this;
-  },
-
-  /**
-   * Retrieve the specified menu entry
-   *
-   * @param {string} itemSelector
-   *        jQuery like selector string of the menu item
-   * @returns {ElemBase} Menu element
-   * @throws Error If menu element has not been found
-   */
-  getItem: function Menu_getItem(itemSelector) {
-    // Run through the entire menu and populate with dynamic entries
-    this._buildMenu(this._menu.getNode());
-
-    var node = this._menu.getNode().querySelector(itemSelector);
-
-    if (!node) {
-      throw new Error("Menu entry '" + itemSelector + "' not found.");
-    }
-
-    return new mozelement.Elem(node);
-  },
-
-  /**
-   * Click the specified menu entry
-   *
-   * @param {string} itemSelector
-   *        jQuery like selector string of the menu item
-   *
-   * @returns {Menu} The Menu instance
-   */
-  click: function Menu_click(itemSelector) {
-    this._controller.click(this.getItem(itemSelector));
-
-    return this;
-  },
-
-  /**
-   * Synthesize a keypress against the menu
-   *
-   * @param {string} key
-   *        Key to press
-   * @param {object} modifier
-   *        Key modifiers
-   * @see MozMillController#keypress
-   *
-   * @returns {Menu} The Menu instance
-   */
-  keypress: function Menu_keypress(key, modifier) {
-    this._controller.keypress(this._menu, key, modifier);
-
-    return this;
-  },
-
-  /**
-   * Opens the context menu, click the specified entry and
-   * make sure that the menu has been closed.
-   *
-   * @param {string} itemSelector
-   *        jQuery like selector string of the element
-   * @param {ElemBase} contextElement
-   *        Element whose context menu has to be opened
-   *
-   * @returns {Menu} The Menu instance
-   */
-  select: function Menu_select(itemSelector, contextElement) {
-    this.open(contextElement);
-    this.click(itemSelector);
-    this.close();
-  },
-
-  /**
-   * Recursive function which iterates through all menu elements and
-   * populates the menus with dynamic menu entries.
-   *
-   * @param {node} menu
-   *        Top menu node whose elements have to be populated
-   */
-  _buildMenu: function Menu__buildMenu(menu) {
-    var items = menu ? menu.childNodes : null;
-
-    Array.forEach(items, function (item) {
-      // When we have a menu node, fake a click onto it to populate
-      // the sub menu with dynamic entries
-      if (item.tagName == "menu") {
-        var popup = item.querySelector("menupopup");
-
-        if (popup) {
-          var popupEvent = this._controller.window.document.createEvent("MouseEvent");
-          popupEvent.initMouseEvent("popupshowing", true, true,
-                                    this._controller.window, 0, 0, 0, 0, 0,
-                                    false, false, false, false, 0, null);
-          popup.dispatchEvent(popupEvent);
-
-          this._buildMenu(popup);
-        }
-      }
-    }, this);
-  }
-};
-
-var MozMillController = function (window) {
-  this.window = window;
-
-  this.mozmillModule = {};
-  Cu.import('resource://mozmill/driver/mozmill.js', this.mozmillModule);
-
-  var self = this;
-  assert.waitFor(function () {
-    return window != null && self.isLoaded();
-  }, "controller(): Window has been initialized.");
-
-  // Ensure to focus the window which will move it virtually into the foreground
-  // when focusmanager.testmode is set enabled.
-  this.window.focus();
-
-  var windowType = window.document.documentElement.getAttribute('windowtype');
-  if (controllerAdditions[windowType] != undefined ) {
-    this.prototype = new utils.Copy(this.prototype);
-    controllerAdditions[windowType](this);
-    this.windowtype = windowType;
-  }
-}
-
-/**
- * Returns the global browser object of the window
- *
- * @returns {Object} The browser object
- */
-MozMillController.prototype.__defineGetter__("browserObject", function () {
-  return utils.getBrowserObject(this.window);
-});
-
-// constructs a MozMillElement from the controller's window
-MozMillController.prototype.__defineGetter__("rootElement", function () {
-  if (this._rootElement == undefined) {
-    let docElement = this.window.document.documentElement;
-    this._rootElement = new mozelement.MozMillElement("Elem", docElement);
-  }
-
-  return this._rootElement;
-});
-
-MozMillController.prototype.sleep = utils.sleep;
-MozMillController.prototype.waitFor = assert.waitFor;
-
-// Open the specified url in the current tab
-MozMillController.prototype.open = function (url) {
-  switch (this.mozmillModule.Application) {
-    case "Firefox":
-      // Stop a running page load to not overlap requests
-      if (this.browserObject.selectedBrowser) {
-        this.browserObject.selectedBrowser.stop();
-      }
-
-      this.browserObject.loadURI(url);
-      break;
-
-    default:
-      throw new Error("MozMillController.open not supported.");
-  }
-
-  broker.pass({'function':'Controller.open()'});
-}
-
-/**
- * Take a screenshot of specified node
- *
- * @param {Element} node
- *        The window or DOM element to capture
- * @param {String} name
- *        The name of the screenshot used in reporting and as filename
- * @param {Boolean} save
- *        If true saves the screenshot as 'name.jpg' in tempdir,
- *        otherwise returns a dataURL
- * @param {Element[]} highlights
- *        A list of DOM elements to highlight by drawing a red rectangle around them
- *
- * @returns {Object} Object which contains properties like filename, dataURL,
- *          name and timestamp of the screenshot
- */
-MozMillController.prototype.screenshot = function (node, name, save, highlights) {
-  if (!node) {
-    throw new Error("node is undefined");
-  }
-
-  // Unwrap the node and highlights
-  if ("getNode" in node) {
-    node = node.getNode();
-  }
-
-  if (highlights) {
-    for (var i = 0; i < highlights.length; ++i) {
-      if ("getNode" in highlights[i]) {
-        highlights[i] = highlights[i].getNode();
-      }
-    }
-  }
-
-  // If save is false, a dataURL is used
-  // Include both in the report anyway to avoid confusion and make the report easier to parse
-  var screenshot = {"filename": undefined,
-                    "dataURL": utils.takeScreenshot(node, highlights),
-                    "name": name,
-                    "timestamp": new Date().toLocaleString()};
-
-  if (!save) {
-    return screenshot;
-  }
-
-  // Save the screenshot to disk
-
-  let {filename, failure} = utils.saveDataURL(screenshot.dataURL, name);
-  screenshot.filename = filename;
-  screenshot.failure = failure;
-
-  if (failure) {
-    broker.log({'function': 'controller.screenshot()',
-                'message': 'Error writing to file: ' + screenshot.filename});
-  } else {
-    // Send the screenshot object to python over jsbridge
-    broker.sendMessage("screenshot", screenshot);
-    broker.pass({'function': 'controller.screenshot()'});
-  }
-
-  return screenshot;
-}
-
-/**
- * Checks if the specified window has been loaded
- *
- * @param {DOMWindow} [aWindow=this.window] Window object to check for loaded state
- */
-MozMillController.prototype.isLoaded = function (aWindow) {
-  var win = aWindow || this.window;
-
-  return windows.map.getValue(utils.getWindowId(win), "loaded") || false;
-};
-
-MozMillController.prototype.__defineGetter__("waitForEvents", function () {
-  if (this._waitForEvents == undefined) {
-    this._waitForEvents = new waitForEvents();
-  }
-
-  return this._waitForEvents;
-});
-
-/**
- * Wrapper function to create a new instance of a menu
- * @see Menu
- */
-MozMillController.prototype.getMenu = function (menuSelector, document) {
-  return new Menu(this, menuSelector, document);
-};
-
-MozMillController.prototype.__defineGetter__("mainMenu", function () {
-  return this.getMenu("menubar");
-});
-
-MozMillController.prototype.__defineGetter__("menus", function () {
-  logDeprecated('controller.menus', 'Use controller.mainMenu instead');
-});
-
-MozMillController.prototype.waitForImage = function (aElement, timeout, interval) {
-  this.waitFor(function () {
-    return aElement.getNode().complete == true;
-  }, "timeout exceeded for waitForImage " + aElement.getInfo(), timeout, interval);
-
-  broker.pass({'function':'Controller.waitForImage()'});
-}
-
-MozMillController.prototype.startUserShutdown = function (timeout, restart, next, resetProfile) {
-  if (restart && resetProfile) {
-    throw new Error("You can't have a user-restart and reset the profile; there is a race condition");
-  }
-
-  let shutdownObj = {
-    'user': true,
-    'restart': Boolean(restart),
-    'next': next,
-    'resetProfile': Boolean(resetProfile),
-    'timeout': timeout
-  };
-
-  broker.sendMessage('shutdown', shutdownObj);
-}
-
-/**
- * Restart the application
- *
- * @param {string} aNext
- *        Name of the next test function to run after restart
- * @param {boolean} [aFlags=undefined]
- *        Additional flags how to handle the shutdown or restart.
- * @see https://developer.mozilla.org/nsIAppStartup#Attributes
- */
-MozMillController.prototype.restartApplication = function (aNext, aFlags) {
-  var flags = Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart;
-
-  if (aFlags) {
-    flags |= aFlags;
-  }
-
-  broker.sendMessage('shutdown', {'user': false,
-                                  'restart': true,
-                                  'flags': flags,
-                                  'next': aNext,
-                                  'timeout': 0 });
-
-  // We have to ensure to stop the test from continuing until the application is
-  // shutting down. The only way to do that is by throwing an exception.
-  throw new errors.ApplicationQuitError();
-}
-
-/**
- * Stop the application
- *
- * @param {boolean} [aResetProfile=false]
- *        Whether to reset the profile during restart
- * @param {boolean} [aFlags=undefined]
- *        Additional flags how to handle the shutdown or restart.
- * @see https://developer.mozilla.org/nsIAppStartup#Attributes
- */
-MozMillController.prototype.stopApplication = function (aResetProfile, aFlags) {
-  var flags = Ci.nsIAppStartup.eAttemptQuit;
-
-  if (aFlags) {
-    flags |= aFlags;
-  }
-
-  broker.sendMessage('shutdown', {'user': false,
-                                  'restart': false,
-                                  'flags': flags,
-                                  'resetProfile': aResetProfile,
-                                  'timeout': 0 });
-
-  // We have to ensure to stop the test from continuing until the application is
-  // shutting down. The only way to do that is by throwing an exception.
-  throw new errors.ApplicationQuitError();
-}
-
-//Browser navigation functions
-MozMillController.prototype.goBack = function () {
-  this.window.content.history.back();
-  broker.pass({'function':'Controller.goBack()'});
-
-  return true;
-}
-
-MozMillController.prototype.goForward = function () {
-  this.window.content.history.forward();
-  broker.pass({'function':'Controller.goForward()'});
-
-  return true;
-}
-
-MozMillController.prototype.refresh = function () {
-  this.window.content.location.reload(true);
-  broker.pass({'function':'Controller.refresh()'});
-
-  return true;
-}
-
-function logDeprecated(funcName, message) {
-  broker.log({'function': funcName + '() - DEPRECATED',
-              'message': funcName + '() is deprecated. ' + message});
-}
-
-function logDeprecatedAssert(funcName) {
-   logDeprecated('controller.' + funcName,
-                 '. Use the generic `assertion` module instead.');
-}
-
-MozMillController.prototype.assertText = function (el, text) {
-  logDeprecatedAssert("assertText");
-
-  var n = el.getNode();
-
-  if (n && n.innerHTML == text) {
-    broker.pass({'function': 'Controller.assertText()'});
-  } else {
-    throw new Error("could not validate element " + el.getInfo() +
-                    " with text "+ text);
-  }
-
-  return true;
-};
-
-/**
- * Assert that a specified node exists
- */
-MozMillController.prototype.assertNode = function (el) {
-  logDeprecatedAssert("assertNode");
-
-  //this.window.focus();
-  var element = el.getNode();
-  if (!element) {
-    throw new Error("could not find element " + el.getInfo());
-  }
-
-  broker.pass({'function': 'Controller.assertNode()'});
-  return true;
-};
-
-/**
- * Assert that a specified node doesn't exist
- */
-MozMillController.prototype.assertNodeNotExist = function (el) {
-  logDeprecatedAssert("assertNodeNotExist");
-
-  try {
-    var element = el.getNode();
-  } catch (e) {
-    broker.pass({'function': 'Controller.assertNodeNotExist()'});
-  }
-
-  if (element) {
-    throw new Error("Unexpectedly found element " + el.getInfo());
-  } else {
-    broker.pass({'function':'Controller.assertNodeNotExist()'});
-  }
-
-  return true;
-};
-
-/**
- * Assert that a form element contains the expected value
- */
-MozMillController.prototype.assertValue = function (el, value) {
-  logDeprecatedAssert("assertValue");
-
-  var n = el.getNode();
-
-  if (n && n.value == value) {
-    broker.pass({'function': 'Controller.assertValue()'});
-  } else {
-    throw new Error("could not validate element " + el.getInfo() +
-                    " with value " + value);
-  }
-
-  return false;
-};
-
-/**
- * Check if the callback function evaluates to true
- */
-MozMillController.prototype.assert = function (callback, message, thisObject) {
-  logDeprecatedAssert("assert");
-
-  utils.assert(callback, message, thisObject);
-  broker.pass({'function': ": controller.assert('" + callback + "')"});
-
-  return true;
-}
-
-/**
- * Assert that a provided value is selected in a select element
- */
-MozMillController.prototype.assertSelected = function (el, value) {
-  logDeprecatedAssert("assertSelected");
-
-  var n = el.getNode();
-  var validator = value;
-
-  if (n && n.options[n.selectedIndex].value == validator) {
-    broker.pass({'function':'Controller.assertSelected()'});
-  } else {
-    throw new Error("could not assert value for element " + el.getInfo() +
-                    " with value " + value);
-  }
-
-  return true;
-};
-
-/**
- * Assert that a provided checkbox is checked
- */
-MozMillController.prototype.assertChecked = function (el) {
-  logDeprecatedAssert("assertChecked");
-
-  var element = el.getNode();
-
-  if (element && element.checked == true) {
-    broker.pass({'function':'Controller.assertChecked()'});
-  } else {
-    throw new Error("assert failed for checked element " + el.getInfo());
-  }
-
-  return true;
-};
-
-/**
- * Assert that a provided checkbox is not checked
- */
-MozMillController.prototype.assertNotChecked = function (el) {
-  logDeprecatedAssert("assertNotChecked");
-
-  var element = el.getNode();
-
-  if (!element) {
-    throw new Error("Could not find element" + el.getInfo());
-  }
-
-  if (!element.hasAttribute("checked") || element.checked != true) {
-    broker.pass({'function': 'Controller.assertNotChecked()'});
-  } else {
-    throw new Error("assert failed for not checked element " + el.getInfo());
-  }
-
-  return true;
-};
-
-/**
- * Assert that an element's javascript property exists or has a particular value
- *
- * if val is undefined, will return true if the property exists.
- * if val is specified, will return true if the property exists and has the correct value
- */
-MozMillController.prototype.assertJSProperty = function (el, attrib, val) {
-  logDeprecatedAssert("assertJSProperty");
-
-  var element = el.getNode();
-
-  if (!element){
-    throw new Error("could not find element " + el.getInfo());
-  }
-
-  var value = element[attrib];
-  var res = (value !== undefined && (val === undefined ? true :
-                                                         String(value) == String(val)));
-  if (res) {
-    broker.pass({'function':'Controller.assertJSProperty("' + el.getInfo() + '") : ' + val});
-  } else {
-    throw new Error("Controller.assertJSProperty(" + el.getInfo() + ") : " +
-                    (val === undefined ? "property '" + attrib +
-                    "' doesn't exist" : val + " == " + value));
-  }
-
-  return true;
-};
-
-/**
- * Assert that an element's javascript property doesn't exist or doesn't have a particular value
- *
- * if val is undefined, will return true if the property doesn't exist.
- * if val is specified, will return true if the property doesn't exist or doesn't have the specified value
- */
-MozMillController.prototype.assertNotJSProperty = function (el, attrib, val) {
-  logDeprecatedAssert("assertNotJSProperty");
-
-  var element = el.getNode();
-
-  if (!element){
-    throw new Error("could not find element " + el.getInfo());
-  }
-
-  var value = element[attrib];
-  var res = (val === undefined ? value === undefined : String(value) != String(val));
-  if (res) {
-    broker.pass({'function':'Controller.assertNotProperty("' + el.getInfo() + '") : ' + val});
-  } else {
-    throw new Error("Controller.assertNotJSProperty(" + el.getInfo() + ") : " +
-                    (val === undefined ? "property '" + attrib +
-                    "' exists" : val + " != " + value));
-  }
-
-  return true;
-};
-
-/**
- * Assert that an element's dom property exists or has a particular value
- *
- * if val is undefined, will return true if the property exists.
- * if val is specified, will return true if the property exists and has the correct value
- */
-MozMillController.prototype.assertDOMProperty = function (el, attrib, val) {
-  logDeprecatedAssert("assertDOMProperty");
-
-  var element = el.getNode();
-
-  if (!element){
-    throw new Error("could not find element " + el.getInfo());
-  }
-
-  var value, res = element.hasAttribute(attrib);
-  if (res && val !== undefined) {
-    value = element.getAttribute(attrib);
-    res = (String(value) == String(val));
-  }
-
-  if (res) {
-    broker.pass({'function':'Controller.assertDOMProperty("' + el.getInfo() + '") : ' + val});
-  } else {
-    throw new Error("Controller.assertDOMProperty(" + el.getInfo() + ") : " +
-                    (val === undefined ? "property '" + attrib +
-                    "' doesn't exist" : val + " == " + value));
-  }
-
-  return true;
-};
-
-/**
- * Assert that an element's dom property doesn't exist or doesn't have a particular value
- *
- * if val is undefined, will return true if the property doesn't exist.
- * if val is specified, will return true if the property doesn't exist or doesn't have the specified value
- */
-MozMillController.prototype.assertNotDOMProperty = function (el, attrib, val) {
-  logDeprecatedAssert("assertNotDOMProperty");
-
-  var element = el.getNode();
-
-  if (!element) {
-    throw new Error("could not find element " + el.getInfo());
-  }
-
-  var value, res = element.hasAttribute(attrib);
-  if (res && val !== undefined) {
-    value = element.getAttribute(attrib);
-    res = (String(value) == String(val));
-  }
-
-  if (!res) {
-    broker.pass({'function':'Controller.assertNotDOMProperty("' + el.getInfo() + '") : ' + val});
-  } else {
-    throw new Error("Controller.assertNotDOMProperty(" + el.getInfo() + ") : " +
-                    (val == undefined ? "property '" + attrib +
-                    "' exists" : val + " == " + value));
-  }
-
-  return true;
-};
-
-/**
- * Assert that a specified image has actually loaded. The Safari workaround results
- * in additional requests for broken images (in Safari only) but works reliably
- */
-MozMillController.prototype.assertImageLoaded = function (el) {
-  logDeprecatedAssert("assertImageLoaded");
-
-  var img = el.getNode();
-
-  if (!img || img.tagName != 'IMG') {
-    throw new Error('Controller.assertImageLoaded() failed.')
-    return false;
-  }
-
-  var comp = img.complete;
-  var ret = null; // Return value
-
-  // Workaround for Safari -- it only supports the
-  // complete attrib on script-created images
-  if (typeof comp == 'undefined') {
-    let test = new Image();
-    // If the original image was successfully loaded,
-    // src for new one should be pulled from cache
-    test.src = img.src;
-    comp = test.complete;
-  }
-
-  // Check the complete attrib. Note the strict
-  // equality check -- we don't want undefined, null, etc.
-  // --------------------------
-  if (comp === false) {
-    // False -- Img failed to load in IE/Safari, or is
-    // still trying to load in FF
-    ret = false;
-  } else if (comp === true && img.naturalWidth == 0) {
-    // True, but image has no size -- image failed to
-    // load in FF
-    ret = false;
-  } else {
-    // Otherwise all we can do is assume everything's
-    // hunky-dory
-   ret = true;
-  }
-
-  if (ret) {
-    broker.pass({'function':'Controller.assertImageLoaded'});
-  } else {
-    throw new Error('Controller.assertImageLoaded() failed.')
-  }
-
-  return true;
-};
-
-/**
- * Drag one element to the top x,y coords of another specified element
- */
-MozMillController.prototype.mouseMove = function (doc, start, dest) {
-  // if one of these elements couldn't be looked up
-  if (typeof start != 'object'){
-    throw new Error("received bad coordinates");
-  }
-
-  if (typeof dest != 'object'){
-    throw new Error("received bad coordinates");
-  }
-
-  var triggerMouseEvent = function (element, clientX, clientY) {
-    clientX = clientX ? clientX: 0;
-    clientY = clientY ? clientY: 0;
-
-    // make the mouse understand where it is on the screen
-    var screenX = element.boxObject.screenX ? element.boxObject.screenX : 0;
-    var screenY = element.boxObject.screenY ? element.boxObject.screenY : 0;
-
-    var evt = element.ownerDocument.createEvent('MouseEvents');
-    if (evt.initMouseEvent) {
-      evt.initMouseEvent('mousemove', true, true, element.ownerGlobal,
-                         1, screenX, screenY, clientX, clientY);
-    } else {
-      evt.initEvent('mousemove', true, true);
-    }
-
-    element.dispatchEvent(evt);
-  };
-
-  // Do the initial move to the drag element position
-  triggerMouseEvent(doc.body, start[0], start[1]);
-  triggerMouseEvent(doc.body, dest[0], dest[1]);
-
-  broker.pass({'function':'Controller.mouseMove()'});
-  return true;
-}
-
-/**
- * Drag an element to the specified offset on another element, firing mouse and
- * drag events. Adapted from EventUtils.js synthesizeDrop()
- *
- * @deprecated Use the MozMillElement object
- *
- * @param {MozElement} aSrc
- *        Source element to be dragged
- * @param {MozElement} aDest
- *        Destination element over which the drop occurs
- * @param {Number} [aOffsetX=element.width/2]
- *        Relative x offset for dropping on the aDest element
- * @param {Number} [aOffsetY=element.height/2]
- *        Relative y offset for dropping on the aDest element
- * @param {DOMWindow} [aSourceWindow=this.element.ownerDocument.defaultView]
- *        Custom source Window to be used.
- * @param {String} [aDropEffect="move"]
- *        Effect used for the drop event
- * @param {Object[]} [aDragData]
- *        An array holding custom drag data to be used during the drag event
- *        Format: [{ type: "text/plain", "Text to drag"}, ...]
- *
- * @returns {String} the captured dropEffect
- */
-MozMillController.prototype.dragToElement = function (aSrc, aDest, aOffsetX,
-                                                      aOffsetY, aSourceWindow,
-                                                      aDropEffect, aDragData) {
-  logDeprecated("controller.dragToElement", "Use the MozMillElement object.");
-  return aSrc.dragToElement(aDest, aOffsetX, aOffsetY, aSourceWindow, null,
-                            aDropEffect, aDragData);
-};
-
-function Tabs(controller) {
-  this.controller = controller;
-}
-
-Tabs.prototype.getTab = function (index) {
-  return this.controller.browserObject.browsers[index].contentDocument;
-}
-
-Tabs.prototype.__defineGetter__("activeTab", function () {
-  return this.controller.browserObject.selectedBrowser.contentDocument;
-});
-
-Tabs.prototype.selectTab = function (index) {
-  // GO in to tab manager and grab the tab by index and call focus.
-}
-
-Tabs.prototype.findWindow = function (doc) {
-  for (var i = 0; i <= (this.controller.window.frames.length - 1); i++) {
-    if (this.controller.window.frames[i].document == doc) {
-      return this.controller.window.frames[i];
-    }
-  }
-
-  throw new Error("Cannot find window for document. Doc title == " + doc.title);
-}
-
-Tabs.prototype.getTabWindow = function (index) {
-  return this.findWindow(this.getTab(index));
-}
-
-Tabs.prototype.__defineGetter__("activeTabWindow", function () {
-  return this.findWindow(this.activeTab);
-});
-
-Tabs.prototype.__defineGetter__("length", function () {
-  return this.controller.browserObject.browsers.length;
-});
-
-Tabs.prototype.__defineGetter__("activeTabIndex", function () {
-  var browser = this.controller.browserObject;
-  return browser.tabContainer.selectedIndex;
-});
-
-Tabs.prototype.selectTabIndex = function (aIndex) {
-  var browser = this.controller.browserObject;
-  browser.selectTabAtIndex(aIndex);
-}
-
-function browserAdditions (controller) {
-  controller.tabs = new Tabs(controller);
-
-  controller.waitForPageLoad = function (aDocument, aTimeout, aInterval) {
-    var timeout = aTimeout || 30000;
-    var win = null;
-    var timed_out = false;
-
-    // If a user tries to do waitForPageLoad(2000), this will assign the
-    // interval the first arg which is most likely what they were expecting
-    if (typeof(aDocument) == "number"){
-      timeout = aDocument;
-    }
-
-    // If we have a real document use its default view
-    if (aDocument && (typeof(aDocument) === "object") &&
-        "defaultView" in aDocument)
-      win = aDocument.defaultView;
-
-    // If no document has been specified, fallback to the default view of the
-    // currently selected tab browser
-    win = win || this.browserObject.selectedBrowser.contentWindow;
-
-    // Wait until the content in the tab has been loaded
-    try {
-      this.waitFor(function () {
-        return windows.map.hasPageLoaded(utils.getWindowId(win));
-      }, "Timeout", timeout, aInterval);
-    }
-    catch (ex) {
-      if (!(ex instanceof errors.TimeoutError)) {
-        throw ex;
-      }
-      timed_out = true;
-    }
-    finally {
-      let state = 'URI=' + win.document.location.href +
-              ', readyState=' + win.document.readyState;
-      let message = "controller.waitForPageLoad(" + state + ")";
-
-      if (timed_out) {
-        throw new errors.AssertionError(message);
-      }
-
-      broker.pass({'function': message});
-    }
-  }
-}
-
-var controllerAdditions = {
-  'navigator:browser'  :browserAdditions
-};
-
-/**
- *  DEPRECATION WARNING
- *
- * The following methods have all been DEPRECATED as of Mozmill 2.0
- */
-MozMillController.prototype.assertProperty = function (el, attrib, val) {
-  logDeprecatedAssert("assertProperty");
-
-  return this.assertJSProperty(el, attrib, val);
-};
-
-MozMillController.prototype.assertPropertyNotExist = function (el, attrib) {
-  logDeprecatedAssert("assertPropertyNotExist");
-  return this.assertNotJSProperty(el, attrib);
-};
-
-/**
- *  DEPRECATION WARNING
- *
- * The following methods have all been DEPRECATED as of Mozmill 2.0
- * Use the MozMillElement object instead (https://developer.mozilla.org/en/Mozmill/Mozmill_Element_Object)
- */
-MozMillController.prototype.select = function (aElement, index, option, value) {
-  logDeprecated("controller.select", "Use the MozMillElement object.");
-
-  return aElement.select(index, option, value);
-};
-
-MozMillController.prototype.keypress = function (aElement, aKey, aModifiers, aExpectedEvent) {
-  logDeprecated("controller.keypress", "Use the MozMillElement object.");
-
-  if (!aElement) {
-    aElement = new mozelement.MozMillElement("Elem", this.window);
-  }
-
-  return aElement.keypress(aKey, aModifiers, aExpectedEvent);
-}
-
-MozMillController.prototype.type = function (aElement, aText, aExpectedEvent) {
-  logDeprecated("controller.type", "Use the MozMillElement object.");
-
-  if (!aElement) {
-    aElement = new mozelement.MozMillElement("Elem", this.window);
-  }
-
-  var that = this;
-  var retval = true;
-  Array.forEach(aText, function (letter) {
-    if (!that.keypress(aElement, letter, {}, aExpectedEvent)) {
-      retval = false; }
-  });
-
-  return retval;
-}
-
-MozMillController.prototype.mouseEvent = function (aElement, aOffsetX, aOffsetY, aEvent, aExpectedEvent) {
-  logDeprecated("controller.mouseEvent", "Use the MozMillElement object.");
-
-  return aElement.mouseEvent(aOffsetX, aOffsetY, aEvent, aExpectedEvent);
-}
-
-MozMillController.prototype.click = function (aElement, left, top, expectedEvent) {
-  logDeprecated("controller.click", "Use the MozMillElement object.");
-
-  return aElement.click(left, top, expectedEvent);
-}
-
-MozMillController.prototype.doubleClick = function (aElement, left, top, expectedEvent) {
-  logDeprecated("controller.doubleClick", "Use the MozMillElement object.");
-
-  return aElement.doubleClick(left, top, expectedEvent);
-}
-
-MozMillController.prototype.mouseDown = function (aElement, button, left, top, expectedEvent) {
-  logDeprecated("controller.mouseDown", "Use the MozMillElement object.");
-
-  return aElement.mouseDown(button, left, top, expectedEvent);
-};
-
-MozMillController.prototype.mouseOut = function (aElement, button, left, top, expectedEvent) {
-  logDeprecated("controller.mouseOut", "Use the MozMillElement object.");
-
-  return aElement.mouseOut(button, left, top, expectedEvent);
-};
-
-MozMillController.prototype.mouseOver = function (aElement, button, left, top, expectedEvent) {
-  logDeprecated("controller.mouseOver", "Use the MozMillElement object.");
-
-  return aElement.mouseOver(button, left, top, expectedEvent);
-};
-
-MozMillController.prototype.mouseUp = function (aElement, button, left, top, expectedEvent) {
-  logDeprecated("controller.mouseUp", "Use the MozMillElement object.");
-
-  return aElement.mouseUp(button, left, top, expectedEvent);
-};
-
-MozMillController.prototype.middleClick = function (aElement, left, top, expectedEvent) {
-  logDeprecated("controller.middleClick", "Use the MozMillElement object.");
-
-  return aElement.middleClick(aElement, left, top, expectedEvent);
-}
-
-MozMillController.prototype.rightClick = function (aElement, left, top, expectedEvent) {
-  logDeprecated("controller.rightClick", "Use the MozMillElement object.");
-
-  return aElement.rightClick(left, top, expectedEvent);
-}
-
-MozMillController.prototype.check = function (aElement, state) {
-  logDeprecated("controller.check", "Use the MozMillElement object.");
-
-  return aElement.check(state);
-}
-
-MozMillController.prototype.radio = function (aElement) {
-  logDeprecated("controller.radio", "Use the MozMillElement object.");
-
-  return aElement.select();
-}
-
-MozMillController.prototype.waitThenClick = function (aElement, timeout, interval) {
-  logDeprecated("controller.waitThenClick", "Use the MozMillElement object.");
-
-  return aElement.waitThenClick(timeout, interval);
-}
-
-MozMillController.prototype.waitForElement = function (aElement, timeout, interval) {
-  logDeprecated("controller.waitForElement", "Use the MozMillElement object.");
-
-  return aElement.waitForElement(timeout, interval);
-}
-
-MozMillController.prototype.waitForElementNotPresent = function (aElement, timeout, interval) {
-  logDeprecated("controller.waitForElementNotPresent", "Use the MozMillElement object.");
-
-  return aElement.waitForElementNotPresent(timeout, interval);
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js
+++ /dev/null
@@ -1,537 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["ID", "Link", "XPath", "Selector", "Name", "Anon", "AnonXPath",
-                        "Lookup", "_byID", "_byName", "_byAttrib", "_byAnonAttrib",
-                       ];
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
-var strings = {}; Cu.import('resource://mozmill/stdlib/strings.js', strings);
-var arrays = {}; Cu.import('resource://mozmill/stdlib/arrays.js', arrays);
-var json2 = {}; Cu.import('resource://mozmill/stdlib/json2.js', json2);
-var withs = {}; Cu.import('resource://mozmill/stdlib/withs.js', withs);
-var dom = {}; Cu.import('resource://mozmill/stdlib/dom.js', dom);
-var objects = {}; Cu.import('resource://mozmill/stdlib/objects.js', objects);
-
-var countQuotes = function (str) {
-  var count = 0;
-  var i = 0;
-
-  while (i < str.length) {
-    i = str.indexOf('"', i);
-    if (i != -1) {
-      count++;
-      i++;
-    } else {
-      break;
-    }
-  }
-
-  return count;
-};
-
-/**
- * smartSplit()
- *
- * Takes a lookup string as input and returns
- * a list of each node in the string
- */
-var smartSplit = function (str) {
-  // Ensure we have an even number of quotes
-  if (countQuotes(str) % 2 != 0) {
-    throw new Error ("Invalid Lookup Expression");
-  }
-
-  /**
-   * This regex matches a single "node" in a lookup string.
-   * In otherwords, it matches the part between the two '/'s
-   *
-   * Regex Explanation:
-   * \/ - start matching at the first forward slash
-   * ([^\/"]*"[^"]*")* - match as many pairs of quotes as possible until we hit a slash (ignore slashes inside quotes)
-   * [^\/]* - match the remainder of text outside of last quote but before next slash
-   */
-  var re = /\/([^\/"]*"[^"]*")*[^\/]*/g
-  var ret = []
-  var match = re.exec(str);
-
-  while (match != null) {
-    ret.push(match[0].replace(/^\//, ""));
-    match = re.exec(str);
-  }
-
-  return ret;
-};
-
-/**
- * defaultDocuments()
- *
- * Returns a list of default documents in which to search for elements
- * if no document is provided
- */
-function defaultDocuments() {
-  var win = Services.wm.getMostRecentWindow("navigator:browser");
-
-  return [
-    win.document,
-    utils.getBrowserObject(win).selectedBrowser.contentWindow.document
-  ];
-};
-
-/**
- * nodeSearch()
- *
- * Takes an optional document, callback and locator string
- * Returns a handle to the located element or null
- */
-function nodeSearch(doc, func, string) {
-  if (doc != undefined) {
-    var documents = [doc];
-  } else {
-    var documents = defaultDocuments();
-  }
-
-  var e = null;
-  var element = null;
-
-  //inline function to recursively find the element in the DOM, cross frame.
-  var search = function (win, func, string) {
-    if (win == null) {
-      return;
-    }
-
-    //do the lookup in the current window
-    element = func.call(win, string);
-
-    if (!element || (element.length == 0)) {
-      var frames = win.frames;
-      for (var i = 0; i < frames.length; i++) {
-        search(frames[i], func, string);
-      }
-    } else {
-      e = element;
-    }
-  };
-
-  for (var i = 0; i < documents.length; ++i) {
-    var win = documents[i].defaultView;
-    search(win, func, string);
-    if (e) {
-      break;
-    }
-  }
-
-  return e;
-};
-
-/**
- * Selector()
- *
- * Finds an element by selector string
- */
-function Selector(_document, selector, index) {
-  if (selector == undefined) {
-    throw new Error('Selector constructor did not recieve enough arguments.');
-  }
-
-  this.selector = selector;
-
-  this.getNodeForDocument = function (s) {
-    return this.document.querySelectorAll(s);
-  };
-
-  var nodes = nodeSearch(_document, this.getNodeForDocument, this.selector);
-
-  return nodes ? nodes[index || 0] : null;
-};
-
-/**
- * ID()
- *
- * Finds an element by ID
- */
-function ID(_document, nodeID) {
-  if (nodeID == undefined) {
-    throw new Error('ID constructor did not recieve enough arguments.');
-  }
-
-  this.getNodeForDocument = function (nodeID) {
-    return this.document.getElementById(nodeID);
-  };
-
-  return nodeSearch(_document, this.getNodeForDocument, nodeID);
-};
-
-/**
- * Link()
- *
- * Finds a link by innerHTML
- */
-function Link(_document, linkName) {
-  if (linkName == undefined) {
-    throw new Error('Link constructor did not recieve enough arguments.');
-  }
-
-  this.getNodeForDocument = function (linkName) {
-    var getText = function (el) {
-      var text = "";
-
-      if (el.nodeType == 3) { //textNode
-        if (el.data != undefined) {
-          text = el.data;
-        } else {
-          text = el.innerHTML;
-        }
-
-        text = text.replace(/n|r|t/g, " ");
-      }
-      else if (el.nodeType == 1) { //elementNode
-        for (var i = 0; i < el.childNodes.length; i++) {
-          var child = el.childNodes.item(i);
-          text += getText(child);
-        }
-
-        if (el.tagName == "P" || el.tagName == "BR" ||
-            el.tagName == "HR" || el.tagName == "DIV") {
-          text += "\n";
-        }
-      }
-
-      return text;
-    };
-
-    //sometimes the windows won't have this function
-    try {
-      var links = this.document.getElementsByTagName('a');
-    } catch (e) {
-      // ADD LOG LINE mresults.write('Error: '+ e, 'lightred');
-    }
-
-    for (var i = 0; i < links.length; i++) {
-      var el = links[i];
-      //if (getText(el).indexOf(this.linkName) != -1) {
-      if (el.innerHTML.indexOf(linkName) != -1) {
-        return el;
-      }
-    }
-
-    return null;
-  };
-
-  return nodeSearch(_document, this.getNodeForDocument, linkName);
-};
-
-/**
- * XPath()
- *
- * Finds an element by XPath
- */
-function XPath(_document, expr) {
-  if (expr == undefined) {
-    throw new Error('XPath constructor did not recieve enough arguments.');
-  }
-
-  this.getNodeForDocument = function (s) {
-    var aNode = this.document;
-    var aExpr = s;
-    var xpe = null;
-
-    if (this.document.defaultView == null) {
-      xpe = new getMethodInWindows('XPathEvaluator')();
-    } else {
-      xpe = new this.document.defaultView.XPathEvaluator();
-    }
-
-    var nsResolver = xpe.createNSResolver(aNode.ownerDocument == null ? aNode.documentElement
-                                                                      : aNode.ownerDocument.documentElement);
-    var result = xpe.evaluate(aExpr, aNode, nsResolver, 0, null);
-    var found = [];
-    var res;
-
-    while (res = result.iterateNext()) {
-      found.push(res);
-    }
-
-    return found[0];
-  };
-
-  return nodeSearch(_document, this.getNodeForDocument, expr);
-};
-
-/**
- * Name()
- *
- * Finds an element by Name
- */
-function Name(_document, nName) {
-  if (nName == undefined) {
-    throw new Error('Name constructor did not recieve enough arguments.');
-  }
-
-  this.getNodeForDocument = function (s) {
-    try{
-      var els = this.document.getElementsByName(s);
-      if (els.length > 0) {
-        return els[0];
-      }
-    } catch (e) {
-    }
-
-    return null;
-  };
-
-  return nodeSearch(_document, this.getNodeForDocument, nName);
-};
-
-
-var _returnResult = function (results) {
-  if (results.length == 0) {
-    return null
-  }
-  else if (results.length == 1) {
-    return results[0];
-  } else {
-    return results;
-  }
-}
-
-var _forChildren = function (element, name, value) {
-  var results = [];
-  var nodes = Array.from(element.childNodes).filter(e => e);
-
-  for (var i in nodes) {
-    var n = nodes[i];
-    if (n[name] == value) {
-      results.push(n);
-    }
-  }
-
-  return results;
-}
-
-var _forAnonChildren = function (_document, element, name, value) {
-  var results = [];
-  var nodes = Array.from(_document.getAnoymousNodes(element)).filter(e => e);
-
-  for (var i in nodes ) {
-    var n = nodes[i];
-    if (n[name] == value) {
-      results.push(n);
-    }
-  }
-
-  return results;
-}
-
-var _byID = function (_document, parent, value) {
-  return _returnResult(_forChildren(parent, 'id', value));
-}
-
-var _byName = function (_document, parent, value) {
-  return _returnResult(_forChildren(parent, 'tagName', value));
-}
-
-var _byAttrib = function (parent, attributes) {
-  var results = [];
-  var nodes = parent.childNodes;
-
-  for (var i in nodes) {
-    var n = nodes[i];
-    let requirementPass = 0;
-    let requirementLength = 0;
-
-    for (var a in attributes) {
-      requirementLength++;
-      try {
-        if (n.getAttribute(a) == attributes[a]) {
-          requirementPass++;
-        }
-      } catch (e) {
-        // Workaround any bugs in custom attribute crap in XUL elements
-      }
-    }
-
-    if (requirementPass == requirementLength) {
-      results.push(n);
-    }
-  }
-
-  return _returnResult(results)
-}
-
-var _byAnonAttrib = function (_document, parent, attributes) {
-  var results = [];
-
-  if (objects.getLength(attributes) == 1) {
-    for (var i in attributes) {
-      var k = i;
-      var v = attributes[i];
-    }
-
-    var result = _document.getAnonymousElementByAttribute(parent, k, v);
-    if (result) {
-      return result;
-    }
-  }
-
-  var nodes = Array.from(_document.getAnonymousNodes(parent)).filter(n => n.getAttribute);
-
-  function resultsForNodes (nodes) {
-    for (var i in nodes) {
-      var n = nodes[i];
-      requirementPass = 0;
-      requirementLength = 0;
-
-      for (var a in attributes) {
-        requirementLength++;
-        if (n.getAttribute(a) == attributes[a]) {
-          requirementPass++;
-        }
-      }
-
-      if (requirementPass == requirementLength) {
-        results.push(n);
-      }
-    }
-  }
-
-  resultsForNodes(nodes);
-  if (results.length == 0) {
-    resultsForNodes(Array.from(parent.childNodes).filter(n => n != undefined && n.getAttribute));
-  }
-
-  return _returnResult(results)
-}
-
-var _byIndex = function (_document, parent, i) {
-  if (parent instanceof Array) {
-    return parent[i];
-  }
-
-  return parent.childNodes[i];
-}
-
-var _anonByName = function (_document, parent, value) {
-  return _returnResult(_forAnonChildren(_document, parent, 'tagName', value));
-}
-
-var _anonByAttrib = function (_document, parent, value) {
-  return _byAnonAttrib(_document, parent, value);
-}
-
-var _anonByIndex = function (_document, parent, i) {
-  return _document.getAnonymousNodes(parent)[i];
-}
-
-/**
- * Lookup()
- *
- * Finds an element by Lookup expression
- */
-function Lookup(_document, expression) {
-  if (expression == undefined) {
-    throw new Error('Lookup constructor did not recieve enough arguments.');
-  }
-
-  var expSplit = smartSplit(expression).filter(e => e != '');
-  expSplit.unshift(_document);
-
-  var nCases = {'id':_byID, 'name':_byName, 'attrib':_byAttrib, 'index':_byIndex};
-  var aCases = {'name':_anonByName, 'attrib':_anonByAttrib, 'index':_anonByIndex};
-
-  /**
-   * Reduces the lookup expression
-   * @param {Object} parentNode
-   *        Parent node (previousValue of the formerly executed reduce callback)
-   * @param {String} exp
-   *        Lookup expression for the parents child node
-   *
-   * @returns {Object} Node found by the given expression
-   */
-  var reduceLookup = function (parentNode, exp) {
-    // Abort in case the parent node was not found
-    if (!parentNode) {
-      return false;
-    }
-
-    // Handle case where only index is provided
-    var cases = nCases;
-
-    // Handle ending index before any of the expression gets mangled
-    if (withs.endsWith(exp, ']')) {
-      var expIndex = json2.JSON.parse(strings.vslice(exp, '[', ']'));
-    }
-
-    // Handle anon
-    if (withs.startsWith(exp, 'anon')) {
-      exp = strings.vslice(exp, '(', ')');
-      cases = aCases;
-    }
-
-    if (withs.startsWith(exp, '[')) {
-      try {
-        var obj = json2.JSON.parse(strings.vslice(exp, '[', ']'));
-      } catch (e) {
-        throw new SyntaxError(e + '. String to be parsed was || ' +
-                              strings.vslice(exp, '[', ']') + ' ||');
-      }
-
-      var r = cases['index'](_document, parentNode, obj);
-      if (r == null) {
-        throw new SyntaxError('Expression "' + exp +
-                              '" returned null. Anonymous == ' + (cases == aCases));
-      }
-
-      return r;
-    }
-
-    for (var c in cases) {
-      if (withs.startsWith(exp, c)) {
-        try {
-          var obj = json2.JSON.parse(strings.vslice(exp, '(', ')'))
-        } catch (e) {
-           throw new SyntaxError(e + '. String to be parsed was || ' +
-                                 strings.vslice(exp, '(', ')') + '  ||');
-        }
-        var result = cases[c](_document, parentNode, obj);
-      }
-    }
-
-    if (!result) {
-      if (withs.startsWith(exp, '{')) {
-        try {
-          var obj = json2.JSON.parse(exp);
-        } catch (e) {
-          throw new SyntaxError(e + '. String to be parsed was || ' + exp + ' ||');
-        }
-
-        if (cases == aCases) {
-          var result = _anonByAttrib(_document, parentNode, obj);
-        } else {
-          var result = _byAttrib(parentNode, obj);
-        }
-      }
-    }
-
-    // Final return
-    if (expIndex) {
-      // TODO: Check length and raise error
-      return result[expIndex];
-    } else {
-      // TODO: Check length and raise error
-      return result;
-    }
-
-    // Maybe we should cause an exception here
-    return false;
-  };
-
-  return expSplit.reduce(reduceLookup);
-};
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js
+++ /dev/null
@@ -1,1157 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["Elem", "Selector", "ID", "Link", "XPath", "Name", "Lookup",
-                        "MozMillElement", "MozMillCheckBox", "MozMillRadio", "MozMillDropList",
-                        "MozMillTextBox", "subclasses"
-                       ];
-
-const NAMESPACE_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-var EventUtils = {};  Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils);
-
-var assertions = {};  Cu.import('resource://mozmill/modules/assertions.js', assertions);
-var broker = {};      Cu.import('resource://mozmill/driver/msgbroker.js', broker);
-var elementslib = {}; Cu.import('resource://mozmill/driver/elementslib.js', elementslib);
-var utils = {};       Cu.import('resource://mozmill/stdlib/utils.js', utils);
-
-var assert = new assertions.Assert();
-
-// A list of all the subclasses available.  Shared modules can push their own subclasses onto this list
-var subclasses = [MozMillCheckBox, MozMillRadio, MozMillDropList, MozMillTextBox];
-
-/**
- * createInstance()
- *
- * Returns an new instance of a MozMillElement
- * The type of the element is automatically determined
- */
-function createInstance(locatorType, locator, elem, document) {
-  var args = { "document": document, "element": elem };
-
-  // If we already have an element lets determine the best MozMillElement type
-  if (elem) {
-    for (var i = 0; i < subclasses.length; ++i) {
-      if (subclasses[i].isType(elem)) {
-        return new subclasses[i](locatorType, locator, args);
-      }
-    }
-  }
-
-  // By default we create a base MozMillElement
-  if (MozMillElement.isType(elem)) {
-    return new MozMillElement(locatorType, locator, args);
-  }
-
-  throw new Error("Unsupported element type " + locatorType + ": " + locator);
-}
-
-var Elem = function (node) {
-  return createInstance("Elem", node, node);
-};
-
-var Selector = function (document, selector, index) {
-  return createInstance("Selector", selector, elementslib.Selector(document, selector, index), document);
-};
-
-var ID = function (document, nodeID) {
-  return createInstance("ID", nodeID, elementslib.ID(document, nodeID), document);
-};
-
-var Link = function (document, linkName) {
-  return createInstance("Link", linkName, elementslib.Link(document, linkName), document);
-};
-
-var XPath = function (document, expr) {
-  return createInstance("XPath", expr, elementslib.XPath(document, expr), document);
-};
-
-var Name = function (document, nName) {
-  return createInstance("Name", nName, elementslib.Name(document, nName), document);
-};
-
-var Lookup = function (document, expression) {
-  var elem = createInstance("Lookup", expression, elementslib.Lookup(document, expression), document);
-
-  // Bug 864268 - Expose the expression property to maintain backwards compatibility
-  elem.expression = elem._locator;
-
-  return elem;
-};
-
-/**
- * MozMillElement
- * The base class for all mozmill elements
- */
-function MozMillElement(locatorType, locator, args) {
-  args = args || {};
-  this._locatorType = locatorType;
-  this._locator = locator;
-  this._element = args["element"];
-  this._owner = args["owner"];
-
-  this._document = this._element ? this._element.ownerDocument : args["document"];
-  this._defaultView = this._document ? this._document.defaultView : null;
-
-  // Used to maintain backwards compatibility with controller.js
-  this.isElement = true;
-}
-
-// Static method that returns true if node is of this element type
-MozMillElement.isType = function (node) {
-  return true;
-};
-
-// This getter is the magic behind lazy loading (note distinction between _element and element)
-MozMillElement.prototype.__defineGetter__("element", function () {
-  // If the document is invalid (e.g. reload of the page), invalidate the cached
-  // element and update the document cache
-  if (this._defaultView && this._defaultView.document !== this._document) {
-    this._document = this._defaultView.document;
-    this._element = undefined;
-  }
-
-  if (this._element == undefined) {
-    if (elementslib[this._locatorType]) {
-      this._element = elementslib[this._locatorType](this._document, this._locator);
-    } else if (this._locatorType == "Elem") {
-      this._element = this._locator;
-    } else {
-      throw new Error("Unknown locator type: " + this._locatorType);
-    }
-  }
-
-  return this._element;
-});
-
-/**
- * Drag an element to the specified offset on another element, firing mouse and
- * drag events. Adapted from EventUtils.js synthesizeDrop()
- *
- * By default it will drag the source element over the destination's element
- * center with a "move" dropEffect.
- *
- * @param {MozElement} aElement
- *        Destination element over which the drop occurs
- * @param {Number} [aOffsetX=aElement.width/2]
- *        Relative x offset for dropping on aElement
- * @param {Number} [aOffsetY=aElement.height/2]
- *        Relative y offset for dropping on aElement
- * @param {DOMWindow} [aSourceWindow=this.element.ownerDocument.defaultView]
- *        Custom source Window to be used.
- * @param {DOMWindow} [aDestWindow=aElement.getNode().ownerDocument.defaultView]
- *        Custom destination Window to be used.
- * @param {String} [aDropEffect="move"]
- *        Possible values: copy, move, link, none
- * @param {Object[]} [aDragData]
- *        An array holding custom drag data to be used during the drag event
- *        Format: [{ type: "text/plain", "Text to drag"}, ...]
- *
- * @returns {String} the captured dropEffect
- */
-MozMillElement.prototype.dragToElement = function(aElement, aOffsetX, aOffsetY,
-                                                  aSourceWindow, aDestWindow,
-                                                  aDropEffect, aDragData) {
-  if (!this.element) {
-    throw new Error("Could not find element " + this.getInfo());
-  }
-  if (!aElement) {
-    throw new Error("Missing destination element");
-  }
-
-  var srcNode = this.element;
-  var destNode = aElement.getNode();
-  var srcWindow = aSourceWindow || srcNode.ownerGlobal || srcNode;
-  var destWindow = aDestWindow || destNode.ownerGlobal || destNode;
-
-  var srcRect = srcNode.getBoundingClientRect();
-  var srcCoords = {
-    x: srcRect.width / 2,
-    y: srcRect.height / 2
-  };
-  var destRect = destNode.getBoundingClientRect();
-  var destCoords = {
-    x: (!aOffsetX || isNaN(aOffsetX)) ? (destRect.width / 2) : aOffsetX,
-    y: (!aOffsetY || isNaN(aOffsetY)) ? (destRect.height / 2) : aOffsetY
-  };
-
-  var windowUtils = destWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindowUtils);
-  var ds = Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService);
-
-  var dataTransfer;
-  var trapDrag = function (event) {
-    srcWindow.removeEventListener("dragstart", trapDrag, true);
-    dataTransfer = event.dataTransfer;
-
-    if (!aDragData) {
-      return;
-    }
-
-    for (var i = 0; i < aDragData.length; i++) {
-      var item = aDragData[i];
-      for (var j = 0; j < item.length; j++) {
-        dataTransfer.mozSetDataAt(item[j].type, item[j].data, i);
-      }
-    }
-
-    dataTransfer.dropEffect = aDropEffect || "move";
-    event.preventDefault();
-    event.stopPropagation();
-  }
-
-  ds.startDragSession();
-
-  try {
-    srcWindow.addEventListener("dragstart", trapDrag, true);
-    EventUtils.synthesizeMouse(srcNode, srcCoords.x, srcCoords.y,
-                               { type: "mousedown" }, srcWindow);
-    EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y,
-                               { type: "mousemove" }, destWindow);
-
-    var event = destWindow.document.createEvent("DragEvent");
-    event.initDragEvent("dragenter", true, true, destWindow, 0, 0, 0, 0, 0,
-                        false, false, false, false, 0, null, dataTransfer);
-    event.initDragEvent("dragover", true, true, destWindow, 0, 0, 0, 0, 0,
-                        false, false, false, false, 0, null, dataTransfer);
-    event.initDragEvent("drop", true, true, destWindow, 0, 0, 0, 0, 0,
-                        false, false, false, false, 0, null, dataTransfer);
-    windowUtils.dispatchDOMEventViaPresShell(destNode, event, true);
-
-    EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y,
-                               { type: "mouseup" }, destWindow);
-
-    return dataTransfer.dropEffect;
-  } finally {
-    ds.endDragSession(true);
-  }
-
-};
-
-// Returns the actual wrapped DOM node
-MozMillElement.prototype.getNode = function () {
-  return this.element;
-};
-
-MozMillElement.prototype.getInfo = function () {
-  return this._locatorType + ": " + this._locator;
-};
-
-/**
- * Sometimes an element which once existed will no longer exist in the DOM
- * This function re-searches for the element
- */
-MozMillElement.prototype.exists = function () {
-  this._element = undefined;
-  if (this.element) {
-    return true;
-  }
-
-  return false;
-};
-
-/**
- * Synthesize a keypress event on the given element
- *
- * @param {string} aKey
- *        Key to use for synthesizing the keypress event. It can be a simple
- *        character like "k" or a string like "VK_ESCAPE" for command keys
- * @param {object} aModifiers
- *        Information about the modifier keys to send
- *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
- *                               [optional - default: false]
- *                  altKey     - Hold down the alt key
- *                              [optional - default: false]
- *                  ctrlKey    - Hold down the ctrl key
- *                               [optional - default: false]
- *                  metaKey    - Hold down the meta key (command key on Mac)
- *                               [optional - default: false]
- *                  shiftKey   - Hold down the shift key
- *                               [optional - default: false]
- * @param {object} aExpectedEvent
- *        Information about the expected event to occur
- *        Elements: target     - Element which should receive the event
- *                               [optional - default: current element]
- *                  type       - Type of the expected key event
- */
-MozMillElement.prototype.keypress = function (aKey, aModifiers, aExpectedEvent) {
-  if (!this.element) {
-    throw new Error("Could not find element " + this.getInfo());
-  }
-
-  var win = this.element.ownerGlobal || this.element;
-  this.element.focus();
-
-  if (aExpectedEvent) {
-    if (!aExpectedEvent.type) {
-      throw new Error(arguments.callee.name + ": Expected event type not specified");
-    }
-
-    var target = aExpectedEvent.target ? aExpectedEvent.target.getNode()
-                                       : this.element;
-    EventUtils.synthesizeKeyExpectEvent(aKey, aModifiers || {}, target, aExpectedEvent.type,
-                                        "MozMillElement.keypress()", win);
-  } else {
-    EventUtils.synthesizeKey(aKey, aModifiers || {}, win);
-  }
-
-  broker.pass({'function':'MozMillElement.keypress()'});
-
-  return true;
-};
-
-
-/**
- * Synthesize a general mouse event on the given element
- *
- * @param {number} aOffsetX
- *        Relative x offset in the elements bounds to click on
- * @param {number} aOffsetY
- *        Relative y offset in the elements bounds to click on
- * @param {object} aEvent
- *        Information about the event to send
- *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
- *                               [optional - default: false]
- *                  altKey     - Hold down the alt key
- *                               [optional - default: false]
- *                  button     - Mouse button to use
- *                               [optional - default: 0]
- *                  clickCount - Number of counts to click
- *                               [optional - default: 1]
- *                  ctrlKey    - Hold down the ctrl key
- *                               [optional - default: false]
- *                  metaKey    - Hold down the meta key (command key on Mac)
- *                               [optional - default: false]
- *                  shiftKey   - Hold down the shift key
- *                               [optional - default: false]
- *                  type       - Type of the mouse event ('click', 'mousedown',
- *                               'mouseup', 'mouseover', 'mouseout')
- *                               [optional - default: 'mousedown' + 'mouseup']
- * @param {object} aExpectedEvent
- *        Information about the expected event to occur
- *        Elements: target     - Element which should receive the event
- *                               [optional - default: current element]
- *                  type       - Type of the expected mouse event
- */
-MozMillElement.prototype.mouseEvent = function (aOffsetX, aOffsetY, aEvent, aExpectedEvent) {
-  if (!this.element) {
-    throw new Error(arguments.callee.name + ": could not find element " + this.getInfo());
-  }
-
-  if ("document" in this.element) {
-    throw new Error("A window cannot be a target for mouse events.");
-  }
-
-  var rect = this.element.getBoundingClientRect();
-
-  if (!aOffsetX || isNaN(aOffsetX)) {
-    aOffsetX = rect.width / 2;
-  }
-
-  if (!aOffsetY || isNaN(aOffsetY)) {
-    aOffsetY = rect.height / 2;
-  }
-
-  // Scroll element into view otherwise the click will fail
-  if ("scrollIntoView" in this.element)
-    this.element.scrollIntoView();
-
-  if (aExpectedEvent) {
-    // The expected event type has to be set
-    if (!aExpectedEvent.type) {
-      throw new Error(arguments.callee.name + ": Expected event type not specified");
-    }
-
-    // If no target has been specified use the specified element
-    var target = aExpectedEvent.target ? aExpectedEvent.target.getNode()
-                                       : this.element;
-    if (!target) {
-      throw new Error(arguments.callee.name + ": could not find element " +
-                      aExpectedEvent.target.getInfo());
-    }
-
-    EventUtils.synthesizeMouseExpectEvent(this.element, aOffsetX, aOffsetY, aEvent,
-                                          target, aExpectedEvent.type,
-                                          "MozMillElement.mouseEvent()",
-                                          this.element.ownerGlobal);
-  } else {
-    EventUtils.synthesizeMouse(this.element, aOffsetX, aOffsetY, aEvent,
-                               this.element.ownerGlobal);
-  }
-
-  // Bug 555347
-  // We don't know why this sleep is necessary but more investigation is needed
-  // before it can be removed
-  utils.sleep(0);
-
-  return true;
-};
-
-/**
- * Synthesize a mouse click event on the given element
- */
-MozMillElement.prototype.click = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  // Handle menu items differently
-  if (this.element && this.element.tagName == "menuitem") {
-    this.element.click();
-  } else {
-    this.mouseEvent(aOffsetX, aOffsetY, {}, aExpectedEvent);
-  }
-
-  broker.pass({'function':'MozMillElement.click()'});
-
-  return true;
-};
-
-/**
- * Synthesize a double click on the given element
- */
-MozMillElement.prototype.doubleClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {clickCount: 2}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.doubleClick()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse down event on the given element
- */
-MozMillElement.prototype.mouseDown = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mousedown"}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.mouseDown()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse out event on the given element
- */
-MozMillElement.prototype.mouseOut = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseout"}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.mouseOut()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse over event on the given element
- */
-MozMillElement.prototype.mouseOver = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseover"}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.mouseOver()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse up event on the given element
- */
-MozMillElement.prototype.mouseUp = function (aButton, aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {button: aButton, type: "mouseup"}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.mouseUp()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse middle click event on the given element
- */
-MozMillElement.prototype.middleClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {button: 1}, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.middleClick()'});
-
-  return true;
-};
-
-/**
- * Synthesize a mouse right click event on the given element
- */
-MozMillElement.prototype.rightClick = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {type : "contextmenu", button: 2 }, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.rightClick()'});
-
-  return true;
-};
-
-/**
- * Synthesize a general touch event on the given element
- *
- * @param {Number} [aOffsetX=aElement.width / 2]
- *        Relative x offset in the elements bounds to click on
- * @param {Number} [aOffsetY=aElement.height / 2]
- *        Relative y offset in the elements bounds to click on
- * @param {Object} [aEvent]
- *        Information about the event to send
- * @param {Boolean} [aEvent.altKey=false]
- *        A Boolean value indicating whether or not the alt key was down when
- *        the touch event was fired
- * @param {Number} [aEvent.angle=0]
- *        The angle (in degrees) that the ellipse described by rx and
- *        ry must be rotated, clockwise, to most accurately cover the area
- *        of contact between the user and the surface.
- * @param {Touch[]} [aEvent.changedTouches]
- *        A TouchList of all the Touch objects representing individual points of
- *        contact whose states changed between the previous touch event and
- *        this one
- * @param {Boolean} [aEvent.ctrlKey]
- *        A Boolean value indicating whether or not the control key was down
- *        when the touch event was fired
- * @param {Number} [aEvent.force=1]
- *        The amount of pressure being applied to the surface by the user, as a
- *        float between 0.0 (no pressure) and 1.0 (maximum pressure)
- * @param {Number} [aEvent.id=0]
- *        A unique identifier for this Touch object. A given touch (say, by a
- *        finger) will have the same identifier for the duration of its movement
- *        around the surface. This lets you ensure that you're tracking the same
- *        touch all the time
- * @param {Boolean} [aEvent.metaKey]
- *        A Boolean value indicating whether or not the meta key was down when
- *        the touch event was fired.
- * @param {Number} [aEvent.rx=1]
- *        The X radius of the ellipse that most closely circumscribes the area
- *        of contact with the screen.
- * @param {Number} [aEvent.ry=1]
- *        The Y radius of the ellipse that most closely circumscribes the area
- *        of contact with the screen.
- * @param {Boolean} [aEvent.shiftKey]
- *        A Boolean value indicating whether or not the shift key was down when
- *        the touch event was fired
- * @param {Touch[]} [aEvent.targetTouches]
- *        A TouchList of all the Touch objects that are both currently in
- *        contact with the touch surface and were also started on the same
- *        element that is the target of the event
- * @param {Touch[]} [aEvent.touches]
- *        A TouchList of all the Touch objects representing all current points
- *        of contact with the surface, regardless of target or changed status
- * @param {Number} [aEvent.type=*|touchstart|touchend|touchmove|touchenter|touchleave|touchcancel]
- *        The type of touch event that occurred
- * @param {Element} [aEvent.target]
- *        The target of the touches associated with this event. This target
- *        corresponds to the target of all the touches in the targetTouches
- *        attribute, but note that other touches in this event may have a
- *        different target. To be careful, you should use the target associated
- *        with individual touches
- */
-MozMillElement.prototype.touchEvent = function (aOffsetX, aOffsetY, aEvent) {
-  if (!this.element) {
-    throw new Error(arguments.callee.name + ": could not find element " + this.getInfo());
-  }
-
-  if ("document" in this.element) {
-    throw new Error("A window cannot be a target for touch events.");
-  }
-
-  var rect = this.element.getBoundingClientRect();
-
-  if (!aOffsetX || isNaN(aOffsetX)) {
-    aOffsetX = rect.width / 2;
-  }
-
-  if (!aOffsetY || isNaN(aOffsetY)) {
-    aOffsetY = rect.height / 2;
-  }
-
-  // Scroll element into view otherwise the click will fail
-  if ("scrollIntoView" in this.element) {
-    this.element.scrollIntoView();
-  }
-
-  EventUtils.synthesizeTouch(this.element, aOffsetX, aOffsetY, aEvent,
-                             this.element.ownerGlobal);
-
-  return true;
-};
-
-/**
- * Synthesize a touch tap event on the given element
- *
- * @param {Number} [aOffsetX=aElement.width / 2]
- *        Left offset in px where the event is triggered
- * @param {Number} [aOffsetY=aElement.height / 2]
- *        Top offset in px where the event is triggered
- * @param {Object} [aExpectedEvent]
- *        Information about the expected event to occur
- * @param {MozMillElement} [aExpectedEvent.target=this.element]
- *        Element which should receive the event
- * @param {MozMillElement} [aExpectedEvent.type]
- *        Type of the expected mouse event
- */
-MozMillElement.prototype.tap = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {
-    clickCount: 1,
-    inputSource: Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH
-  }, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.tap()'});
-
-  return true;
-};
-
-/**
- * Synthesize a double tap on the given element
- *
- * @param {Number} [aOffsetX=aElement.width / 2]
- *        Left offset in px where the event is triggered
- * @param {Number} [aOffsetY=aElement.height / 2]
- *        Top offset in px where the event is triggered
- * @param {Object} [aExpectedEvent]
- *        Information about the expected event to occur
- * @param {MozMillElement} [aExpectedEvent.target=this.element]
- *        Element which should receive the event
- * @param {MozMillElement} [aExpectedEvent.type]
- *        Type of the expected mouse event
- */
-MozMillElement.prototype.doubleTap = function (aOffsetX, aOffsetY, aExpectedEvent) {
-  this.mouseEvent(aOffsetX, aOffsetY, {
-    clickCount: 2,
-    inputSource: Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH
-  }, aExpectedEvent);
-
-  broker.pass({'function':'MozMillElement.doubleTap()'});
-
-  return true;
-};
-
-/**
- * Synthesize a long press
- *
- * @param {Number} aOffsetX
- *        Left offset in px where the event is triggered
- * @param {Number} aOffsetY
- *        Top offset in px where the event is triggered
- * @param {Number} [aTime=1000]
- *        Duration of the "press" event in ms
- */
-MozMillElement.prototype.longPress = function (aOffsetX, aOffsetY, aTime) {
-  var time = aTime || 1000;
-
-  this.touchStart(aOffsetX, aOffsetY);
-  utils.sleep(time);
-  this.touchEnd(aOffsetX, aOffsetY);
-
-  broker.pass({'function':'MozMillElement.longPress()'});
-
-  return true;
-};
-
-/**
- * Synthesize a touch & drag event on the given element
- *
- * @param {Number} aOffsetX1
- *        Left offset of the start position
- * @param {Number} aOffsetY1
- *        Top offset of the start position
- * @param {Number} aOffsetX2
- *        Left offset of the end position
- * @param {Number} aOffsetY2
- *        Top offset of the end position
- */
-MozMillElement.prototype.touchDrag = function (aOffsetX1, aOffsetY1, aOffsetX2, aOffsetY2) {
-  this.touchStart(aOffsetX1, aOffsetY1);
-  this.touchMove(aOffsetX2, aOffsetY2);
-  this.touchEnd(aOffsetX2, aOffsetY2);
-
-  broker.pass({'function':'MozMillElement.move()'});
-
-  return true;
-};
-
-/**
- * Synthesize a press / touchstart event on the given element
- *
- * @param {Number} aOffsetX
- *        Left offset where the event is triggered
- * @param {Number} aOffsetY
- *        Top offset where the event is triggered
- */
-MozMillElement.prototype.touchStart = function (aOffsetX, aOffsetY) {
-  this.touchEvent(aOffsetX, aOffsetY, { type: "touchstart" });
-
-  broker.pass({'function':'MozMillElement.touchStart()'});
-
-  return true;
-};
-
-/**
- * Synthesize a release / touchend event on the given element
- *
- * @param {Number} aOffsetX
- *        Left offset where the event is triggered
- * @param {Number} aOffsetY
- *        Top offset where the event is triggered
- */
-MozMillElement.prototype.touchEnd = function (aOffsetX, aOffsetY) {
-  this.touchEvent(aOffsetX, aOffsetY, { type: "touchend" });
-
-  broker.pass({'function':'MozMillElement.touchEnd()'});
-
-  return true;
-};
-
-/**
- * Synthesize a touchMove event on the given element
- *
- * @param {Number} aOffsetX
- *        Left offset where the event is triggered
- * @param {Number} aOffsetY
- *        Top offset where the event is triggered
- */
-MozMillElement.prototype.touchMove = function (aOffsetX, aOffsetY) {
-  this.touchEvent(aOffsetX, aOffsetY, { type: "touchmove" });
-
-  broker.pass({'function':'MozMillElement.touchMove()'});
-
-  return true;
-};
-
-MozMillElement.prototype.waitForElement = function (timeout, interval) {
-  var elem = this;
-
-  assert.waitFor(function () {
-    return elem.exists();
-  }, "Element.waitForElement(): Element '" + this.getInfo() +
-     "' has been found", timeout, interval);
-
-  broker.pass({'function':'MozMillElement.waitForElement()'});
-};
-
-MozMillElement.prototype.waitForElementNotPresent = function (timeout, interval) {
-  var elem = this;
-
-  assert.waitFor(function () {
-    return !elem.exists();
-  }, "Element.waitForElementNotPresent(): Element '" + this.getInfo() +
-     "' has not been found", timeout, interval);
-
-  broker.pass({'function':'MozMillElement.waitForElementNotPresent()'});
-};
-
-MozMillElement.prototype.waitThenClick = function (timeout, interval,
-                                                   aOffsetX, aOffsetY, aExpectedEvent) {
-  this.waitForElement(timeout, interval);
-  this.click(aOffsetX, aOffsetY, aExpectedEvent);
-};
-
-/**
- * Waits for the element to be available in the DOM, then trigger a tap event
- *
- * @param {Number} [aTimeout=5000]
- *        Time to wait for the element to be available
- * @param {Number} [aInterval=100]
- *        Interval to check for availability
- * @param {Number} [aOffsetX=aElement.width / 2]
- *        Left offset where the event is triggered
- * @param {Number} [aOffsetY=aElement.height / 2]
- *        Top offset where the event is triggered
- * @param {Object} [aExpectedEvent]
- *        Information about the expected event to occur
- * @param {MozMillElement} [aExpectedEvent.target=this.element]
- *        Element which should receive the event
- * @param {MozMillElement} [aExpectedEvent.type]
- *        Type of the expected mouse event
- */
-MozMillElement.prototype.waitThenTap = function (aTimeout, aInterval,
-                                                 aOffsetX, aOffsetY, aExpectedEvent) {
-  this.waitForElement(aTimeout, aInterval);
-  this.tap(aOffsetX, aOffsetY, aExpectedEvent);
-};
-
-// Dispatches an HTMLEvent
-MozMillElement.prototype.dispatchEvent = function (eventType, canBubble, modifiers) {
-  canBubble = canBubble || true;
-  modifiers = modifiers || { };
-
-  let document = 'ownerDocument' in this.element ? this.element.ownerDocument
-                                                 : this.element.document;
-
-  let evt = document.createEvent('HTMLEvents');
-  evt.shiftKey = modifiers["shift"];
-  evt.metaKey = modifiers["meta"];
-  evt.altKey = modifiers["alt"];
-  evt.ctrlKey = modifiers["ctrl"];
-  evt.initEvent(eventType, canBubble, true);
-
-  this.element.dispatchEvent(evt);
-};
-
-
-/**
- * MozMillCheckBox, which inherits from MozMillElement
- */
-function MozMillCheckBox(locatorType, locator, args) {
-  MozMillElement.call(this, locatorType, locator, args);
-}
-
-
-MozMillCheckBox.prototype = Object.create(MozMillElement.prototype, {
-  check : {
-    /**
-     * Enable/Disable a checkbox depending on the target state
-     *
-     * @param {boolean} state State to set
-     * @return {boolean} Success state
-     */
-    value : function MMCB_check(state) {
-      var result = false;
-
-      if (!this.element) {
-        throw new Error("could not find element " + this.getInfo());
-      }
-
-      // If we have a XUL element, unwrap its XPCNativeWrapper
-      if (this.element.namespaceURI == NAMESPACE_XUL) {
-        this.element = utils.unwrapNode(this.element);
-      }
-
-      state = (typeof(state) == "boolean") ? state : false;
-      if (state != this.element.checked) {
-        this.click();
-        var element = this.element;
-
-        assert.waitFor(function () {
-          return element.checked == state;
-        }, "CheckBox.check(): Checkbox " + this.getInfo() + " could not be checked/unchecked", 500);
-
-        result = true;
-      }
-
-      broker.pass({'function':'MozMillCheckBox.check(' + this.getInfo() +
-                   ', state: ' + state + ')'});
-
-      return result;
-    }
-  }
-});
-
-
-/**
- * Returns true if node is of type MozMillCheckBox
- *
- * @static
- * @param {DOMNode} node Node to check for its type
- * @return {boolean} True if node is of type checkbox
- */
-MozMillCheckBox.isType = function MMCB_isType(node) {
-  return ((node.localName.toLowerCase() == "input" && node.getAttribute("type") == "checkbox") ||
-    (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'checkbox') ||
-    (node.localName.toLowerCase() == 'checkbox'));
-};
-
-
-/**
- * MozMillRadio, which inherits from MozMillElement
- */
-function MozMillRadio(locatorType, locator, args) {
-  MozMillElement.call(this, locatorType, locator, args);
-}
-
-
-MozMillRadio.prototype = Object.create(MozMillElement.prototype, {
-  select : {
-    /**
-     * Select the given radio button
-     *
-     * @param {number} [index=0]
-     *        Specifies which radio button in the group to select (only
-     *        applicable to radiogroup elements)
-     * @return {boolean} Success state
-     */
-    value : function MMR_select(index) {
-      if (!this.element) {
-        throw new Error("could not find element " + this.getInfo());
-      }
-
-      if (this.element.localName.toLowerCase() == "radiogroup") {
-        var element = this.element.getElementsByTagName("radio")[index || 0];
-        new MozMillRadio("Elem", element).click();
-      } else {
-        var element = this.element;
-        this.click();
-      }
-
-      assert.waitFor(function () {
-        // If we have a XUL element, unwrap its XPCNativeWrapper
-        if (element.namespaceURI == NAMESPACE_XUL) {
-          element = utils.unwrapNode(element);
-          return element.selected == true;
-        }
-
-        return element.checked == true;
-      }, "Radio.select(): Radio button " + this.getInfo() + " has been selected", 500);
-
-      broker.pass({'function':'MozMillRadio.select(' + this.getInfo() + ')'});
-
-      return true;
-    }
-  }
-});
-
-
-/**
- * Returns true if node is of type MozMillRadio
- *
- * @static
- * @param {DOMNode} node Node to check for its type
- * @return {boolean} True if node is of type radio
- */
-MozMillRadio.isType = function MMR_isType(node) {
-  return ((node.localName.toLowerCase() == 'input' && node.getAttribute('type') == 'radio') ||
-    (node.localName.toLowerCase() == 'toolbarbutton' && node.getAttribute('type') == 'radio') ||
-    (node.localName.toLowerCase() == 'radio') ||
-    (node.localName.toLowerCase() == 'radiogroup'));
-};
-
-
-/**
- * MozMillDropList, which inherits from MozMillElement
- */
-function MozMillDropList(locatorType, locator, args) {
-  MozMillElement.call(this, locatorType, locator, args);
-}
-
-
-MozMillDropList.prototype = Object.create(MozMillElement.prototype, {
-  select : {
-    /**
-     * Select the specified option and trigger the relevant events of the element
-     * @return {boolean}
-     */
-    value : function MMDL_select(index, option, value) {
-      if (!this.element){
-        throw new Error("Could not find element " + this.getInfo());
-      }
-
-      //if we have a select drop down
-      if (this.element.localName.toLowerCase() == "select"){
-        var item = null;
-
-        // The selected item should be set via its index
-        if (index != undefined) {
-          // Resetting a menulist has to be handled separately
-          if (index == -1) {
-            this.dispatchEvent('focus', false);
-            this.element.selectedIndex = index;
-            this.dispatchEvent('change', true);
-
-            broker.pass({'function':'MozMillDropList.select()'});
-
-            return true;
-          } else {
-            item = this.element.options.item(index);
-          }
-        } else {
-          for (var i = 0; i < this.element.options.length; i++) {
-            var entry = this.element.options.item(i);
-            if (option != undefined && entry.innerHTML == option ||
-              value != undefined && entry.value == value) {
-              item = entry;
-              break;
-            }
-          }
-        }
-
-        // Click the item
-        try {
-          // EventUtils.synthesizeMouse doesn't work.
-          this.dispatchEvent('focus', false);
-          item.selected = true;
-          this.dispatchEvent('change', true);
-
-          var self = this;
-          var selected = index || option || value;
-          assert.waitFor(function () {
-            switch (selected) {
-              case index:
-                return selected === self.element.selectedIndex;
-                break;
-              case option:
-                return selected === item.label;
-                break;
-              case value:
-                return selected === item.value;
-                break;
-            }
-          }, "DropList.select(): The correct item has been selected");
-
-          broker.pass({'function':'MozMillDropList.select()'});
-
-          return true;
-        } catch (e) {
-          throw new Error("No item selected for element " + this.getInfo());
-        }
-      }
-      //if we have a xul menupopup select accordingly
-      else if (this.element.namespaceURI.toLowerCase() == NAMESPACE_XUL) {
-        var ownerDoc = this.element.ownerDocument;
-        // Unwrap the XUL element's XPCNativeWrapper
-        this.element = utils.unwrapNode(this.element);
-        // Get the list of menuitems
-        var menuitems = this.element.
-                        getElementsByTagNameNS(NAMESPACE_XUL, "menupopup")[0].
-                        getElementsByTagNameNS(NAMESPACE_XUL, "menuitem");
-
-        var item = null;
-
-        if (index != undefined) {
-          if (index == -1) {
-            this.dispatchEvent('focus', false);
-            this.element.boxObject.activeChild = null;
-            this.dispatchEvent('change', true);
-
-            broker.pass({'function':'MozMillDropList.select()'});
-
-            return true;
-          } else {
-            item = menuitems[index];
-          }
-        } else {
-          for (var i = 0; i < menuitems.length; i++) {
-            var entry = menuitems[i];
-            if (option != undefined && entry.label == option ||
-              value != undefined && entry.value == value) {
-              item = entry;
-              break;
-            }
-          }
-        }
-
-        // Click the item
-        try {
-          item.click();
-
-          var self = this;
-          var selected = index || option || value;
-          assert.waitFor(function () {
-            switch (selected) {
-              case index:
-                return selected === self.element.selectedIndex;
-                break;
-              case option:
-                return selected === self.element.label;
-                break;
-              case value:
-                return selected === self.element.value;
-                break;
-            }
-          }, "DropList.select(): The correct item has been selected");
-
-          broker.pass({'function':'MozMillDropList.select()'});
-
-          return true;
-        } catch (e) {
-          throw new Error('No item selected for element ' + this.getInfo());
-        }
-      }
-    }
-  }
-});
-
-
-/**
- * Returns true if node is of type MozMillDropList
- *
- * @static
- * @param {DOMNode} node Node to check for its type
- * @return {boolean} True if node is of type dropdown list
- */
-MozMillDropList.isType = function MMR_isType(node) {
-  return ((node.localName.toLowerCase() == 'toolbarbutton' &&
-    (node.getAttribute('type') == 'menu' || node.getAttribute('type') == 'menu-button')) ||
-    (node.localName.toLowerCase() == 'menu') ||
-    (node.localName.toLowerCase() == 'menulist') ||
-    (node.localName.toLowerCase() == 'select' ));
-};
-
-
-/**
- * MozMillTextBox, which inherits from MozMillElement
- */
-function MozMillTextBox(locatorType, locator, args) {
-  MozMillElement.call(this, locatorType, locator, args);
-}
-
-
-MozMillTextBox.prototype = Object.create(MozMillElement.prototype, {
-  sendKeys : {
-    /**
-     * Synthesize keypress events for each character on the given element
-     *
-     * @param {string} aText
-     *        The text to send as single keypress events
-     * @param {object} aModifiers
-     *        Information about the modifier keys to send
-     *        Elements: accelKey   - Hold down the accelerator key (ctrl/meta)
-     *                               [optional - default: false]
-     *                  altKey     - Hold down the alt key
-     *                              [optional - default: false]
-     *                  ctrlKey    - Hold down the ctrl key
-     *                               [optional - default: false]
-     *                  metaKey    - Hold down the meta key (command key on Mac)
-     *                               [optional - default: false]
-     *                  shiftKey   - Hold down the shift key
-     *                               [optional - default: false]
-     * @param {object} aExpectedEvent
-     *        Information about the expected event to occur
-     *        Elements: target     - Element which should receive the event
-     *                               [optional - default: current element]
-     *                  type       - Type of the expected key event
-     * @return {boolean} Success state
-     */
-    value : function MMTB_sendKeys(aText, aModifiers, aExpectedEvent) {
-      if (!this.element) {
-        throw new Error("could not find element " + this.getInfo());
-      }
-
-      var element = this.element;
-      Array.forEach(aText, function (letter) {
-        var win = element.ownerGlobal || element;
-        element.focus();
-
-        if (aExpectedEvent) {
-          if (!aExpectedEvent.type) {
-            throw new Error(arguments.callee.name + ": Expected event type not specified");
-          }
-
-          var target = aExpectedEvent.target ? aExpectedEvent.target.getNode()
-            : element;
-          EventUtils.synthesizeKeyExpectEvent(letter, aModifiers || {}, target,
-            aExpectedEvent.type,
-            "MozMillTextBox.sendKeys()", win);
-        } else {
-          EventUtils.synthesizeKey(letter, aModifiers || {}, win);
-        }
-      });
-
-      broker.pass({'function':'MozMillTextBox.type()'});
-
-      return true;
-    }
-  }
-});
-
-
-/**
- * Returns true if node is of type MozMillTextBox
- *
- * @static
- * @param {DOMNode} node Node to check for its type
- * @return {boolean} True if node is of type textbox
- */
-MozMillTextBox.isType = function MMR_isType(node) {
-  return ((node.localName.toLowerCase() == 'input' &&
-    (node.getAttribute('type') == 'text' || node.getAttribute('type') == 'search')) ||
-    (node.localName.toLowerCase() == 'textarea') ||
-    (node.localName.toLowerCase() == 'textbox'));
-};
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/mozmill.js
+++ /dev/null
@@ -1,283 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["controller", "utils", "elementslib", "os",
-                        "getBrowserController", "newBrowserController",
-                        "getAddonsController", "getPreferencesController",
-                        "newMail3PaneController", "getMail3PaneController",
-                        "wm", "platform", "getAddrbkController",
-                        "getMsgComposeController", "getDownloadsController",
-                        "Application", "findElement",
-                        "getPlacesController", 'isMac', 'isLinux', 'isWindows',
-                        "firePythonCallback", "getAddons"
-                       ];
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-
-Cu.import("resource://gre/modules/AddonManager.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-// imports
-var assertions = {};  Cu.import('resource://mozmill/modules/assertions.js', assertions);
-var broker = {};      Cu.import('resource://mozmill/driver/msgbroker.js', broker);
-var controller = {};  Cu.import('resource://mozmill/driver/controller.js', controller);
-var elementslib = {}; Cu.import('resource://mozmill/driver/elementslib.js', elementslib);
-var findElement = {}; Cu.import('resource://mozmill/driver/mozelement.js', findElement);
-var os = {};          Cu.import('resource://mozmill/stdlib/os.js', os);
-var utils = {};       Cu.import('resource://mozmill/stdlib/utils.js', utils);
-var windows = {};     Cu.import('resource://mozmill/modules/windows.js', windows);
-
-
-const DEBUG = false;
-
-// This is a useful "check" timer. See utils.js, good for debugging
-if (DEBUG) {
-  utils.startTimer();
-}
-
-var assert = new assertions.Assert();
-
-// platform information
-var platform = os.getPlatform();
-var isMac = false;
-var isWindows = false;
-var isLinux = false;
-
-if (platform == "darwin"){
-  isMac = true;
-}
-
-if (platform == "winnt"){
-  isWindows = true;
-}
-
-if (platform == "linux"){
-  isLinux = true;
-}
-
-var wm = Services.wm;
-
-var appInfo = Services.appinfo;
-var Application = utils.applicationName;
-
-
-/**
- * Retrieves the list with information about installed add-ons.
- *
- * @returns {String} JSON data of installed add-ons
- */
-function getAddons() {
-  var addons = null;
-
-  AddonManager.getAllAddons(function (addonList) {
-    var tmp_list = [ ];
-
-    addonList.forEach(function (addon) {
-      var tmp = { };
-
-      // We have to filter out properties of type 'function' of the addon
-      // object, which will break JSON.stringify() and result in incomplete
-      // addon information.
-      for (var key in addon) {
-        if (typeof(addon[key]) !== "function") {
-          tmp[key] = addon[key];
-        }
-      }
-
-      tmp_list.push(tmp);
-    });
-
-    addons = tmp_list;
-  });
-
-  try {
-    // Sychronize with getAllAddons so we do not return too early
-    assert.waitFor(function () {
-      return !!addons;
-    })
-
-    return addons;
-  } catch (e) {
-    return null;
-  }
-}
-
-/**
- * Retrieves application details for the Mozmill report
- *
- * @return {String} JSON data of application details
- */
-function getApplicationDetails() {
-  var locale = Services.locale.getAppLocaleAsLangTag();
-
-  // Put all our necessary information into JSON and return it:
-  // appinfo, startupinfo, and addons
-  var details = {
-    application_id: appInfo.ID,
-    application_name: Application,
-    application_version: appInfo.version,
-    application_locale: locale,
-    platform_buildid: appInfo.platformBuildID,
-    platform_version: appInfo.platformVersion,
-    addons: getAddons(),
-    startupinfo: getStartupInfo(),
-    paths: {
-      appdata: Services.dirsvc.get('UAppData', Ci.nsIFile).path,
-      profile: Services.dirsvc.get('ProfD', Ci.nsIFile).path
-    }
-  };
-
-  return JSON.stringify(details);
-}
-
-// get startup time if available
-// see http://blog.mozilla.com/tglek/2011/04/26/measuring-startup-speed-correctly/
-function getStartupInfo() {
-  var startupInfo = {};
-
-  try {
-    var _startupInfo = Services.startup.getStartupInfo();
-    for (var time in _startupInfo) {
-      // convert from Date object to ms since epoch
-      startupInfo[time] = _startupInfo[time].getTime();
-    }
-  } catch (e) {
-    startupInfo = null;
-  }
-
-  return startupInfo;
-}
-
-
-
-function newBrowserController () {
-  return new controller.MozMillController(utils.getMethodInWindows('OpenBrowserWindow')());
-}
-
-function getBrowserController () {
-  var browserWindow = wm.getMostRecentWindow("navigator:browser");
-
-  if (browserWindow == null) {
-    return newBrowserController();
-  } else {
-    return new controller.MozMillController(browserWindow);
-  }
-}
-
-function getPlacesController () {
-  utils.getMethodInWindows('PlacesCommandHook').showPlacesOrganizer('AllBookmarks');
-
-  return new controller.MozMillController(wm.getMostRecentWindow(''));
-}
-
-function getAddonsController () {
-  if (Application == 'SeaMonkey') {
-    utils.getMethodInWindows('toEM')();
-  }
-  else if (Application == 'Thunderbird') {
-    utils.getMethodInWindows('openAddonsMgr')();
-  }
-  else if (Application == 'Sunbird') {
-    utils.getMethodInWindows('goOpenAddons')();
-  } else {
-    utils.getMethodInWindows('BrowserOpenAddonsMgr')();
-  }
-
-  return new controller.MozMillController(wm.getMostRecentWindow(''));
-}
-
-function getDownloadsController() {
-  utils.getMethodInWindows('BrowserDownloadsUI')();
-
-  return new controller.MozMillController(wm.getMostRecentWindow(''));
-}
-
-function getPreferencesController() {
-  if (Application == 'Thunderbird') {
-    utils.getMethodInWindows('openOptionsDialog')();
-  } else {
-    utils.getMethodInWindows('openPreferences')();
-  }
-
-  return new controller.MozMillController(wm.getMostRecentWindow(''));
-}
-
-// Thunderbird functions
-function newMail3PaneController () {
-  return new controller.MozMillController(utils.getMethodInWindows('toMessengerWindow')());
-}
-
-function getMail3PaneController () {
-  var mail3PaneWindow = wm.getMostRecentWindow("mail:3pane");
-
-  if (mail3PaneWindow == null) {
-    return newMail3PaneController();
-  } else {
-    return new controller.MozMillController(mail3PaneWindow);
-  }
-}
-
-// Thunderbird - Address book window
-function newAddrbkController () {
-  utils.getMethodInWindows("toAddressBook")();
-  utils.sleep(2000);
-  var addyWin = wm.getMostRecentWindow("mail:addressbook");
-
-  return new controller.MozMillController(addyWin);
-}
-
-function getAddrbkController () {
-  var addrbkWindow = wm.getMostRecentWindow("mail:addressbook");
-  if (addrbkWindow == null) {
-    return newAddrbkController();
-  } else {
-    return new controller.MozMillController(addrbkWindow);
-  }
-}
-
-function firePythonCallback (filename, method, args, kwargs) {
-  let obj = {'filename': filename, 'method': method};
-  obj['args'] = args || [];
-  obj['kwargs'] = kwargs || {};
-
-  broker.sendMessage("firePythonCallback", obj);
-}
-
-function timer (name) {
-  this.name = name;
-  this.timers = {};
-  this.actions = [];
-
-  frame.timers.push(this);
-}
-
-timer.prototype.start = function (name) {
-  this.timers[name].startTime = (new Date).getTime();
-}
-
-timer.prototype.stop = function (name) {
-  var t = this.timers[name];
-
-  t.endTime = (new Date).getTime();
-  t.totalTime = (t.endTime - t.startTime);
-}
-
-timer.prototype.end = function () {
-  frame.events.fireEvent("timer", this);
-  frame.timers.remove(this);
-}
-
-// Initialization
-
-/**
- * Initialize Mozmill
- */
-function initialize() {
-  windows.init();
-}
-
-initialize();
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/driver/msgbroker.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['addListener', 'addObject',
-                        'removeListener',
-                        'sendMessage', 'log', 'pass', 'fail'];
-
-var listeners = {};
-
-// add a listener for a specific message type
-function addListener(msgType, listener) {
-  if (listeners[msgType] === undefined) {
-    listeners[msgType] = [];
-  }
-
-  listeners[msgType].push(listener);
-}
-
-// add each method in an object as a message listener
-function addObject(object) {
-  for (var msgType in object) {
-    addListener(msgType, object[msgType]);
-  }
-}
-
-// remove a listener for all message types
-function removeListener(listener) {
-  for (var msgType in listeners) {
-    for (let i = 0; i < listeners.length; ++i) {
-      if (listeners[msgType][i] == listener) {
-        listeners[msgType].splice(i, 1); // remove listener from array
-      }
-    }
-  }
-}
-
-function sendMessage(msgType, obj) {
-  if (listeners[msgType] === undefined) {
-    return;
-  }
-
-  for (let i = 0; i < listeners[msgType].length; ++i) {
-    listeners[msgType][i](obj);
-  }
-}
-
-function log(obj) {
-  sendMessage('log', obj);
-}
-
-function pass(obj) {
-  sendMessage('pass', obj);
-}
-
-function fail(obj) {
-  sendMessage('fail', obj);
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/assertions.js
+++ /dev/null
@@ -1,672 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['Assert', 'Expect'];
-
-var Cu = Components.utils;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-var broker = {}; Cu.import('resource://mozmill/driver/msgbroker.js', broker);
-var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
-var stack = {}; Cu.import('resource://mozmill/modules/stack.js', stack);
-
-/**
- * @name assertions
- * @namespace Defines expect and assert methods to be used for assertions.
- */
-
-/**
- * The Assert class implements fatal assertions, and can be used in cases
- * when a failing test has to directly abort the current test function. All
- * remaining tasks will not be performed.
- *
- */
-var Assert = function () {}
-
-Assert.prototype = {
-
-  // The following deepEquals implementation is from Narwhal under this license:
-
-  // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
-  //
-  // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
-  //
-  // Originally from narwhal.js (http://narwhaljs.org)
-  // Copyright (c) 2009 Thomas Robinson <280north.com>
-  //
-  // Permission is hereby granted, free of charge, to any person obtaining a copy
-  // of this software and associated documentation files (the 'Software'), to
-  // deal in the Software without restriction, including without limitation the
-  // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-  // sell copies of the Software, and to permit persons to whom the Software is
-  // furnished to do so, subject to the following conditions:
-  //
-  // The above copyright notice and this permission notice shall be included in
-  // all copies or substantial portions of the Software.
-  //
-  // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-  // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-  // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-  _deepEqual: function (actual, expected) {
-    // 7.1. All identical values are equivalent, as determined by ===.
-    if (actual === expected) {
-      return true;
-
-    // 7.2. If the expected value is a Date object, the actual value is
-    // equivalent if it is also a Date object that refers to the same time.
-    } else if (actual instanceof Date && expected instanceof Date) {
-      return actual.getTime() === expected.getTime();
-
-    // 7.3. Other pairs that do not both pass typeof value == 'object',
-    // equivalence is determined by ==.
-    } else if (typeof actual != 'object' && typeof expected != 'object') {
-      return actual == expected;
-
-    // 7.4. For all other Object pairs, including Array objects, equivalence is
-    // determined by having the same number of owned properties (as verified
-    // with Object.prototype.hasOwnProperty.call), the same set of keys
-    // (although not necessarily the same order), equivalent values for every
-    // corresponding key, and an identical 'prototype' property. Note: this
-    // accounts for both named and indexed properties on Arrays.
-    } else {
-      return this._objEquiv(actual, expected);
-    }
-  },
-
-  _objEquiv: function (a, b) {
-    if (a == null || a == undefined || b == null || b == undefined)
-      return false;
-    // an identical 'prototype' property.
-    if (a.prototype !== b.prototype) return false;
-
-    function isArguments(object) {
-      return Object.prototype.toString.call(object) == '[object Arguments]';
-    }
-
-    //~~~I've managed to break Object.keys through screwy arguments passing.
-    // Converting to array solves the problem.
-    if (isArguments(a)) {
-      if (!isArguments(b)) {
-        return false;
-      }
-      a = pSlice.call(a);
-      b = pSlice.call(b);
-      return this._deepEqual(a, b);
-    }
-    try {
-      var ka = Object.keys(a),
-          kb = Object.keys(b),
-          key, i;
-    } catch (e) {//happens when one is a string literal and the other isn't
-      return false;
-    }
-    // having the same number of owned properties (keys incorporates
-    // hasOwnProperty)
-    if (ka.length != kb.length)
-      return false;
-    //the same set of keys (although not necessarily the same order),
-    ka.sort();
-    kb.sort();
-    //~~~cheap key test
-    for (i = ka.length - 1; i >= 0; i--) {
-      if (ka[i] != kb[i])
-        return false;
-    }
-    //equivalent values for every corresponding key, and
-    //~~~possibly expensive deep test
-    for (i = ka.length - 1; i >= 0; i--) {
-      key = ka[i];
-      if (!this._deepEqual(a[key], b[key])) return false;
-    }
-    return true;
-  },
-
-  _expectedException : function Assert__expectedException(actual, expected) {
-    if (!actual || !expected) {
-      return false;
-    }
-
-    if (expected instanceof RegExp) {
-      return expected.test(actual);
-    } else if (actual instanceof expected) {
-      return true;
-    } else if (expected.call({}, actual) === true) {
-      return true;
-    } else if (actual.name === expected.name) {
-      return true;
-    }
-
-    return false;
-  },
-
-  /**
-   * Log a test as failing by throwing an AssertionException.
-   *
-   * @param {object} aResult
-   *   Test result details used for reporting.
-   *   <dl>
-   *     <dd>fileName</dd>
-   *     <dt>Name of the file in which the assertion failed.</dt>
-   *     <dd>functionName</dd>
-   *     <dt>Function in which the assertion failed.</dt>
-   *     <dd>lineNumber</dd>
-   *     <dt>Line number of the file in which the assertion failed.</dt>
-   *     <dd>message</dd>
-   *     <dt>Message why the assertion failed.</dt>
-   *   </dl>
-   * @throws {errors.AssertionError}
-   *
-   */
-  _logFail: function Assert__logFail(aResult) {
-    throw new errors.AssertionError(aResult.message,
-                                    aResult.fileName,
-                                    aResult.lineNumber,
-                                    aResult.functionName,
-                                    aResult.name);
-  },
-
-  /**
-   * Log a test as passing by adding a pass frame.
-   *
-   * @param {object} aResult
-   *   Test result details used for reporting.
-   *   <dl>
-   *     <dd>fileName</dd>
-   *     <dt>Name of the file in which the assertion failed.</dt>
-   *     <dd>functionName</dd>
-   *     <dt>Function in which the assertion failed.</dt>
-   *     <dd>lineNumber</dd>
-   *     <dt>Line number of the file in which the assertion failed.</dt>
-   *     <dd>message</dd>
-   *     <dt>Message why the assertion failed.</dt>
-   *   </dl>
-   */
-  _logPass: function Assert__logPass(aResult) {
-    broker.pass({pass: aResult});
-  },
-
-  /**
-   * Test the condition and mark test as passed or failed
-   *
-   * @param {boolean} aCondition
-   *   Condition to test.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @param {string} aDiagnosis
-   *   Diagnose message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  _test: function Assert__test(aCondition, aMessage, aDiagnosis) {
-    let diagnosis = aDiagnosis || "";
-    let message = aMessage || "";
-
-    if (diagnosis)
-      message = aMessage ? message + " - " + diagnosis : diagnosis;
-
-    // Build result data
-    let frame = stack.findCallerFrame(Components.stack);
-
-    let result = {
-      'fileName'     : frame.filename.replace(/(.*)-> /, ""),
-      'functionName' : frame.name,
-      'lineNumber'   : frame.lineNumber,
-      'message'      : message
-    };
-
-    // Log test result
-    if (aCondition) {
-      this._logPass(result);
-    }
-    else {
-      result.stack = Components.stack;
-      this._logFail(result);
-    }
-
-    return aCondition;
-  },
-
-  /**
-   * Perform an always passing test
-   *
-   * @param {string} aMessage
-   *   Message to show for the test result.
-   * @returns {boolean} Always returns true.
-   */
-  pass: function Assert_pass(aMessage) {
-    return this._test(true, aMessage, undefined);
-  },
-
-  /**
-   * Perform an always failing test
-   *
-   * @param {string} aMessage
-   *   Message to show for the test result.
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Always returns false.
-   */
-  fail: function Assert_fail(aMessage) {
-    return this._test(false, aMessage, undefined);
-  },
-
-  /**
-   * Test if the value pass
-   *
-   * @param {boolean|string|number|object} aValue
-   *   Value to test.
-   * @param {string} aMessage
-   *   Message to show for the test result.
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  ok: function Assert_ok(aValue, aMessage) {
-    let condition = !!aValue;
-    let diagnosis = "got '" + aValue + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
- /**
-   * Test if both specified values are identical.
-   *
-   * @param {boolean|string|number|object} aValue
-   *   Value to test.
-   * @param {boolean|string|number|object} aExpected
-   *   Value to strictly compare with.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  equal: function Assert_equal(aValue, aExpected, aMessage) {
-    let condition = (aValue === aExpected);
-    let diagnosis = "'" + aValue + "' should equal '" + aExpected + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
- /**
-   * Test if both specified values are not identical.
-   *
-   * @param {boolean|string|number|object} aValue
-   *   Value to test.
-   * @param {boolean|string|number|object} aExpected
-   *   Value to strictly compare with.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  notEqual: function Assert_notEqual(aValue, aExpected, aMessage) {
-    let condition = (aValue !== aExpected);
-    let diagnosis = "'" + aValue + "' should not equal '" + aExpected + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Test if an object equals another object
-   *
-   * @param {object} aValue
-   *   The object to test.
-   * @param {object} aExpected
-   *   The object to strictly compare with.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  deepEqual: function equal(aValue, aExpected, aMessage) {
-    let condition = this._deepEqual(aValue, aExpected);
-    try {
-      var aValueString = JSON.stringify(aValue);
-    } catch (e) {
-      var aValueString = String(aValue);
-    }
-    try {
-      var aExpectedString = JSON.stringify(aExpected);
-    } catch (e) {
-      var aExpectedString = String(aExpected);
-    }
-
-    let diagnosis = "'" + aValueString + "' should equal '" +
-                    aExpectedString + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Test if an object does not equal another object
-   *
-   * @param {object} aValue
-   *   The object to test.
-   * @param {object} aExpected
-   *   The object to strictly compare with.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  notDeepEqual: function notEqual(aValue, aExpected, aMessage) {
-     let condition = !this._deepEqual(aValue, aExpected);
-     try {
-       var aValueString = JSON.stringify(aValue);
-     } catch (e) {
-       var aValueString = String(aValue);
-     }
-     try {
-       var aExpectedString = JSON.stringify(aExpected);
-     } catch (e) {
-       var aExpectedString = String(aExpected);
-     }
-
-     let diagnosis = "'" + aValueString + "' should not equal '" +
-                     aExpectedString + "'";
-
-     return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Test if the regular expression matches the string.
-   *
-   * @param {string} aString
-   *   String to test.
-   * @param {RegEx} aRegex
-   *   Regular expression to use for testing that a match exists.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  match: function Assert_match(aString, aRegex, aMessage) {
-    // XXX Bug 634948
-    // Regex objects are transformed to strings when evaluated in a sandbox
-    // For now lets re-create the regex from its string representation
-    let pattern = "";
-    let flags = "";
-    try {
-      let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
-
-      pattern = matches[1];
-      flags = matches[2];
-    } catch (e) {
-    }
-
-    let regex = new RegExp(pattern, flags);
-    let condition = (aString.match(regex) !== null);
-    let diagnosis = "'" + regex + "' matches for '" + aString + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Test if the regular expression does not match the string.
-   *
-   * @param {string} aString
-   *   String to test.
-   * @param {RegEx} aRegex
-   *   Regular expression to use for testing that a match does not exist.
-   * @param {string} aMessage
-   *   Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  notMatch: function Assert_notMatch(aString, aRegex, aMessage) {
-    // XXX Bug 634948
-    // Regex objects are transformed to strings when evaluated in a sandbox
-    // For now lets re-create the regex from its string representation
-    let pattern = flags = "";
-    try {
-      let matches = aRegex.toString().match(/\/(.*)\/(.*)/);
-
-      pattern = matches[1];
-      flags = matches[2];
-    } catch (e) {
-    }
-
-    let regex = new RegExp(pattern, flags);
-    let condition = (aString.match(regex) === null);
-    let diagnosis = "'" + regex + "' doesn't match for '" + aString + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-
-  /**
-   * Test if a code block throws an exception.
-   *
-   * @param {string} block
-   *   function to call to test for exception
-   * @param {RegEx} error
-   *   the expected error class
-   * @param {string} message
-   *   message to present if assertion fails
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  throws : function Assert_throws(block, /*optional*/error, /*optional*/message) {
-    return this._throws.apply(this, [true].concat(Array.prototype.slice.call(arguments)));
-  },
-
-  /**
-   * Test if a code block doesn't throw an exception.
-   *
-   * @param {string} block
-   *   function to call to test for exception
-   * @param {RegEx} error
-   *   the expected error class
-   * @param {string} message
-   *   message to present if assertion fails
-   * @throws {errors.AssertionError}
-   *
-   * @returns {boolean} Result of the test.
-   */
-  doesNotThrow : function Assert_doesNotThrow(block, /*optional*/error, /*optional*/message) {
-    return this._throws.apply(this, [false].concat(Array.prototype.slice.call(arguments)));
-  },
-
-  /* Tests whether a code block throws the expected exception
-     class. helper for throws() and doesNotThrow()
-
-     adapted from node.js's assert._throws()
-     https://github.com/joyent/node/blob/master/lib/assert.js
-  */
-  _throws : function Assert__throws(shouldThrow, block, expected, message) {
-    var actual;
-
-    if (typeof expected === 'string') {
-      message = expected;
-      expected = null;
-    }
-
-    try {
-      block();
-    } catch (e) {
-      actual = e;
-    }
-
-    message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
-              (message ? ' ' + message : '.');
-
-    if (shouldThrow && !actual) {
-      return this._test(false, message, 'Missing expected exception');
-    }
-
-    if (!shouldThrow && this._expectedException(actual, expected)) {
-      return this._test(false, message, 'Got unwanted exception');
-    }
-
-    if ((shouldThrow && actual && expected &&
-        !this._expectedException(actual, expected)) || (!shouldThrow && actual)) {
-      throw actual;
-    }
-
-    return this._test(true, message);
-  },
-
-  /**
-   * Test if the string contains the pattern.
-   *
-   * @param {String} aString String to test.
-   * @param {String} aPattern Pattern to look for in the string
-   * @param {String} aMessage Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {Boolean} Result of the test.
-   */
-  contain: function Assert_contain(aString, aPattern, aMessage) {
-    let condition = (aString.indexOf(aPattern) !== -1);
-    let diagnosis = "'" + aString + "' should contain '" + aPattern + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Test if the string does not contain the pattern.
-   *
-   * @param {String} aString String to test.
-   * @param {String} aPattern Pattern to look for in the string
-   * @param {String} aMessage Message to show for the test result
-   * @throws {errors.AssertionError}
-   *
-   * @returns {Boolean} Result of the test.
-   */
-  notContain: function Assert_notContain(aString, aPattern, aMessage) {
-    let condition = (aString.indexOf(aPattern) === -1);
-    let diagnosis = "'" + aString + "' should not contain '" + aPattern + "'";
-
-    return this._test(condition, aMessage, diagnosis);
-  },
-
-  /**
-   * Waits for the callback evaluates to true
-   *
-   * @param {Function} aCallback
-   *        Callback for evaluation
-   * @param {String} aMessage
-   *        Message to show for result
-   * @param {Number} aTimeout
-   *        Timeout in waiting for evaluation
-   * @param {Number} aInterval
-   *        Interval between evaluation attempts
-   * @param {Object} aThisObject
-   *        this object
-   * @throws {errors.AssertionError}
-   *
-   * @returns {Boolean} Result of the test.
-   */
-  waitFor: function Assert_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
-    var timeout = aTimeout || 5000;
-    var interval = aInterval || 100;
-
-    var self = {
-      timeIsUp: false,
-      result: aCallback.call(aThisObject)
-    };
-    var deadline = Date.now() + timeout;
-
-    function wait() {
-      if (self.result !== true) {
-        self.result = aCallback.call(aThisObject);
-        self.timeIsUp = Date.now() > deadline;
-      }
-    }
-
-    var hwindow = Services.appShell.hiddenDOMWindow;
-    var timeoutInterval = hwindow.setInterval(wait, interval);
-    var thread = Services.tm.currentThread;
-
-    Services.tm.spinEventLoopUntil(() => {
-      let type = typeof(self.result);
-      if (type !== 'boolean') {
-        throw TypeError("waitFor() callback has to return a boolean" +
-                        " instead of '" + type + "'");
-      }
-
-      return self.result === true || self.timeIsUp;
-    });
-
-    hwindow.clearInterval(timeoutInterval);
-
-    if (self.result !== true && self.timeIsUp) {
-      aMessage = aMessage || arguments.callee.name + ": Timeout exceeded for '" + aCallback + "'";
-      throw new errors.TimeoutError(aMessage);
-    }
-
-    broker.pass({'function':'assert.waitFor()'});
-    return true;
-  }
-}
-
-/* non-fatal assertions */
-var Expect = function () {}
-
-Expect.prototype = new Assert();
-
-/**
- * Log a test as failing by adding a fail frame.
- *
- * @param {object} aResult
- *   Test result details used for reporting.
- *   <dl>
- *     <dd>fileName</dd>
- *     <dt>Name of the file in which the assertion failed.</dt>
- *     <dd>functionName</dd>
- *     <dt>Function in which the assertion failed.</dt>
- *     <dd>lineNumber</dd>
- *     <dt>Line number of the file in which the assertion failed.</dt>
- *     <dd>message</dd>
- *     <dt>Message why the assertion failed.</dt>
- *   </dl>
- */
-Expect.prototype._logFail = function Expect__logFail(aResult) {
-  broker.fail({fail: aResult});
-}
-
-/**
- * Waits for the callback evaluates to true
- *
- * @param {Function} aCallback
- *        Callback for evaluation
- * @param {String} aMessage
- *        Message to show for result
- * @param {Number} aTimeout
- *        Timeout in waiting for evaluation
- * @param {Number} aInterval
- *        Interval between evaluation attempts
- * @param {Object} aThisObject
- *        this object
- */
-Expect.prototype.waitFor = function Expect_waitFor(aCallback, aMessage, aTimeout, aInterval, aThisObject) {
-  let condition = true;
-  let message = aMessage;
-
-  try {
-    Assert.prototype.waitFor.apply(this, arguments);
-  }
-  catch (ex) {
-    if (!(ex instanceof errors.AssertionError)) {
-      throw ex;
-    }
-    message = ex.message;
-    condition = false;
-  }
-
-  return this._test(condition, message);
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/driver.js
+++ /dev/null
@@ -1,290 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * @namespace Defines the Mozmill driver for global actions
- */
-var driver = exports;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-// Temporarily include utils module to re-use sleep
-var assertions = {}; Cu.import('resource://mozmill/modules/assertions.js', assertions);
-var mozmill = {}; Cu.import("resource://mozmill/driver/mozmill.js", mozmill);
-var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
-
-/**
- * Gets the topmost browser window. If there are none at that time, optionally
- * opens one. Otherwise will raise an exception if none are found.
- *
- * @memberOf driver
- * @param {Boolean] [aOpenIfNone=true] Open a new browser window if none are found.
- * @returns {DOMWindow}
- */
-function getBrowserWindow(aOpenIfNone) {
-  // Set default
-  if (typeof aOpenIfNone === 'undefined') {
-    aOpenIfNone = true;
-  }
-
-  // If implicit open is off, turn on strict checking, and vice versa.
-  let win = getTopmostWindowByType("navigator:browser", !aOpenIfNone);
-
-  // Can just assume automatic open here. If we didn't want it and nothing found,
-  // we already raised above when getTopmostWindow was called.
-  if (!win)
-    win = openBrowserWindow();
-
-  return win;
-}
-
-
-/**
- * Retrieves the hidden window on OS X
- *
- * @memberOf driver
- * @returns {DOMWindow} The hidden window
- */
-function getHiddenWindow() {
-  return Services.appShell.hiddenDOMWindow;
-}
-
-
-/**
- * Opens a new browser window
- *
- * @memberOf driver
- * @returns {DOMWindow}
- */
-function openBrowserWindow() {
-  // On OS X we have to be able to create a new browser window even with no other
-  // window open. Therefore we have to use the hidden window. On other platforms
-  // at least one remaining browser window has to exist.
-  var win = mozmill.isMac ? getHiddenWindow() :
-                            getTopmostWindowByType("navigator:browser", true);
-  return win.OpenBrowserWindow();
-}
-
-
-/**
- * Pause the test execution for the given amount of time
- *
- * @type utils.sleep
- * @memberOf driver
- */
-var sleep = utils.sleep;
-
-/**
- * Wait until the given condition via the callback returns true.
- *
- * @type utils.waitFor
- * @memberOf driver
- */
-var waitFor = assertions.Assert.waitFor;
-
-//
-// INTERNAL WINDOW ENUMERATIONS
-//
-
-/**
- * Internal function to build a list of DOM windows using a given enumerator
- * and filter.
- *
- * @private
- * @memberOf driver
- * @param {nsISimpleEnumerator} aEnumerator Window enumerator to use.
- * @param {Function} [aFilterCallback] Function which is used to filter windows.
- * @param {Boolean} [aStrict=true] Throw an error if no windows found
- *
- * @returns {DOMWindow[]} The windows found, in the same order as the enumerator.
- */
-function _getWindows(aEnumerator, aFilterCallback, aStrict) {
-  // Set default
-  if (typeof aStrict === 'undefined')
-    aStrict = true;
-
-  let windows = [];
-
-  while (aEnumerator.hasMoreElements()) {
-    let window = aEnumerator.getNext();
-
-    if (!aFilterCallback || aFilterCallback(window)) {
-      windows.push(window);
-    }
-  }
-
-  // If this list is empty and we're strict, throw an error
-  if (windows.length === 0 && aStrict) {
-    var message = 'No windows were found';
-
-    // We'll throw a more detailed error if a filter was used.
-    if (aFilterCallback && aFilterCallback.name)
-      message += ' using filter "' + aFilterCallback.name + '"';
-
-    throw new Error(message);
-  }
-
-  return windows;
-}
-
-//
-// FILTER CALLBACKS
-//
-
-/**
- * Generator of a closure to filter a window based by a method
- *
- * @memberOf driver
- * @param {String} aName Name of the method in the window object.
- * @returns {Boolean} True if the condition is met.
- */
-function windowFilterByMethod(aName) {
-  return function byMethod(aWindow) { return (aName in aWindow); }
-}
-
-
-/**
- * Generator of a closure to filter a window based by the its title
- *
- * @param {String} aTitle Title of the window.
- * @returns {Boolean} True if the condition is met.
- */
-function windowFilterByTitle(aTitle) {
-  return function byTitle(aWindow) { return (aWindow.document.title === aTitle); }
-}
-
-
-/**
- * Generator of a closure to filter a window based by the its type
- *
- * @memberOf driver
- * @param {String} aType Type of the window.
- * @returns {Boolean} True if the condition is met.
- */
-function windowFilterByType(aType) {
-  return function byType(aWindow) {
-           var type = aWindow.document.documentElement.getAttribute("windowtype");
-           return (type === aType);
-         }
-}
-
-//
-// WINDOW LIST RETRIEVAL FUNCTIONS
-//
-
-/**
- * Retrieves a sorted list of open windows based on their age (newest to oldest),
- * optionally matching filter criteria.
- *
- * @memberOf driver
- * @param {Function} [aFilterCallback] Function which is used to filter windows.
- * @param {Boolean} [aStrict=true] Throw an error if no windows found
- *
- * @returns {DOMWindow[]} List of windows.
- */
-function getWindowsByAge(aFilterCallback, aStrict) {
-  var windows = _getWindows(Services.wm.getEnumerator(""),
-                            aFilterCallback, aStrict);
-
-  // Reverse the list, since naturally comes back old->new
-  return windows.reverse();
-}
-
-
-/**
- * Retrieves a sorted list of open windows based on their z order (topmost first),
- * optionally matching filter criteria.
- *
- * @memberOf driver
- * @param {Function} [aFilterCallback] Function which is used to filter windows.
- * @param {Boolean} [aStrict=true] Throw an error if no windows found
- *
- * @returns {DOMWindow[]} List of windows.
- */
-function getWindowsByZOrder(aFilterCallback, aStrict) {
-  return _getWindows(Services.wm.getZOrderDOMWindowEnumerator("", true),
-                     aFilterCallback, aStrict);
-}
-
-//
-// SINGLE WINDOW RETRIEVAL FUNCTIONS
-//
-
-/**
- * Retrieves the last opened window, optionally matching filter criteria.
- *
- * @memberOf driver
- * @param {Function} [aFilterCallback] Function which is used to filter windows.
- * @param {Boolean} [aStrict=true] If true, throws error if no window found.
- *
- * @returns {DOMWindow} The window, or null if none found and aStrict == false
- */
-function getNewestWindow(aFilterCallback, aStrict) {
-  var windows = getWindowsByAge(aFilterCallback, aStrict);
-  return windows.length ? windows[0] : null;
-}
-
-/**
- * Retrieves the topmost window, optionally matching filter criteria.
- *
- * @memberOf driver
- * @param {Function} [aFilterCallback] Function which is used to filter windows.
- * @param {Boolean} [aStrict=true] If true, throws error if no window found.
- *
- * @returns {DOMWindow} The window, or null if none found and aStrict == false
- */
-function getTopmostWindow(aFilterCallback, aStrict) {
-  var windows = getWindowsByZOrder(aFilterCallback, aStrict);
-  return windows.length ? windows[0] : null;
-}
-
-
-/**
- * Retrieves the topmost window given by the window type
- *
- * XXX: Bug 462222
- *      This function has to be used instead of getTopmostWindow until the
- *      underlying platform bug has been fixed.
- *
- * @memberOf driver
- * @param {String} [aWindowType=null] Window type to query for
- * @param {Boolean} [aStrict=true] Throw an error if no windows found
- *
- * @returns {DOMWindow} The window, or null if none found and aStrict == false
- */
-function getTopmostWindowByType(aWindowType, aStrict) {
-  if (typeof aStrict === 'undefined')
-    aStrict = true;
-
-  var win = Services.wm.getMostRecentWindow(aWindowType);
-
-  if (win === null && aStrict) {
-    var message = 'No windows of type "' + aWindowType + '" were found';
-    throw new errors.UnexpectedError(message);
-  }
-
-  return win;
-}
-
-
-// Export of functions
-driver.getBrowserWindow = getBrowserWindow;
-driver.getHiddenWindow = getHiddenWindow;
-driver.openBrowserWindow = openBrowserWindow;
-driver.sleep = sleep;
-driver.waitFor = waitFor;
-
-driver.windowFilterByMethod = windowFilterByMethod;
-driver.windowFilterByTitle = windowFilterByTitle;
-driver.windowFilterByType = windowFilterByType;
-
-driver.getWindowsByAge = getWindowsByAge;
-driver.getNewestWindow = getNewestWindow;
-driver.getTopmostWindowByType = getTopmostWindowByType;
-
-
-// XXX Bug: 462222
-//     Currently those functions cannot be used. So they shouldn't be exported.
-//driver.getWindowsByZOrder = getWindowsByZOrder;
-//driver.getTopmostWindow = getTopmostWindow;
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/errors.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['BaseError',
-                        'ApplicationQuitError',
-                        'AssertionError',
-                        'TimeoutError'];
-
-
-/**
- * Creates a new instance of a base error
- *
- * @class Represents the base for custom errors
- * @param {string} [aMessage=Error().message]
- *        The error message to show
- * @param {string} [aFileName=Error().fileName]
- *        The file name where the error has been raised
- * @param {string} [aLineNumber=Error().lineNumber]
- *        The line number of the file where the error has been raised
- * @param {string} [aFunctionName=undefined]
- *        The function name in which the error has been raised
- */
-function BaseError(aMessage, aFileName, aLineNumber, aFunctionName) {
-  this.name = this.constructor.name;
-
-  var err = new Error();
-  if (err.stack) {
-    this.stack = err.stack;
-  }
-
-  this.message = aMessage || err.message;
-  this.fileName = aFileName || err.fileName;
-  this.lineNumber = aLineNumber || err.lineNumber;
-  this.functionName = aFunctionName;
-}
-
-
-/**
- * Creates a new instance of an application quit error used by Mozmill to
- * indicate that the application is going to shutdown
- *
- * @class Represents an error object thrown when the application is going to shutdown
- * @param {string} [aMessage=Error().message]
- *        The error message to show
- * @param {string} [aFileName=Error().fileName]
- *        The file name where the error has been raised
- * @param {string} [aLineNumber=Error().lineNumber]
- *        The line number of the file where the error has been raised
- * @param {string} [aFunctionName=undefined]
- *        The function name in which the error has been raised
- */
-function ApplicationQuitError(aMessage, aFileName, aLineNumber, aFunctionName) {
-  BaseError.apply(this, arguments);
-}
-
-ApplicationQuitError.prototype = Object.create(BaseError.prototype, {
-  constructor : { value : ApplicationQuitError }
-});
-
-
-/**
- * Creates a new instance of an assertion error
- *
- * @class Represents an error object thrown by failing assertions
- * @param {string} [aMessage=Error().message]
- *        The error message to show
- * @param {string} [aFileName=Error().fileName]
- *        The file name where the error has been raised
- * @param {string} [aLineNumber=Error().lineNumber]
- *        The line number of the file where the error has been raised
- * @param {string} [aFunctionName=undefined]
- *        The function name in which the error has been raised
- */
-function AssertionError(aMessage, aFileName, aLineNumber, aFunctionName) {
-  BaseError.apply(this, arguments);
-}
-
-AssertionError.prototype = Object.create(BaseError.prototype, {
-  constructor : { value : AssertionError }
-});
-
-/**
- * Creates a new instance of a timeout error
- *
- * @class Represents an error object thrown by failing assertions
- * @param {string} [aMessage=Error().message]
- *        The error message to show
- * @param {string} [aFileName=Error().fileName]
- *        The file name where the error has been raised
- * @param {string} [aLineNumber=Error().lineNumber]
- *        The line number of the file where the error has been raised
- * @param {string} [aFunctionName=undefined]
- *        The function name in which the error has been raised
- */
-function TimeoutError(aMessage, aFileName, aLineNumber, aFunctionName) {
-  AssertionError.apply(this, arguments);
-}
-
-TimeoutError.prototype = Object.create(AssertionError.prototype, {
-  constructor : { value : TimeoutError }
-});
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/frame.js
+++ /dev/null
@@ -1,787 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['Collector','Runner','events', 'runTestFile', 'log',
-                        'timers', 'persisted', 'shutdownApplication'];
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-const TIMEOUT_SHUTDOWN_HTTPD = 15000;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-Cu.import('resource://mozmill/stdlib/httpd.js');
-
-var broker = {};  Cu.import('resource://mozmill/driver/msgbroker.js', broker);
-var assertions = {}; Cu.import('resource://mozmill/modules/assertions.js', assertions);
-var errors = {}; Cu.import('resource://mozmill/modules/errors.js', errors);
-var os = {};      Cu.import('resource://mozmill/stdlib/os.js', os);
-var strings = {}; Cu.import('resource://mozmill/stdlib/strings.js', strings);
-var arrays = {};  Cu.import('resource://mozmill/stdlib/arrays.js', arrays);
-var withs = {};   Cu.import('resource://mozmill/stdlib/withs.js', withs);
-var utils = {};   Cu.import('resource://mozmill/stdlib/utils.js', utils);
-
-var securableModule = {};
-Cu.import('resource://mozmill/stdlib/securable-module.js', securableModule);
-
-var uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-
-var httpd = null;
-var persisted = {};
-
-var assert = new assertions.Assert();
-var expect = new assertions.Expect();
-
-var mozmill = undefined;
-var mozelement = undefined;
-var modules = undefined;
-
-var timers = [];
-
-
-/**
- * Shutdown or restart the application
- *
- * @param {boolean} [aFlags=undefined]
- *        Additional flags how to handle the shutdown or restart.
- * @see https://developer.mozilla.org/nsIAppStartup#Attributes
- */
-function shutdownApplication(aFlags) {
-  var flags = Ci.nsIAppStartup.eForceQuit;
-
-  if (aFlags) {
-    flags |= aFlags;
-  }
-
-  // Send a request to shutdown the application. That will allow us and other
-  // components to finish up with any shutdown code. Please note that we don't
-  // care if other components or add-ons want to prevent this via cancelQuit,
-  // we really force the shutdown.
-  let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
-                   createInstance(Components.interfaces.nsISupportsPRBool);
-  Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
-
-  // Use a timer to trigger the application restart, which will allow us to
-  // send an ACK packet via jsbridge if the method has been called via Python.
-  var event = {
-    notify: function(timer) {
-      Services.startup.quit(flags);
-    }
-  }
-
-  var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-  timer.initWithCallback(event, 100, Ci.nsITimer.TYPE_ONE_SHOT);
-}
-
-function stateChangeBase(possibilties, restrictions, target, cmeta, v) {
-  if (possibilties) {
-    if (!arrays.inArray(possibilties, v)) {
-      // TODO Error value not in this.poss
-      return;
-    }
-  }
-
-  if (restrictions) {
-    for (var i in restrictions) {
-      var r = restrictions[i];
-      if (!r(v)) {
-        // TODO error value did not pass restriction
-        return;
-      }
-    }
-  }
-
-  // Fire jsbridge notification, logging notification, listener notifications
-  events[target] = v;
-  events.fireEvent(cmeta, target);
-}
-
-
-var events = {
-  appQuit           : false,
-  currentModule     : null,
-  currentState      : null,
-  currentTest       : null,
-  shutdownRequested : false,
-  userShutdown      : null,
-  userShutdownTimer : null,
-
-  listeners       : {},
-  globalListeners : []
-}
-
-events.setState = function (v) {
-  return stateChangeBase(['dependencies', 'setupModule', 'teardownModule',
-                          'test', 'setupTest', 'teardownTest', 'collection'],
-                          null, 'currentState', 'setState', v);
-}
-
-events.toggleUserShutdown = function (obj){
-  if (!this.userShutdown) {
-    this.userShutdown = obj;
-
-    var event = {
-      notify: function(timer) {
-       events.toggleUserShutdown(obj);
-      }
-    }
-
-    this.userShutdownTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
-    this.userShutdownTimer.initWithCallback(event, obj.timeout, Ci.nsITimer.TYPE_ONE_SHOT);
-
-  } else {
-    this.userShutdownTimer.cancel();
-
-    // If the application is not going to shutdown, the user shutdown failed and
-    // we have to force a shutdown.
-    if (!events.appQuit) {
-      this.fail({'function':'events.toggleUserShutdown',
-                 'message':'Shutdown expected but none detected before timeout',
-                 'userShutdown': obj});
-
-      var flags = Ci.nsIAppStartup.eAttemptQuit;
-      if (events.isRestartShutdown()) {
-        flags |= Ci.nsIAppStartup.eRestart;
-      }
-
-      shutdownApplication(flags);
-    }
-  }
-}
-
-events.isUserShutdown = function () {
-  return this.userShutdown ? this.userShutdown["user"] : false;
-}
-
-events.isRestartShutdown = function () {
-  return this.userShutdown.restart;
-}
-
-events.startShutdown = function (obj) {
-  events.fireEvent('shutdown', obj);
-
-  if (obj["user"]) {
-    events.toggleUserShutdown(obj);
-  } else {
-    shutdownApplication(obj.flags);
-  }
-}
-
-events.setTest = function (test) {
-  test.__start__ = Date.now();
-  test.__passes__ = [];
-  test.__fails__ = [];
-
-  events.currentTest = test;
-
-  var obj = {'filename': events.currentModule.__file__,
-             'name': test.__name__}
-  events.fireEvent('setTest', obj);
-}
-
-events.endTest = function (test) {
-  // use the current test unless specified
-  if (test === undefined) {
-    test = events.currentTest;
-  }
-
-  // If no test is set it has already been reported. Beside that we don't want
-  // to report it a second time.
-  if (!test || test.status === 'done')
-    return;
-
-  // report the end of a test
-  test.__end__ = Date.now();
-  test.status = 'done';
-
-  var obj = {'filename': events.currentModule.__file__,
-             'passed': test.__passes__.length,
-             'failed': test.__fails__.length,
-             'passes': test.__passes__,
-             'fails' : test.__fails__,
-             'name'  : test.__name__,
-             'time_start': test.__start__,
-             'time_end': test.__end__}
-
-  if (test.skipped) {
-    obj['skipped'] = true;
-    obj.skipped_reason = test.skipped_reason;
-  }
-
-  if (test.meta) {
-    obj.meta = test.meta;
-  }
-
-  // Report the test result only if the test is a true test or if it is failing
-  if (withs.startsWith(test.__name__, "test") || test.__fails__.length > 0) {
-    events.fireEvent('endTest', obj);
-  }
-}
-
-events.setModule = function (aModule) {
-  aModule.__start__ = Date.now();
-  aModule.__status__ = 'running';
-
-  var result = stateChangeBase(null,
-                               [function (aModule) {return (aModule.__file__ != undefined)}],
-                               'currentModule', 'setModule', aModule);
-
-  return result;
-}
-
-events.endModule = function (aModule) {
-  // It should only reported once, so check if it already has been done
-  if (aModule.__status__ === 'done')
-    return;
-
-  aModule.__end__ = Date.now();
-  aModule.__status__ = 'done';
-
-  var obj = {
-    'filename': aModule.__file__,
-    'time_start': aModule.__start__,
-    'time_end': aModule.__end__
-  }
-
-  events.fireEvent('endModule', obj);
-}
-
-events.pass = function (obj) {
-  // a low level event, such as a keystroke, succeeds
-  if (events.currentTest) {
-    events.currentTest.__passes__.push(obj);
-  }
-
-  for (var timer of timers) {
-    timer.actions.push(
-      {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
-       "obj": obj,
-       "result": "pass"}
-    );
-  }
-
-  events.fireEvent('pass', obj);
-}
-
-events.fail = function (obj) {
-  var error = obj.exception;
-
-  if (error) {
-    // Error objects aren't enumerable https://bugzilla.mozilla.org/show_bug.cgi?id=637207
-    obj.exception = {
-      name: error.name,
-      message: error.message,
-      lineNumber: error.lineNumber,
-      fileName: error.fileName,
-      stack: error.stack
-    };
-  }
-
-  // a low level event, such as a keystroke, fails
-  if (events.currentTest) {
-    events.currentTest.__fails__.push(obj);
-  }
-
-  for (var timer of timers) {
-    timer.actions.push(
-      {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
-       "obj": obj,
-       "result": "fail"}
-    );
-  }
-
-  events.fireEvent('fail', obj);
-}
-
-events.skip = function (reason) {
-  // this is used to report skips associated with setupModule and nothing else
-  events.currentTest.skipped = true;
-  events.currentTest.skipped_reason = reason;
-
-  for (var timer of timers) {
-    timer.actions.push(
-      {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__,
-       "obj": reason,
-       "result": "skip"}
-    );
-  }
-
-  events.fireEvent('skip', reason);
-}
-
-events.fireEvent = function (name, obj) {
-  if (events.appQuit) {
-    // dump('* Event discarded: ' + name + ' ' + JSON.stringify(obj) + '\n');
-    return;
-  }
-
-  if (this.listeners[name]) {
-    for (var i in this.listeners[name]) {
-      this.listeners[name][i](obj);
-    }
-  }
-
-  for (var listener of this.globalListeners) {
-    listener(name, obj);
-  }
-}
-
-events.addListener = function (name, listener) {
-  if (this.listeners[name]) {
-    this.listeners[name].push(listener);
-  } else if (name == '') {
-    this.globalListeners.push(listener)
-  } else {
-    this.listeners[name] = [listener];
-  }
-}
-
-events.removeListener = function (listener) {
-  for (var listenerIndex in this.listeners) {
-    var e = this.listeners[listenerIndex];
-
-    for (var i in e){
-      if (e[i] == listener) {
-        this.listeners[listenerIndex] = arrays.remove(e, i);
-      }
-    }
-  }
-
-  for (var i in this.globalListeners) {
-    if (this.globalListeners[i] == listener) {
-      this.globalListeners = arrays.remove(this.globalListeners, i);
-    }
-  }
-}
-
-events.persist = function () {
-  try {
-    events.fireEvent('persist', persisted);
-  } catch (e) {
-    events.fireEvent('error', "persist serialization failed.")
-  }
-}
-
-events.firePythonCallback = function (obj) {
-  obj['test'] = events.currentModule.__file__;
-  events.fireEvent('firePythonCallback', obj);
-}
-
-events.screenshot = function (obj) {
-  // Find the name of the test function
-  for (var attr in events.currentModule) {
-    if (events.currentModule[attr] == events.currentTest) {
-      var testName = attr;
-      break;
-    }
-  }
-
-  obj['test_file'] = events.currentModule.__file__;
-  obj['test_name'] = testName;
-  events.fireEvent('screenshot', obj);
-}
-
-var log = function (obj) {
-  events.fireEvent('log', obj);
-}
-
-// Register the listeners
-broker.addObject({'endTest': events.endTest,
-                  'fail': events.fail,
-                  'firePythonCallback': events.firePythonCallback,
-                  'log': log,
-                  'pass': events.pass,
-                  'persist': events.persist,
-                  'screenshot': events.screenshot,
-                  'shutdown': events.startShutdown,
-                 });
-
-try {
-  Cu.import('resource://jsbridge/modules/Events.jsm');
-
-  events.addListener('', function (name, obj) {
-    Events.fireEvent('mozmill.' + name, obj);
-  });
-} catch (e) {
-  Services.console.logStringMessage("Event module of JSBridge not available.");
-}
-
-
-/**
- * Observer for notifications when the application is going to shutdown
- */
-function AppQuitObserver() {
-  this.runner = null;
-
-  Services.obs.addObserver(this, "quit-application-requested");
-}
-
-AppQuitObserver.prototype = {
-  observe: function (aSubject, aTopic, aData) {
-    switch (aTopic) {
-      case "quit-application-requested":
-        Services.obs.removeObserver(this, "quit-application-requested");
-
-        // If we observe a quit notification make sure to send the
-        // results of the current test. In those cases we don't reach
-        // the equivalent code in runTestModule()
-        events.pass({'message': 'AppQuitObserver: ' + JSON.stringify(aData),
-                     'userShutdown': events.userShutdown});
-
-        if (this.runner) {
-          this.runner.end();
-        }
-
-        if (httpd) {
-          httpd.stop();
-        }
-
-        events.appQuit = true;
-
-        break;
-    }
-  }
-}
-
-var appQuitObserver = new AppQuitObserver();
-
-/**
- * The collector handles HTTPd.js and initilizing the module
- */
-function Collector() {
-  this.test_modules_by_filename = {};
-  this.testing = [];
-}
-
-Collector.prototype.addHttpResource = function (aDirectory, aPath) {
-  var fp = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-  fp.initWithPath(os.abspath(aDirectory, this.current_file));
-
-  return httpd.addHttpResource(fp, aPath);
-}
-
-Collector.prototype.initTestModule = function (filename, testname) {
-  var test_module = this.loadFile(filename, this);
-  var has_restarted = !(testname == null);
-  test_module.__tests__ = [];
-
-  for (var i in test_module) {
-    if (typeof(test_module[i]) == "function") {
-      test_module[i].__name__ = i;
-
-      // Only run setupModule if we are a single test OR if we are the first
-      // test of a restart chain (don't run it prior to members in a restart
-      // chain)
-      if (i == "setupModule" && !has_restarted) {
-        test_module.__setupModule__ = test_module[i];
-      } else if (i == "setupTest") {
-        test_module.__setupTest__ = test_module[i];
-      } else if (i == "teardownTest") {
-        test_module.__teardownTest__ = test_module[i];
-      } else if (i == "teardownModule") {
-        test_module.__teardownModule__ = test_module[i];
-      } else if (withs.startsWith(i, "test")) {
-        if (testname && (i != testname)) {
-          continue;
-        }
-
-        testname = null;
-        test_module.__tests__.push(test_module[i]);
-      }
-    }
-  }
-
-  test_module.collector = this;
-  test_module.status = 'loaded';
-
-  this.test_modules_by_filename[filename] = test_module;
-
-  return test_module;
-}
-
-Collector.prototype.loadFile = function (path, collector) {
-  var moduleLoader = new securableModule.Loader({
-    rootPaths: ["resource://mozmill/modules/"],
-    defaultPrincipal: "system",
-    globals : { Cc: Cc,
-                Ci: Ci,
-                Cu: Cu,
-                Cr: Components.results}
-  });
-
-  // load a test module from a file and add some candy
-  var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
-  file.initWithPath(path);
-  var uri = Services.io.newFileURI(file).spec;
-
-  this.loadTestResources();
-
-  var systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
-  var module = new Components.utils.Sandbox(systemPrincipal);
-  module.assert = assert;
-  module.Cc = Cc;
-  module.Ci = Ci;
-  module.Cr = Components.results;
-  module.Cu = Cu;
-  module.collector = collector;
-  module.driver = moduleLoader.require("driver");
-  module.elementslib = mozelement;
-  module.errors = errors;
-  module.expect = expect;
-  module.findElement = mozelement;
-  module.log = log;
-  module.mozmill = mozmill;
-  module.persisted = persisted;
-
-  module.require = function (mod) {
-    var loader = new securableModule.Loader({
-      rootPaths: [Services.io.newFileURI(file.parent).spec,
-                  "resource://mozmill/modules/"],
-      defaultPrincipal: "system",
-      globals : { assert: assert,
-                  expect: expect,
-                  mozmill: mozmill,
-                  elementslib: mozelement,      // This a quick hack to maintain backwards compatibility with 1.5.x
-                  findElement: mozelement,
-                  persisted: persisted,
-                  Cc: Cc,
-                  Ci: Ci,
-                  Cu: Cu,
-                  log: log }
-    });
-
-    if (modules != undefined) {
-      loader.modules = modules;
-    }
-
-    var retval = loader.require(mod);
-    modules = loader.modules;
-
-    return retval;
-  }
-
-  if (collector != undefined) {
-    collector.current_file = file;
-    collector.current_path = path;
-  }
-
-  try {
-    Services.scriptloader.loadSubScript(uri, module, "UTF-8");
-  } catch (e) {
-    var obj = {
-      'filename': path,
-      'passed': 0,
-      'failed': 1,
-      'passes': [],
-      'fails' : [{'exception' : {
-                    message: e.message,
-                    filename: e.filename,
-                    lineNumber: e.lineNumber}}],
-      'name'  :'<TOP_LEVEL>'
-    };
-
-    events.fail({'exception': e});
-    events.fireEvent('endTest', obj);
-  }
-
-  module.__file__ = path;
-  module.__uri__ = uri;
-
-  return module;
-}
-
-Collector.prototype.loadTestResources = function () {
-  // load resources we want in our tests
-  if (mozmill === undefined) {
-    mozmill = {};
-    Cu.import("resource://mozmill/driver/mozmill.js", mozmill);
-  }
-  if (mozelement === undefined) {
-    mozelement = {};
-    Cu.import("resource://mozmill/driver/mozelement.js", mozelement);
-  }
-}
-
-
-/**
- *
- */
-function Httpd(aPort) {
-  this.http_port = aPort;
-
-  while (true) {
-    try {
-      var srv = new HttpServer();
-      srv.registerContentType("sjs", "sjs");
-      srv.identity.setPrimary("http", "localhost", this.http_port);
-      srv.start(this.http_port);
-
-      this._httpd = srv;
-      break;
-    }
-    catch (e) {
-      // Failure most likely due to port conflict
-      this.http_port++;
-    }
-  }
-}
-
-Httpd.prototype.addHttpResource = function (aDir, aPath) {
-  var path = aPath ? ("/" + aPath + "/") : "/";
-
-  try {
-    this._httpd.registerDirectory(path, aDir);
-    return 'http://localhost:' + this.http_port + path;
-  }
-  catch (e) {
-    throw Error("Failure to register directory: " + aDir.path);
-  }
-};
-
-Httpd.prototype.stop = function () {
-  if (!this._httpd) {
-    return;
-  }
-
-  var shutdown = false;
-  this._httpd.stop(function () { shutdown = true; });
-
-  assert.waitFor(function () {
-    return shutdown;
-  }, "Local HTTP server has been stopped", TIMEOUT_SHUTDOWN_HTTPD);
-
-  this._httpd = null;
-};
-
-function startHTTPd() {
-  if (!httpd) {
-    // Ensure that we start the HTTP server only once during a session
-    httpd = new Httpd(43336);
-  }
-}
-
-
-function Runner() {
-  this.collector = new Collector();
-  this.ended = false;
-
-  var m = {}; Cu.import('resource://mozmill/driver/mozmill.js', m);
-  this.platform = m.platform;
-
-  events.fireEvent('startRunner', true);
-}
-
-Runner.prototype.end = function () {
-  if (!this.ended) {
-    this.ended = true;
-
-    appQuitObserver.runner = null;
-
-    events.endTest();
-    events.endModule(events.currentModule);
-    events.fireEvent('endRunner', true);
-    events.persist();
-  }
-};
-
-Runner.prototype.runTestFile = function (filename, name) {
-  var module = this.collector.initTestModule(filename, name);
-  this.runTestModule(module);
-};
-
-Runner.prototype.runTestModule = function (module) {
-  appQuitObserver.runner = this;
-  events.setModule(module);
-
-  // If setupModule passes, run all the tests. Otherwise mark them as skipped.
-  if (this.execFunction(module.__setupModule__, module)) {
-    for (var test of module.__tests__) {
-      if (events.shutdownRequested) {
-        break;
-      }
-
-      // If setupTest passes, run the test. Otherwise mark it as skipped.
-      if (this.execFunction(module.__setupTest__, module)) {
-        this.execFunction(test);
-      } else {
-        this.skipFunction(test, module.__setupTest__.__name__ + " failed");
-      }
-
-      this.execFunction(module.__teardownTest__, module);
-    }
-
-  } else {
-    for (var test of module.__tests__) {
-      this.skipFunction(test, module.__setupModule__.__name__ + " failed");
-    }
-  }
-
-  this.execFunction(module.__teardownModule__, module);
-  events.endModule(module);
-};
-
-Runner.prototype.execFunction = function (func, arg) {
-  if (typeof func !== "function" || events.shutdownRequested) {
-    return true;
-  }
-
-  var isTest = withs.startsWith(func.__name__, "test");
-
-  events.setState(isTest ? "test" : func.__name);
-  events.setTest(func);
-
-  // skip excluded platforms
-  if (func.EXCLUDED_PLATFORMS != undefined) {
-    if (arrays.inArray(func.EXCLUDED_PLATFORMS, this.platform)) {
-      events.skip("Platform exclusion");
-      events.endTest(func);
-      return false;
-    }
-  }
-
-  // skip function if requested
-  if (func.__force_skip__ != undefined) {
-    events.skip(func.__force_skip__);
-    events.endTest(func);
-    return false;
-  }
-
-  // execute the test function
-  try {
-    func(arg);
-  } catch (e) {
-    if (e instanceof errors.ApplicationQuitError) {
-      events.shutdownRequested = true;
-    } else {
-      events.fail({'exception': e, 'test': func})
-    }
-  }
-
-  // If a user shutdown has been requested and the function already returned,
-  // we can assume that a shutdown will not happen anymore. We should force a
-  // shutdown then, to prevent the next test from being executed.
-  if (events.isUserShutdown()) {
-    events.shutdownRequested = true;
-    events.toggleUserShutdown(events.userShutdown);
-  }
-
-  events.endTest(func);
-  return events.currentTest.__fails__.length == 0;
-};
-
-function runTestFile(filename, name) {
-  var runner = new Runner();
-  runner.runTestFile(filename, name);
-  runner.end();
-
-  return true;
-}
-
-Runner.prototype.skipFunction = function (func, message) {
-  events.setTest(func);
-  events.skip(message);
-  events.endTest(func);
-};
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/l10n.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * @namespace Defines useful methods to work with localized content
- */
-var l10n = exports;
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-/**
- * Retrieve the localized content for a given DTD entity
- *
- * @memberOf l10n
- * @param {String[]} aDTDs Array of URLs for DTD files.
- * @param {String} aEntityId ID of the entity to get the localized content of.
- *
- * @returns {String} Localized content
- */
-function getEntity(aDTDs, aEntityId) {
-  // Add xhtml11.dtd to prevent missing entity errors with XHTML files
-  aDTDs.push("resource:///res/dtd/xhtml11.dtd");
-
-  // Build a string of external entities
-  var references = "";
-  for (let i = 0; i < aDTDs.length; i++) {
-    var id = 'dtd' + i;
-    references += '<!ENTITY % ' + id + ' SYSTEM "' + aDTDs[i] + '">%' + id + ';';
-  }
-
-  var header = '<?xml version="1.0"?><!DOCTYPE elem [' + references + ']>';
-  var element = '<elem id="entity">&' + aEntityId + ';</elem>';
-  var content = header + element;
-
-  var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
-               createInstance(Ci.nsIDOMParser);
-  var doc = parser.parseFromString(content, 'text/xml');
-  var node = doc.querySelector('elem[id="entity"]');
-
-  if (!node) {
-    throw new Error("Unkown entity '" + aEntityId + "'");
-  }
-
-  return node.textContent;
-}
-
-
-/**
- * Retrieve the localized content for a given property
- *
- * @memberOf l10n
- * @param {String} aURL URL of the .properties file.
- * @param {String} aProperty The property to get the value of.
- *
- * @returns {String} Value of the requested property
- */
-function getProperty(aURL, aProperty) {
-  var bundle = Services.strings.createBundle(aURL);
-
-  try {
-    return bundle.GetStringFromName(aProperty);
-  } catch (ex) {
-    throw new Error("Unkown property '" + aProperty + "'");
-  }
-}
-
-
-// Export of functions
-l10n.getEntity = getEntity;
-l10n.getProperty = getProperty;
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/stack.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['findCallerFrame'];
-
-
-/**
- * @namespace Defines utility methods for handling stack frames
- */
-
-/**
- * Find the frame to use for logging the test result. If a start frame has
- * been specified, we walk down the stack until a frame with the same filename
- * as the start frame has been found. The next file in the stack will be the
- * frame to use for logging the result.
- *
- * @memberOf stack
- * @param {Object} [aStartFrame=Components.stack] Frame to start from walking up the stack.
- * @returns {Object} Frame of the stack to use for logging the result.
- */
-function findCallerFrame(aStartFrame) {
-  let frame = Components.stack;
-  let filename = frame.filename.replace(/(.*)-> /, "");
-
-  // If a start frame has been specified, walk up the stack until we have
-  // found the corresponding file
-  if (aStartFrame) {
-    filename = aStartFrame.filename.replace(/(.*)-> /, "");
-
-    while (frame.caller &&
-           frame.filename && (frame.filename.indexOf(filename) == -1)) {
-      frame = frame.caller;
-    }
-  }
-
-  // Walk even up more until the next file has been found
-  while (frame.caller &&
-         (!frame.filename || (frame.filename.indexOf(filename) != -1)))
-    frame = frame.caller;
-
-  return frame;
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/modules/windows.js
+++ /dev/null
@@ -1,292 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ["init", "map"];
-
-var Cc = Components.classes;
-var Ci = Components.interfaces;
-var Cu = Components.utils;
-
-// imports
-var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils);
-
-var uuidgen = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-
-/**
- * The window map is used to store information about the current state of
- * open windows, e.g. loaded state
- */
-var map = {
-  _windows : { },
-
-  /**
-   * Check if a given window id is contained in the map of windows
-   *
-   * @param {Number} aWindowId
-   *        Outer ID of the window to check.
-   * @returns {Boolean} True if the window is part of the map, otherwise false.
-   */
-  contains : function (aWindowId) {
-    return (aWindowId in this._windows);
-  },
-
-  /**
-   * Retrieve the value of the specified window's property.
-   *
-   * @param {Number} aWindowId
-   *        Outer ID of the window to check.
-   * @param {String} aProperty
-   *        Property to retrieve the value from
-   * @return {Object} Value of the window's property
-   */
-  getValue : function (aWindowId, aProperty) {
-    if (!this.contains(aWindowId)) {
-      return undefined;
-    } else {
-      var win = this._windows[aWindowId];
-
-      return (aProperty in win) ? win[aProperty]
-                                : undefined;
-    }
-  },
-
-  /**
-   * Remove the entry for a given window
-   *
-   * @param {Number} aWindowId
-   *        Outer ID of the window to check.
-   */
-  remove : function (aWindowId) {
-    if (this.contains(aWindowId)) {
-      delete this._windows[aWindowId];
-    }
-
-    // dump("* current map: " + JSON.stringify(this._windows) + "\n");
-  },
-
-  /**
-   * Update the property value of a given window
-   *
-   * @param {Number} aWindowId
-   *        Outer ID of the window to check.
-   * @param {String} aProperty
-   *        Property to update the value for
-   * @param {Object}
-   *        Value to set
-   */
-  update : function (aWindowId, aProperty, aValue) {
-    if (!this.contains(aWindowId)) {
-      this._windows[aWindowId] = { };
-    }
-
-    this._windows[aWindowId][aProperty] = aValue;
-    // dump("* current map: " + JSON.stringify(this._windows) + "\n");
-  },
-
-  /**
-   * Update the internal loaded state of the given content window. To identify
-   * an active (re)load action we make use of an uuid.
-   *
-   * @param {Window} aId - The outer id of the window to update
-   * @param {Boolean} aIsLoaded - Has the window been loaded
-   */
-  updatePageLoadStatus : function (aId, aIsLoaded) {
-    this.update(aId, "loaded", aIsLoaded);
-
-    var uuid = this.getValue(aId, "id_load_in_transition");
-
-    // If no uuid has been set yet or when the page gets unloaded create a new id
-    if (!uuid || !aIsLoaded) {
-      uuid = uuidgen.generateUUID();
-      this.update(aId, "id_load_in_transition", uuid);
-    }
-
-    // dump("*** Page status updated: id=" + aId + ", loaded=" + aIsLoaded + ", uuid=" + uuid + "\n");
-  },
-
-  /**
-   * This method only applies to content windows, where we have to check if it has
-   * been successfully loaded or reloaded. An uuid allows us to wait for the next
-   * load action triggered by e.g. controller.open().
-   *
-   * @param {Window} aId - The outer id of the content window to check
-   *
-   * @returns {Boolean} True if the content window has been loaded
-   */
-  hasPageLoaded : function (aId) {
-    var load_current = this.getValue(aId, "id_load_in_transition");
-    var load_handled = this.getValue(aId, "id_load_handled");
-
-    var isLoaded = this.contains(aId) && this.getValue(aId, "loaded") &&
-                   (load_current !== load_handled);
-
-    if (isLoaded) {
-      // Backup the current uuid so we can check later if another page load happened.
-      this.update(aId, "id_load_handled", load_current);
-    }
-
-    // dump("** Page has been finished loading: id=" + aId + ", status=" + isLoaded + ", uuid=" + load_current + "\n");
-
-    return isLoaded;
-  }
-};
-
-
-// Observer when a new top-level window is ready
-var windowReadyObserver = {
-  observe: function (aSubject, aTopic, aData) {
-    // Not in all cases we get a ChromeWindow. So ensure we really operate
-    // on such an instance. Otherwise load events will not be handled.
-    var win = utils.getChromeWindow(aSubject);
-
-    // var id = utils.getWindowId(win);
-    // dump("*** 'toplevel-window-ready' observer notification: id=" + id + "\n");
-    attachEventListeners(win);
-  }
-};
-
-
-// Observer when a top-level window is closed
-var windowCloseObserver = {
-  observe: function (aSubject, aTopic, aData) {
-    var id = utils.getWindowId(aSubject);
-    // dump("*** 'outer-window-destroyed' observer notification: id=" + id + "\n");
-
-    map.remove(id);
-  }
-};
-
-// Bug 915554
-// Support for the old Private Browsing Mode (eg. ESR17)
-// TODO: remove once ESR17 is no longer supported
-var enterLeavePrivateBrowsingObserver = {
-  observe: function (aSubject, aTopic, aData) {
-    handleAttachEventListeners();
-  }
-};
-
-/**
- * Attach event listeners
- *
- * @param {ChromeWindow} aWindow
- *        Window to attach listeners on.
- */
-function attachEventListeners(aWindow) {
-  // These are the event handlers
-  var pageShowHandler = function (aEvent) {
-    var doc = aEvent.originalTarget;
-
-    // Only update the flag if we have a document as target
-    // see https://bugzilla.mozilla.org/show_bug.cgi?id=690829
-    if ("defaultView" in doc) {
-      var id = utils.getWindowId(doc.defaultView);
-      // dump("*** 'pageshow' event: id=" + id + ", baseURI=" + doc.baseURI + "\n");
-      map.updatePageLoadStatus(id, true);
-    }
-
-    // We need to add/remove the unload/pagehide event listeners to preserve caching.
-    aWindow.addEventListener("beforeunload", beforeUnloadHandler, true);
-    aWindow.addEventListener("pagehide", pageHideHandler, true);
-  };
-
-  var DOMContentLoadedHandler = function (aEvent) {
-    var doc = aEvent.originalTarget;
-
-    // Only update the flag if we have a document as target
-    if ("defaultView" in doc) {
-      var id = utils.getWindowId(doc.defaultView);
-      // dump("*** 'DOMContentLoaded' event: id=" + id + ", baseURI=" + doc.baseURI + "\n");
-
-      // We only care about error pages for DOMContentLoaded
-      var errorRegex = /about:.+(error)|(blocked)\?/;
-      if (errorRegex.exec(doc.baseURI)) {
-        // Wait about 1s to be sure the DOM is ready
-        utils.sleep(1000);
-
-        map.updatePageLoadStatus(id, true);
-      }
-
-      // We need to add/remove the unload event listener to preserve caching.
-      aWindow.addEventListener("beforeunload", beforeUnloadHandler, true);
-    }
-  };
-
-  // beforeunload is still needed because pagehide doesn't fire before the page is unloaded.
-  // still use pagehide for cases when beforeunload doesn't get fired
-  var beforeUnloadHandler = function (aEvent) {
-    var doc = aEvent.originalTarget;
-
-    // Only update the flag if we have a document as target
-    if ("defaultView" in doc) {
-      var id = utils.getWindowId(doc.defaultView);
-      // dump("*** 'beforeunload' event: id=" + id + ", baseURI=" + doc.baseURI + "\n");
-      map.updatePageLoadStatus(id, false);
-    }
-
-    aWindow.removeEventListener("beforeunload", beforeUnloadHandler, true);
-  };
-
-  var pageHideHandler = function (aEvent) {
-    var doc = aEvent.originalTarget;
-
-    // Only update the flag if we have a document as target
-    if ("defaultView" in doc) {
-      var id = utils.getWindowId(doc.defaultView);
-      // dump("*** 'pagehide' event: id=" + id + ", baseURI=" + doc.baseURI + "\n");
-      map.updatePageLoadStatus(id, false);
-    }
-    // If event.persisted is true the beforeUnloadHandler would never fire
-    // and we have to remove the event handler here to avoid memory leaks.
-    if (aEvent.persisted)
-      aWindow.removeEventListener("beforeunload", beforeUnloadHandler, true);
-  };
-
-  var onWindowLoaded = function (aEvent) {
-    var id = utils.getWindowId(aWindow);
-    // dump("*** 'load' event: id=" + id + ", baseURI=" + aWindow.document.baseURI + "\n");
-
-    map.update(id, "loaded", true);
-
-    // Note: Error pages will never fire a "pageshow" event. For those we
-    // have to wait for the "DOMContentLoaded" event. That's the final state.
-    // Error pages will always have a baseURI starting with
-    // "about:" followed by "error" or "blocked".
-    aWindow.addEventListener("DOMContentLoaded", DOMContentLoadedHandler, true);
-
-    // Page is ready
-    aWindow.addEventListener("pageshow", pageShowHandler, true);
-
-    // Leave page (use caching)
-    aWindow.addEventListener("pagehide", pageHideHandler, true);
-  };
-
-  // If the window has already been finished loading, call the load handler
-  // directly. Otherwise attach it to the current window.
-  if (aWindow.document.readyState === 'complete') {
-    onWindowLoaded();
-  } else {
-    aWindow.addEventListener("load", onWindowLoaded);
-  }
-}
-
-// Attach event listeners to all already open top-level windows
-function handleAttachEventListeners() {
-  var enumerator = Cc["@mozilla.org/appshell/window-mediator;1"].
-                   getService(Ci.nsIWindowMediator).getEnumerator("");
-  while (enumerator.hasMoreElements()) {
-    var win = enumerator.getNext();
-    attachEventListeners(win);
-  }
-}
-
-function init() {
-  // Activate observer for new top level windows
-  var observerService = Cc["@mozilla.org/observer-service;1"].
-                        getService(Ci.nsIObserverService);
-  observerService.addObserver(windowReadyObserver, "toplevel-window-ready");
-  observerService.addObserver(windowCloseObserver, "outer-window-destroyed");
-  observerService.addObserver(enterLeavePrivateBrowsingObserver, "private-browsing");
-
-  handleAttachEventListeners();
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js
+++ /dev/null
@@ -1,823 +0,0 @@
-// Export all available functions for Mozmill
-var EXPORTED_SYMBOLS = ["disableNonTestMouseEvents","sendMouseEvent", "sendChar",
-                        "sendString", "sendKey", "synthesizeMouse", "synthesizeTouch",
-                        "synthesizeMouseAtPoint", "synthesizeTouchAtPoint",
-                        "synthesizeMouseAtCenter", "synthesizeTouchAtCenter",
-                        "synthesizeWheel", "synthesizeKey",
-                        "synthesizeMouseExpectEvent", "synthesizeKeyExpectEvent",
-                        "synthesizeText",
-                        "synthesizeComposition", "synthesizeQuerySelectedText"];
-
-var Ci = Components.interfaces;
-var Cc = Components.classes;
-
-var window = Cc["@mozilla.org/appshell/appShellService;1"]
-             .getService(Ci.nsIAppShellService).hiddenDOMWindow;
-
-var _EU_Ci = Ci;
-var navigator = window.navigator;
-var KeyEvent = window.KeyEvent;
-var parent = window.parent;
-
-function is(aExpression1, aExpression2, aMessage) {
-  if (aExpression1 !== aExpression2) {
-    throw new Error(aMessage);
-  }
-}
-
-/**
- * EventUtils provides some utility methods for creating and sending DOM events.
- * Current methods:
- *  sendMouseEvent
- *  sendChar
- *  sendString
- *  sendKey
- *  synthesizeMouse
- *  synthesizeMouseAtCenter
- *  synthesizeWheel
- *  synthesizeKey
- *  synthesizeMouseExpectEvent
- *  synthesizeKeyExpectEvent
- *
- *  When adding methods to this file, please add a performance test for it.
- */
-
-/**
- * Send a mouse event to the node aTarget (aTarget can be an id, or an
- * actual node) . The "event" passed in to aEvent is just a JavaScript
- * object with the properties set that the real mouse event object should
- * have. This includes the type of the mouse event.
- * E.g. to send an click event to the node with id 'node' you might do this:
- *
- * sendMouseEvent({type:'click'}, 'node');
- */
-function getElement(id) {
-  return ((typeof(id) == "string") ?
-    document.getElementById(id) : id); 
-};   
-
-this.$ = this.getElement;
-
-function sendMouseEvent(aEvent, aTarget, aWindow) {
-  if (['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
-    throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'");
-  }
-
-  if (!aWindow) {
-    aWindow = window;
-  }
-
-  if (!(aTarget instanceof aWindow.Element)) {
-    aTarget = aWindow.document.getElementById(aTarget);
-  }
-
-  var event = aWindow.document.createEvent('MouseEvent');
-
-  var typeArg          = aEvent.type;
-  var canBubbleArg     = true;
-  var cancelableArg    = true;
-  var viewArg          = aWindow;
-  var detailArg        = aEvent.detail        || (aEvent.type == 'click'     ||
-                                                  aEvent.type == 'mousedown' ||
-                                                  aEvent.type == 'mouseup' ? 1 :
-                                                  aEvent.type == 'dblclick'? 2 : 0);
-  var screenXArg       = aEvent.screenX       || 0;
-  var screenYArg       = aEvent.screenY       || 0;
-  var clientXArg       = aEvent.clientX       || 0;
-  var clientYArg       = aEvent.clientY       || 0;
-  var ctrlKeyArg       = aEvent.ctrlKey       || false;
-  var altKeyArg        = aEvent.altKey        || false;
-  var shiftKeyArg      = aEvent.shiftKey      || false;
-  var metaKeyArg       = aEvent.metaKey       || false;
-  var buttonArg        = aEvent.button        || 0;
-  var relatedTargetArg = aEvent.relatedTarget || null;
-
-  event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,
-                       screenXArg, screenYArg, clientXArg, clientYArg,
-                       ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
-                       buttonArg, relatedTargetArg);
-
-  SpecialPowers.dispatchEvent(aWindow, aTarget, event);
-}
-
-/**
- * Send the char aChar to the focused element.  This method handles casing of
- * chars (sends the right charcode, and sends a shift key for uppercase chars).
- * No other modifiers are handled at this point.
- *
- * For now this method only works for ASCII characters and emulates the shift
- * key state on US keyboard layout.
- */
-function sendChar(aChar, aWindow) {
-  var hasShift;
-  // Emulate US keyboard layout for the shiftKey state.
-  switch (aChar) {
-    case "!":
-    case "@":
-    case "#":
-    case "$":
-    case "%":
-    case "^":
-    case "&":
-    case "*":
-    case "(":
-    case ")":
-    case "_":
-    case "+":
-    case "{":
-    case "}":
-    case ":":
-    case "\"":
-    case "|":
-    case "<":
-    case ">":
-    case "?":
-      hasShift = true;
-      break;
-    default:
-      hasShift = (aChar == aChar.toUpperCase());
-      break;
-  }
-  synthesizeKey(aChar, { shiftKey: hasShift }, aWindow);
-}
-
-/**
- * Send the string aStr to the focused element.
- *
- * For now this method only works for ASCII characters and emulates the shift
- * key state on US keyboard layout.
- */
-function sendString(aStr, aWindow) {
-  for (var i = 0; i < aStr.length; ++i) {
-    sendChar(aStr.charAt(i), aWindow);
-  }
-}
-
-/**
- * Send the non-character key aKey to the focused node.
- * The name of the key should be the part that comes after "DOM_VK_" in the
- *   KeyEvent constant name for this key.
- * No modifiers are handled at this point.
- */
-function sendKey(aKey, aWindow) {
-  var keyName = "VK_" + aKey.toUpperCase();
-  synthesizeKey(keyName, { shiftKey: false }, aWindow);
-}
-
-/**
- * Parse the key modifier flags from aEvent. Used to share code between
- * synthesizeMouse and synthesizeKey.
- */
-function _parseModifiers(aEvent)
-{
-  const nsIDOMWindowUtils = _EU_Ci.nsIDOMWindowUtils;
-  var mval = 0;
-  if (aEvent.shiftKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_SHIFT;
-  }
-  if (aEvent.ctrlKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_CONTROL;
-  }
-  if (aEvent.altKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_ALT;
-  }
-  if (aEvent.metaKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_META;
-  }
-  if (aEvent.accelKey) {
-    mval |= (navigator.platform.indexOf("Mac") >= 0) ?
-      nsIDOMWindowUtils.MODIFIER_META : nsIDOMWindowUtils.MODIFIER_CONTROL;
-  }
-  if (aEvent.altGrKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_ALTGRAPH;
-  }
-  if (aEvent.capsLockKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_CAPSLOCK;
-  }
-  if (aEvent.fnKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_FN;
-  }
-  if (aEvent.numLockKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_NUMLOCK;
-  }
-  if (aEvent.scrollLockKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_SCROLLLOCK;
-  }
-  if (aEvent.symbolLockKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_SYMBOLLOCK;
-  }
-  if (aEvent.osKey) {
-    mval |= nsIDOMWindowUtils.MODIFIER_OS;
-  }
-
-  return mval;
-}
-
-/**
- * Synthesize a mouse event on a target. The actual client point is determined
- * by taking the aTarget's client box and offseting it by aOffsetX and
- * aOffsetY. This allows mouse clicks to be simulated by calling this method.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
- *
- * If the type is specified, an mouse event of that type is fired. Otherwise,
- * a mousedown followed by a mouse up is performed.
- *
- * aWindow is optional, and defaults to the current window object.
- *
- * Returns whether the event had preventDefault() called on it.
- */
-function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  return synthesizeMouseAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
-       aEvent, aWindow);
-}
-function synthesizeTouch(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeTouchAtPoint(rect.left + aOffsetX, rect.top + aOffsetY,
-       aEvent, aWindow);
-}
-
-/*
- * Synthesize a mouse event at a particular point in aWindow.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, clickCount, button, type
- *
- * If the type is specified, an mouse event of that type is fired. Otherwise,
- * a mousedown followed by a mouse up is performed.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeMouseAtPoint(left, top, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  var defaultPrevented = false;
-
-  if (utils) {
-    var button = aEvent.button || 0;
-    var clickCount = aEvent.clickCount || 1;
-    var modifiers = _parseModifiers(aEvent);
-    var pressure = ("pressure" in aEvent) ? aEvent.pressure : 0;
-    var inputSource = ("inputSource" in aEvent) ? aEvent.inputSource : 0;
-
-    if (("type" in aEvent) && aEvent.type) {
-      defaultPrevented = utils.sendMouseEvent(aEvent.type, left, top, button, clickCount, modifiers, false, pressure, inputSource);
-    }
-    else {
-      utils.sendMouseEvent("mousedown", left, top, button, clickCount, modifiers, false, pressure, inputSource);
-      utils.sendMouseEvent("mouseup", left, top, button, clickCount, modifiers, false, pressure, inputSource);
-    }
-  }
-
-  return defaultPrevented;
-}
-function synthesizeTouchAtPoint(left, top, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-
-  if (utils) {
-    var id = aEvent.id || 0;
-    var rx = aEvent.rx || 1;
-    var ry = aEvent.rx || 1;
-    var angle = aEvent.angle || 0;
-    var force = aEvent.force || 1;
-    var modifiers = _parseModifiers(aEvent);
-
-    if (("type" in aEvent) && aEvent.type) {
-      utils.sendTouchEvent(aEvent.type, [id], [left], [top], [rx], [ry], [angle], [force], 1, modifiers);
-    }
-    else {
-      utils.sendTouchEvent("touchstart", [id], [left], [top], [rx], [ry], [angle], [force], 1, modifiers);
-      utils.sendTouchEvent("touchend", [id], [left], [top], [rx], [ry], [angle], [force], 1, modifiers);
-    }
-  }
-}
-// Call synthesizeMouse with coordinates at the center of aTarget.
-function synthesizeMouseAtCenter(aTarget, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeMouse(aTarget, rect.width / 2, rect.height / 2, aEvent,
-                  aWindow);
-}
-function synthesizeTouchAtCenter(aTarget, aEvent, aWindow)
-{
-  var rect = aTarget.getBoundingClientRect();
-  synthesizeTouch(aTarget, rect.width / 2, rect.height / 2, aEvent,
-                  aWindow);
-}
-
-/**
- * Synthesize a wheel event on a target. The actual client point is determined
- * by taking the aTarget's client box and offseting it by aOffsetX and
- * aOffsetY.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, deltaX, deltaY, deltaZ,
- *   deltaMode, lineOrPageDeltaX, lineOrPageDeltaY, isMomentum, isPixelOnlyDevice,
- *   isCustomizedByPrefs, expectedOverflowDeltaX, expectedOverflowDeltaY
- *
- * deltaMode must be defined, others are ok even if undefined.
- *
- * expectedOverflowDeltaX and expectedOverflowDeltaY take integer value.  The
- * value is just checked as 0 or positive or negative.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeWheel(aTarget, aOffsetX, aOffsetY, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return;
-  }
-
-  var modifiers = _parseModifiers(aEvent);
-  var options = 0;
-  if (aEvent.isPixelOnlyDevice &&
-      (aEvent.deltaMode == WheelEvent.DOM_DELTA_PIXEL)) {
-    options |= utils.WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE;
-  }
-  if (aEvent.isMomentum) {
-    options |= utils.WHEEL_EVENT_CAUSED_BY_MOMENTUM;
-  }
-  if (aEvent.isCustomizedByPrefs) {
-    options |= utils.WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS;
-  }
-  if (typeof aEvent.expectedOverflowDeltaX !== "undefined") {
-    if (aEvent.expectedOverflowDeltaX === 0) {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO;
-    } else if (aEvent.expectedOverflowDeltaX > 0) {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE;
-    } else {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE;
-    }
-  }
-  if (typeof aEvent.expectedOverflowDeltaY !== "undefined") {
-    if (aEvent.expectedOverflowDeltaY === 0) {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO;
-    } else if (aEvent.expectedOverflowDeltaY > 0) {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE;
-    } else {
-      options |= utils.WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE;
-    }
-  }
-  var isPixelOnlyDevice =
-    aEvent.isPixelOnlyDevice && aEvent.deltaMode == WheelEvent.DOM_DELTA_PIXEL;
-
-  // Avoid the JS warnings "reference to undefined property"
-  if (!aEvent.deltaX) {
-    aEvent.deltaX = 0;
-  }
-  if (!aEvent.deltaY) {
-    aEvent.deltaY = 0;
-  }
-  if (!aEvent.deltaZ) {
-    aEvent.deltaZ = 0;
-  }
-
-  var lineOrPageDeltaX =
-    aEvent.lineOrPageDeltaX != null ? aEvent.lineOrPageDeltaX :
-                  aEvent.deltaX > 0 ? Math.floor(aEvent.deltaX) :
-                                      Math.ceil(aEvent.deltaX);
-  var lineOrPageDeltaY =
-    aEvent.lineOrPageDeltaY != null ? aEvent.lineOrPageDeltaY :
-                  aEvent.deltaY > 0 ? Math.floor(aEvent.deltaY) :
-                                      Math.ceil(aEvent.deltaY);
-
-  var rect = aTarget.getBoundingClientRect();
-  utils.sendWheelEvent(rect.left + aOffsetX, rect.top + aOffsetY,
-                       aEvent.deltaX, aEvent.deltaY, aEvent.deltaZ,
-                       aEvent.deltaMode, modifiers,
-                       lineOrPageDeltaX, lineOrPageDeltaY, options);
-}
-
-function _computeKeyCodeFromChar(aChar)
-{
-  if (aChar.length != 1) {
-    return 0;
-  }
-  const nsIDOMKeyEvent = _EU_Ci.nsIDOMKeyEvent;
-  if (aChar >= 'a' && aChar <= 'z') {
-    return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'a'.charCodeAt(0);
-  }
-  if (aChar >= 'A' && aChar <= 'Z') {
-    return nsIDOMKeyEvent.DOM_VK_A + aChar.charCodeAt(0) - 'A'.charCodeAt(0);
-  }
-  if (aChar >= '0' && aChar <= '9') {
-    return nsIDOMKeyEvent.DOM_VK_0 + aChar.charCodeAt(0) - '0'.charCodeAt(0);
-  }
-  // returns US keyboard layout's keycode
-  switch (aChar) {
-    case '~':
-    case '`':
-      return nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
-    case '!':
-      return nsIDOMKeyEvent.DOM_VK_1;
-    case '@':
-      return nsIDOMKeyEvent.DOM_VK_2;
-    case '#':
-      return nsIDOMKeyEvent.DOM_VK_3;
-    case '$':
-      return nsIDOMKeyEvent.DOM_VK_4;
-    case '%':
-      return nsIDOMKeyEvent.DOM_VK_5;
-    case '^':
-      return nsIDOMKeyEvent.DOM_VK_6;
-    case '&':
-      return nsIDOMKeyEvent.DOM_VK_7;
-    case '*':
-      return nsIDOMKeyEvent.DOM_VK_8;
-    case '(':
-      return nsIDOMKeyEvent.DOM_VK_9;
-    case ')':
-      return nsIDOMKeyEvent.DOM_VK_0;
-    case '-':
-    case '_':
-      return nsIDOMKeyEvent.DOM_VK_SUBTRACT;
-    case '+':
-    case '=':
-      return nsIDOMKeyEvent.DOM_VK_EQUALS;
-    case '{':
-    case '[':
-      return nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
-    case '}':
-    case ']':
-      return nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
-    case '|':
-    case '\\':
-      return nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
-    case ':':
-    case ';':
-      return nsIDOMKeyEvent.DOM_VK_SEMICOLON;
-    case '\'':
-    case '"':
-      return nsIDOMKeyEvent.DOM_VK_QUOTE;
-    case '<':
-    case ',':
-      return nsIDOMKeyEvent.DOM_VK_COMMA;
-    case '>':
-    case '.':
-      return nsIDOMKeyEvent.DOM_VK_PERIOD;
-    case '?':
-    case '/':
-      return nsIDOMKeyEvent.DOM_VK_SLASH;
-    default:
-      return 0;
-  }
-}
-
-/**
- * isKeypressFiredKey() returns TRUE if the given key should cause keypress
- * event when widget handles the native key event.  Otherwise, FALSE.
- *
- * aDOMKeyCode should be one of consts of nsIDOMKeyEvent::DOM_VK_*, or a key
- * name begins with "VK_", or a character.
- */
-function isKeypressFiredKey(aDOMKeyCode)
-{
-  if (typeof(aDOMKeyCode) == "string") {
-    if (aDOMKeyCode.indexOf("VK_") == 0) {
-      aDOMKeyCode = KeyEvent["DOM_" + aDOMKeyCode];
-      if (!aDOMKeyCode) {
-        throw new Error(`Unknown key: ${aDOMKeyCode}`);
-      }
-    } else {
-      // If the key generates a character, it must cause a keypress event.
-      return true;
-    }
-  }
-  switch (aDOMKeyCode) {
-    case KeyEvent.DOM_VK_SHIFT:
-    case KeyEvent.DOM_VK_CONTROL:
-    case KeyEvent.DOM_VK_ALT:
-    case KeyEvent.DOM_VK_CAPS_LOCK:
-    case KeyEvent.DOM_VK_NUM_LOCK:
-    case KeyEvent.DOM_VK_SCROLL_LOCK:
-    case KeyEvent.DOM_VK_META:
-      return false;
-    default:
-      return true;
-  }
-}
-
-/**
- * Synthesize a key event. It is targeted at whatever would be targeted by an
- * actual keypress by the user, typically the focused element.
- *
- * aKey should be either a character or a keycode starting with VK_ such as
- * VK_ENTER.
- *
- * aEvent is an object which may contain the properties:
- *   shiftKey, ctrlKey, altKey, metaKey, accessKey, type, location
- *
- * Sets one of KeyboardEvent.DOM_KEY_LOCATION_* to location.  Otherwise,
- * DOMWindowUtils will choose good location from the keycode.
- *
- * If the type is specified, a key event of that type is fired. Otherwise,
- * a keydown, a keypress and then a keyup event are fired in sequence.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeKey(aKey, aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (utils) {
-    var keyCode = 0, charCode = 0;
-    if (aKey.indexOf("VK_") == 0) {
-      keyCode = KeyEvent["DOM_" + aKey];
-      if (!keyCode) {
-        throw new Error(`Unknown key: ${aKey}`);
-      }
-    } else {
-      charCode = aKey.charCodeAt(0);
-      keyCode = _computeKeyCodeFromChar(aKey.charAt(0));
-    }
-
-    var modifiers = _parseModifiers(aEvent);
-    var flags = 0;
-    if (aEvent.location != undefined) {
-      switch (aEvent.location) {
-        case KeyboardEvent.DOM_KEY_LOCATION_STANDARD:
-          flags |= utils.KEY_FLAG_LOCATION_STANDARD;
-          break;
-        case KeyboardEvent.DOM_KEY_LOCATION_LEFT:
-          flags |= utils.KEY_FLAG_LOCATION_LEFT;
-          break;
-        case KeyboardEvent.DOM_KEY_LOCATION_RIGHT:
-          flags |= utils.KEY_FLAG_LOCATION_RIGHT;
-          break;
-        case KeyboardEvent.DOM_KEY_LOCATION_NUMPAD:
-          flags |= utils.KEY_FLAG_LOCATION_NUMPAD;
-          break;
-      }
-    }
-
-    if (!("type" in aEvent) || !aEvent.type) {
-      // Send keydown + (optional) keypress + keyup events.
-      var keyDownDefaultHappened =
-        utils.sendKeyEvent("keydown", keyCode, 0, modifiers, flags);
-      if (isKeypressFiredKey(keyCode)) {
-        if (!keyDownDefaultHappened) {
-          flags |= utils.KEY_FLAG_PREVENT_DEFAULT;
-        }
-        utils.sendKeyEvent("keypress", keyCode, charCode, modifiers, flags);
-      }
-      utils.sendKeyEvent("keyup", keyCode, 0, modifiers, flags);
-    } else if (aEvent.type == "keypress") {
-      // Send standalone keypress event.
-      utils.sendKeyEvent(aEvent.type, keyCode, charCode, modifiers, flags);
-    } else {
-      // Send other standalone event than keypress.
-      utils.sendKeyEvent(aEvent.type, keyCode, 0, modifiers, flags);
-    }
-  }
-}
-
-var _gSeenEvent = false;
-
-/**
- * Indicate that an event with an original target of aExpectedTarget and
- * a type of aExpectedEvent is expected to be fired, or not expected to
- * be fired.
- */
-function _expectEvent(aExpectedTarget, aExpectedEvent, aTestName)
-{
-  if (!aExpectedTarget || !aExpectedEvent)
-    return null;
-
-  _gSeenEvent = false;
-
-  var type = (aExpectedEvent.charAt(0) == "!") ?
-             aExpectedEvent.substring(1) : aExpectedEvent;
-  var eventHandler = function(event) {
-    var epassed = (!_gSeenEvent && event.originalTarget == aExpectedTarget &&
-                   event.type == type);
-    is(epassed, true, aTestName + " " + type + " event target " + (_gSeenEvent ? "twice" : ""));
-    _gSeenEvent = true;
-  };
-
-  aExpectedTarget.addEventListener(type, eventHandler);
-  return eventHandler;
-}
-
-/**
- * Check if the event was fired or not. The event handler aEventHandler
- * will be removed.
- */
-function _checkExpectedEvent(aExpectedTarget, aExpectedEvent, aEventHandler, aTestName)
-{
-  if (aEventHandler) {
-    var expectEvent = (aExpectedEvent.charAt(0) != "!");
-    var type = expectEvent ? aExpectedEvent : aExpectedEvent.substring(1);
-    aExpectedTarget.removeEventListener(type, aEventHandler);
-    var desc = type + " event";
-    if (!expectEvent)
-      desc += " not";
-    is(_gSeenEvent, expectEvent, aTestName + " " + desc + " fired");
-  }
-
-  _gSeenEvent = false;
-}
-
-/**
- * Similar to synthesizeMouse except that a test is performed to see if an
- * event is fired at the right target as a result.
- *
- * aExpectedTarget - the expected originalTarget of the event.
- * aExpectedEvent - the expected type of the event, such as 'select'.
- * aTestName - the test name when outputing results
- *
- * To test that an event is not fired, use an expected type preceded by an
- * exclamation mark, such as '!select'. This might be used to test that a
- * click on a disabled element doesn't fire certain events for instance.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeMouseExpectEvent(aTarget, aOffsetX, aOffsetY, aEvent,
-                                    aExpectedTarget, aExpectedEvent, aTestName,
-                                    aWindow)
-{
-  var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
-  synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
-  _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
-}
-
-/**
- * Similar to synthesizeKey except that a test is performed to see if an
- * event is fired at the right target as a result.
- *
- * aExpectedTarget - the expected originalTarget of the event.
- * aExpectedEvent - the expected type of the event, such as 'select'.
- * aTestName - the test name when outputing results
- *
- * To test that an event is not fired, use an expected type preceded by an
- * exclamation mark, such as '!select'.
- *
- * aWindow is optional, and defaults to the current window object.
- */
-function synthesizeKeyExpectEvent(key, aEvent, aExpectedTarget, aExpectedEvent,
-                                  aTestName, aWindow)
-{
-  var eventHandler = _expectEvent(aExpectedTarget, aExpectedEvent, aTestName);
-  synthesizeKey(key, aEvent, aWindow);
-  _checkExpectedEvent(aExpectedTarget, aExpectedEvent, eventHandler, aTestName);
-}
-
-function disableNonTestMouseEvents(aDisable)
-{
-  var domutils = _getDOMWindowUtils();
-  domutils.disableNonTestMouseEvents(aDisable);
-}
-
-function _getDOMWindowUtils(aWindow)
-{
-  if (!aWindow) {
-    aWindow = window;
-  }
-
-  // we need parent.SpecialPowers for:
-  //  layout/base/tests/test_reftests_with_caret.html
-  //  chrome: toolkit/content/tests/chrome/test_findbar.xul
-  //  chrome: toolkit/content/tests/chrome/test_popup_anchor.xul
-  if ("SpecialPowers" in window && window.SpecialPowers != undefined) {
-    return SpecialPowers.getDOMWindowUtils(aWindow);
-  }
-  if ("SpecialPowers" in parent && parent.SpecialPowers != undefined) {
-    return parent.SpecialPowers.getDOMWindowUtils(aWindow);
-  }
-
-  //TODO: this is assuming we are in chrome space
-  return aWindow.QueryInterface(_EU_Ci.nsIInterfaceRequestor).
-                               getInterface(_EU_Ci.nsIDOMWindowUtils);
-}
-
-// Must be synchronized with nsIDOMWindowUtils.
-const COMPOSITION_ATTR_RAWINPUT              = 0x02;
-const COMPOSITION_ATTR_SELECTEDRAWTEXT       = 0x03;
-const COMPOSITION_ATTR_CONVERTEDTEXT         = 0x04;
-const COMPOSITION_ATTR_SELECTEDCONVERTEDTEXT = 0x05;
-
-/**
- * Synthesize a composition event.
- *
- * @param aEvent               The composition event information.  This must
- *                             have |type| member.  The value must be
- *                             "compositionstart", "compositionend" or
- *                             "compositionupdate".
- *                             And also this may have |data| and |locale| which
- *                             would be used for the value of each property of
- *                             the composition event.  Note that the data would
- *                             be ignored if the event type were
- *                             "compositionstart".
- * @param aWindow              Optional (If null, current |window| will be used)
- */
-function synthesizeComposition(aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return;
-  }
-
-  utils.sendCompositionEvent(aEvent.type, aEvent.data ? aEvent.data : "",
-                             aEvent.locale ? aEvent.locale : "");
-}
-/**
- * Synthesize a text event.
- *
- * @param aEvent   The text event's information, this has |composition|
- *                 and |caret| members.  |composition| has |string| and
- *                 |clauses| members.  |clauses| must be array object.  Each
- *                 object has |length| and |attr|.  And |caret| has |start| and
- *                 |length|.  See the following tree image.
- *
- *                 aEvent
- *                   +-- composition
- *                   |     +-- string
- *                   |     +-- clauses[]
- *                   |           +-- length
- *                   |           +-- attr
- *                   +-- caret
- *                         +-- start
- *                         +-- length
- *
- *                 Set the composition string to |composition.string|.  Set its
- *                 clauses information to the |clauses| array.
- *
- *                 When it's composing, set the each clauses' length to the
- *                 |composition.clauses[n].length|.  The sum of the all length
- *                 values must be same as the length of |composition.string|.
- *                 Set nsIDOMWindowUtils.COMPOSITION_ATTR_* to the
- *                 |composition.clauses[n].attr|.
- *
- *                 When it's not composing, set 0 to the
- *                 |composition.clauses[0].length| and
- *                 |composition.clauses[0].attr|.
- *
- *                 Set caret position to the |caret.start|. It's offset from
- *                 the start of the composition string.  Set caret length to
- *                 |caret.length|.  If it's larger than 0, it should be wide
- *                 caret.  However, current nsEditor doesn't support wide
- *                 caret, therefore, you should always set 0 now.
- *
- * @param aWindow  Optional (If null, current |window| will be used)
- */
-function synthesizeText(aEvent, aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return;
-  }
-
-  if (!aEvent.composition || !aEvent.composition.clauses ||
-      !aEvent.composition.clauses[0]) {
-    return;
-  }
-
-  var firstClauseLength = aEvent.composition.clauses[0].length;
-  var firstClauseAttr   = aEvent.composition.clauses[0].attr;
-  var secondClauseLength = 0;
-  var secondClauseAttr = 0;
-  var thirdClauseLength = 0;
-  var thirdClauseAttr = 0;
-  if (aEvent.composition.clauses[1]) {
-    secondClauseLength = aEvent.composition.clauses[1].length;
-    secondClauseAttr   = aEvent.composition.clauses[1].attr;
-    if (aEvent.composition.clauses[2]) {
-      thirdClauseLength = aEvent.composition.clauses[2].length;
-      thirdClauseAttr   = aEvent.composition.clauses[2].attr;
-    }
-  }
-
-  var caretStart = -1;
-  var caretLength = 0;
-  if (aEvent.caret) {
-    caretStart = aEvent.caret.start;
-    caretLength = aEvent.caret.length;
-  }
-
-  utils.sendTextEvent(aEvent.composition.string,
-                      firstClauseLength, firstClauseAttr,
-                      secondClauseLength, secondClauseAttr,
-                      thirdClauseLength, thirdClauseAttr,
-                      caretStart, caretLength);
-}
-
-/**
- * Synthesize a query selected text event.
- *
- * @param aWindow  Optional (If null, current |window| will be used)
- * @return         An nsIQueryContentEventResult object.  If this failed,
- *                 the result might be null.
- */
-function synthesizeQuerySelectedText(aWindow)
-{
-  var utils = _getDOMWindowUtils(aWindow);
-  if (!utils) {
-    return null;
-  }
-
-  return utils.sendQueryContentEvent(utils.QUERY_SELECTED_TEXT, 0, 0, 0, 0);
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/arrays.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['inArray', 'getSet', 'indexOf',
-                        'remove', 'rindexOf', 'compare'];
-
-
-function remove(array, from, to) {
-  var rest = array.slice((to || from) + 1 || array.length);
-  array.length = from < 0 ? array.length + from : from;
-
-  return array.push.apply(array, rest);
-}
-
-function inArray(array, value) {
-  for (var i in array) {
-    if (value == array[i]) {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-function getSet(array) {
-  var narray = [];
-
-  for (var i in array) {
-    if (!inArray(narray, array[i])) {
-      narray.push(array[i]);
-    }
-  }
-
-  return narray;
-}
-
-function indexOf(array, v, offset) {
-  for (var i in array) {
-    if (offset == undefined || i >= offset) {
-      if (!isNaN(i) && array[i] == v) {
-        return new Number(i);
-      }
-    }
-  }
-
-  return -1;
-}
-
-function rindexOf (array, v) {
-  var l = array.length;
-
-  for (var i in array) {
-    if (!isNaN(i)) {
-      var i = new Number(i);
-    }
-
-    if (!isNaN(i) && array[l - i] == v) {
-      return l - i;
-    }
-  }
-
-  return -1;
-}
-
-function compare (array, carray) {
-  if (array.length != carray.length) {
-    return false;
-  }
-
-  for (var i in array) {
-    if (array[i] != carray[i]) {
-      return false;
-    }
-  }
-
-  return true;
-}
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/dom.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, you can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var EXPORTED_SYMBOLS = ['getAttributes'];
-
-
-var getAttributes = function (node) {
-  var attributes = {};
-
-  for (var i in node.attributes) {
-    if (!isNaN(i)) {
-      try {
-        var attr = node.attributes[i];
-        attributes[attr.name] = attr.value;
-      }
-      catch (e) {
-      }
-    }
-  }
-
-  return attributes;
-}
-
deleted file mode 100644
--- a/services/sync/tps/extensions/mozmill/resource/stdlib/httpd.js
+++ /dev/null
@@ -1,5349 +0,0 @@
-/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * An implementation of an HTTP server both as a loadable script and as an XPCOM
- * component.  See the accompanying README file for user documentation on
- * httpd.js.
- */
-
-this.EXPORTED_SYMBOLS = [
-  "HTTP_400",
-  "HTTP_401",
-  "HTTP_402",
-  "HTTP_403",
-  "HTTP_404",
-  "HTTP_405",
-  "HTTP_406",
-  "HTTP_407",
-  "HTTP_408",
-  "HTTP_409",
-  "HTTP_410",
-  "HTTP_411",
-  "HTTP_412",
-  "HTTP_413",
-  "HTTP_414",
-  "HTTP_415",
-  "HTTP_417",
-  "HTTP_500",
-  "HTTP_501",
-  "HTTP_502",
-  "HTTP_503",
-  "HTTP_504",
-  "HTTP_505",
-  "HttpError",
-  "HttpServer",
-];
-
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-const CC = Components.Constructor;
-
-const PR_UINT32_MAX = Math.pow(2, 32) - 1;
-
-/** True if debugging output is enabled, false otherwise. */
-var DEBUG = false; // non-const *only* so tweakable in server tests
-
-/** True if debugging output should be timestamped. */
-var DEBUG_TIMESTAMP = false; // non-const so tweakable in server tests
-
-var gGlobalObject = Cu.getGlobalForObject(this);
-
-/**
- * Asserts that the given condition holds.  If it doesn't, the given message is
- * dumped, a stack trace is printed, and an exception is thrown to attempt to
- * stop execution (which unfortunately must rely upon the exception not being
- * accidentally swallowed by the code that uses it).
- */
-function NS_ASSERT(cond, msg)
-{
-  if (DEBUG && !cond)
-  {
-    dumpn("###!!!");
-    dumpn("###!!! ASSERTION" + (msg ? ": " + msg : "!"));
-    dumpn("###!!! Stack follows:");
-
-    var stack = new Error().stack.split(/\n/);
-    dumpn(stack.map(function(val) { return "###!!!   " + val; }).join("\n"));
-
-    throw Cr.NS_ERROR_ABORT;
-  }
-}
-
-/** Constructs an HTTP error object. */
-this.HttpError = function HttpError(code, description)
-{
-  this.code = code;
-  this.description = description;
-}
-HttpError.prototype =
-{
-  toString: function()
-  {
-    return this.code + " " + this.description;
-  }
-};
-
-/**
- * Errors thrown to trigger specific HTTP server responses.
- */
-this.HTTP_400 = new HttpError(400, "Bad Request");
-this.HTTP_401 = new HttpError(401, "Unauthorized");
-this.HTTP_402 = new HttpError(402, "Payment Required");
-this.HTTP_403 = new HttpError(403, "Forbidden");
-this.HTTP_404 = new HttpError(404, "Not Found");
-this.HTTP_405 = new HttpError(405, "Method Not Allowed");
-this.HTTP_406 = new HttpError(406, "Not Acceptable");
-this.HTTP_407 = new HttpError(407, "Proxy Authentication Required");
-this.HTTP_408 = new HttpError(408, "Request Timeout");
-this.HTTP_409 = new HttpError(409, "Conflict");
-this.HTTP_410 = new HttpError(410, "Gone");
-this.HTTP_411 = new HttpError(411, "Length Required");
-this.HTTP_412 = new HttpError(412, "Precondition Failed");
-this.HTTP_413 = new HttpError(413, "Request Entity Too Large");
-this.HTTP_414 = new HttpError(414, "Request-URI Too Long");
-this.HTTP_415 = new HttpError(415, "Unsupported Media Type");
-this.HTTP_417 = new HttpError(417, "Expectation Failed");
-
-this.HTTP_500 = new HttpError(500, "Internal Server Error");
-this.HTTP_501 = new HttpError(501, "Not Implemented");
-this.HTTP_502 = new HttpError(502, "Bad Gateway");
-this.HTTP_503 = new HttpError(503, "Service Unavailable");
-this.HTTP_504 = new HttpError(504, "Gateway Timeout");
-this.HTTP_505 = new HttpError(505, "HTTP Version Not Supported");
-
-/** Creates a hash with fields corresponding to the values in arr. */
-function array2obj(arr)
-{
-  var obj = {};
-  for (var i = 0; i < arr.length; i++)
-    obj[arr[i]] = arr[i];
-  return obj;
-}
-
-/** Returns an array of the integers x through y, inclusive. */
-function range(x, y)
-{
-  var arr = [];
-  for (var i = x; i <= y; i++)
-    arr.push(i);
-  return arr;
-}
-
-/** An object (hash) whose fields are the numbers of all HTTP error codes. */
-const HTTP_ERROR_CODES = array2obj(range(400, 417).concat(range(500, 505)));
-
-
-/**
- * The character used to distinguish hidden files from non-hidden files, a la
- * the leading dot in Apache.  Since that mechanism also hides files from
- * easy display in LXR, ls output, etc. however, we choose instead to use a
- * suffix character.  If a requested file ends with it, we append another
- * when getting the file on the server.  If it doesn't, we just look up that
- * file.  Therefore, any file whose name ends with exactly one of the character
- * is "hidden" and available for use by the server.
- */
-const HIDDEN_CHAR = "^";
-
-/**
- * The file name suffix indicating the file containing overridden headers for
- * a requested file.
- */
-const HEADERS_SUFFIX = HIDDEN_CHAR + "headers" + HIDDEN_CHAR;
-
-/** Type used to denote SJS scripts for CGI-like functionality. */
-const SJS_TYPE = "sjs";
-
-/** Base for relative timestamps produced by dumpn(). */
-var firstStamp = 0;
-
-/** dump(str) with a trailing "\n" -- only outputs if DEBUG. */
-function dumpn(str)
-{
-  if (DEBUG)
-  {
-    var prefix = "HTTPD-INFO | ";
-    if (DEBUG_TIMESTAMP)
-    {
-      if (firstStamp === 0)
-        firstStamp = Date.now();
-
-      var elapsed = Date.now() - firstStamp; // milliseconds
-      var min = Math.floor(elapsed / 60000);
-      var sec = (elapsed % 60000) / 1000;
-
-      if (sec < 10)
-        prefix += min + ":0" + sec.toFixed(3) + " | ";
-      else
-        prefix += min + ":" + sec.toFixed(3) + " | ";
-    }
-
-    dump(prefix + str + "\n");
-  }
-}
-
-/** Dumps the current JS stack if DEBUG. */
-function dumpStack()
-{
-  // peel off the frames for dumpStack() and Error()
-  var stack = new Error().stack.split(/\n/).slice(2);
-  stack.forEach(dumpn);
-}
-
-
-/** The XPCOM thread manager. */
-var gThreadManager = null;
-
-/** The XPCOM prefs service. */
-var gRootPrefBranch = null;
-function getRootPrefBranch()
-{
-  if (!gRootPrefBranch)
-  {
-    gRootPrefBranch = Cc["@mozilla.org/preferences-service;1"]
-                        .getService(Ci.nsIPrefBranch);
-  }
-  return gRootPrefBranch;
-}
-
-/**
- * JavaScript constructors for commonly-used classes; precreating these is a
- * speedup over doing the same from base principles.  See the docs at
- * http://developer.mozilla.org/en/docs/Components.Constructor for details.
- */
-const ServerSocket = CC("@mozilla.org/network/server-socket;1",
-                        "nsIServerSocket",
-                        "init");
-const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
-                                 "nsIScriptableInputStream",
-                                 "init");
-const Pipe = CC("@mozilla.org/pipe;1",
-                "nsIPipe",
-                "init");
-const FileInputStream = CC("@mozilla.org/network/file-input-stream;1",
-                           "nsIFileInputStream",
-                           "init");
-const ConverterInputStream = CC("@mozilla.org/intl/converter-input-stream;1",
-                                "nsIConverterInputStream",
-                                "init");
-const WritablePropertyBag = CC("@mozilla.org/hash-property-bag;1",
-                               "nsIWritablePropertyBag2");
-const SupportsString = CC("@mozilla.org/supports-string;1",
-                          "nsISupportsString");
-
-/* These two are non-const only so a test can overwrite them. */
-var BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
-                           "nsIBinaryInputStream",
-                           "setInputStream");
-var BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
-                            "nsIBinaryOutputStream",
-                            "setOutputStream");
-
-/**
- * Returns the RFC 822/1123 representation of a date.
- *
- * @param date : Number
- *   the date, in milliseconds from midnight (00:00:00), January 1, 1970 GMT
- * @returns string
- *   the representation of the given date
- */
-function toDateString(date)
-{
-  //
-  // rfc1123-date = wkday "," SP date1 SP time SP "GMT"
-  // date1        = 2DIGIT SP month SP 4DIGIT
-  //                ; day month year (e.g., 02 Jun 1982)
-  // time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
-  //                ; 00:00:00 - 23:59:59
-  // wkday        = "Mon" | "Tue" | "Wed"
-  //              | "Thu" | "Fri" | "Sat" | "Sun"
-  // month        = "Jan" | "Feb" | "Mar" | "Apr"
-  //              | "May" | "Jun" | "Jul" | "Aug"
-  //              | "Sep" | "Oct" | "Nov" | "Dec"
-  //
-
-  const wkdayStrings = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
-  const monthStrings = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
-                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
-
-  /**
-   * Processes a date and returns the encoded UTC time as a string according to
-   * the format specified in RFC 2616.
-   *
-   * @param date : Date
-   *   the date to process
-   * @returns string
-   *   a string of the form "HH:MM:SS", ranging from "00:00:00" to "23:59:59"
-   */
-  function toTime(date)
-  {
-    var hrs = date.getUTCHours();
-    var rv  = (hrs < 10) ? "0" + hrs : hrs;
-    
-    var mins = date.getUTCMinutes();
-    rv += ":";
-    rv += (mins < 10) ? "0" + mins : mins;
-
-    var secs = date.getUTCSeconds();
-    rv += ":";
-    rv += (secs < 10) ? "0" + secs : secs;
-
-    return rv;
-  }
-
-  /**
-   * Processes a date and returns the encoded UTC date as a string according to
-   * the date1 format specified in RFC 2616.
-   *
-   * @param date : Date
-   *   the date to process
-   * @returns string
-   *   a string of the form "HH:MM:SS", ranging from "00:00:00" to "23:59:59"
-   */
-  function toDate1(date)
-  {
-    var day = date.getUTCDate();
-    var month = date.getUTCMonth();
-    var year = date.getUTCFullYear();
-
-    var rv = (day < 10) ? "0" + day : day;
-    rv += " " + monthStrings[month];
-    rv += " " + year;
-
-    return rv;
-  }
-
-  date = new Date(date);
-
-  const fmtString = "%wkday%, %date1% %time% GMT";
-  var rv = fmtString.replace("%wkday%", wkdayStrings[date.getUTCDay()]);
-  rv = rv.replace("%time%", toTime(date));
-  return rv.replace("%date1%", toDate1(date));
-}
-
-/**
- * Prints out a human-readable representation of the object o and its fields,
- * omitting those whose names begin with "_" if showMembers != true (to ignore
- * "private" properties exposed via getters/setters).
- */
-function printObj(o, showMembers)
-{
-  var s = "******************************\n";
-  s +=    "o = {\n";
-  for (var i in o)
-  {
-    if (typeof(i) != "string" ||
-        (showMembers || (i.length > 0 && i[0] != "_")))
-      s+= "      " + i + ": " + o[i] + ",\n";
-  }
-  s +=    "    };\n";
-  s +=    "******************************";
-  dumpn(s);
-}
-
-/**
- * Instantiates a new HTTP server.
- */
-function nsHttpServer()
-{
-  if (!gThreadManager)
-    gThreadManager = Cc["@mozilla.org/thread-manager;1"].getService();
-
-  /** The port on which this server listens. */
-  this._port = undefined;
-
-  /** The socket associated with this. */
-  this._socket = null;
-
-  /** The handler used to process requests to this server. */
-  this._handler = new ServerHandler(this);
-
-  /** Naming information for this server. */
-  this._identity = new ServerIdentity();
-
-  /**
-   * Indicates when the server is to be shut down at the end of the request.
-   */
-  this._doQuit = false;
-
-  /**
-   * True if the socket in this is closed (and closure notifications have been
-   * sent and processed if the socket was ever opened), false otherwise.
-   */
-  this._socketClosed = true;
-
-  /**
-   * Used for tracking existing connections and ensuring that all connections
-   * are properly cleaned up before server shutdown; increases by 1 for every
-   * new incoming connection.
-   */
-  this._connectionGen = 0;
-
-  /**
-   * Hash of all open connections, indexed by connection number at time of
-   * creation.
-   */
-  this._connections = {};
-}
-nsHttpServer.prototype =
-{
-  classID: Components.ID("{54ef6f81-30af-4b1d-ac55-8ba811293e41}"),
-
-  // NSISERVERSOCKETLISTENER
-
-  /**
-   * Processes an incoming request coming in on the given socket and contained
-   * in the given transport.
-   *
-   * @param socket : nsIServerSocket
-   *   the socket through which the request was served
-   * @param trans : nsISocketTransport
-   *   the transport for the request/response
-   * @see nsIServerSocketListener.onSocketAccepted
-   */
-  onSocketAccepted: function(socket, trans)
-  {
-    dumpn("*** onSocketAccepted(socket=" + socket + ", trans=" + trans + ")");
-
-    dumpn(">>> new connection on " + trans.host + ":" + trans.port);
-
-    const SEGMENT_SIZE = 8192;
-    const SEGMENT_COUNT = 1024;
-    try
-    {
-      var input = trans.openInputStream(0, SEGMENT_SIZE, SEGMENT_COUNT)
-                       .QueryInterface(Ci.nsIAsyncInputStream);
-      var output = trans.openOutputStream(0, 0, 0);
-    }
-    catch (e)
-    {
-      dumpn("*** error opening transport streams: " + e);
-      trans.close(Cr.NS_BINDING_ABORTED);
-      return;
-    }
-
-    var connectionNumber = ++this._connectionGen;
-
-    try
-    {
-      var conn = new Connection(input, output, this, socket.port, trans.port,
-                                connectionNumber);
-      var reader = new RequestReader(conn);
-
-      // XXX add request timeout functionality here!
-
-      // Note: must use main thread here, or we might get a GC that will cause
-      //       threadsafety assertions.  We really need to fix XPConnect so that
-      //       you can actually do things in multi-threaded JS.  :-(
-      input.asyncWait(reader, 0, 0, gThreadManager.mainThread);
-    }
-    catch (e)
-    {
-      // Assume this connection can't be salvaged and bail on it completely;
-      // don't attempt to close it so that we can assert that any connection
-      // being closed is in this._connections.
-      dumpn("*** error in initial request-processing stages: " + e);
-      trans.close(Cr.NS_BINDING_ABORTED);
-      return;
-    }
-
-    this._connections[connectionNumber] = conn;
-    dumpn("*** starting connection " + connectionNumber);
-  },
-
-  /**
-   * Called when the socket associated with this is closed.
-   *
-   * @param socket : nsIServerSocket
-   *   the socket being closed
-   * @param status : nsresult
-   *   the reason the socket stopped listening (NS_BINDING_ABORTED if the server
-   *   was stopped using nsIHttpServer.stop)
-   * @see nsIServerSocketListener.onStopListening
-   */
-  onStopListening: function(socket, status)
-  {
-    dumpn(">>> shutting down server on port " + socket.port);
-    for (var n in this._connections) {
-      if (!this._connections[n]._requestStarted) {
-        this._connections[n].close();
-      }
-    }
-    this._socketClosed = true;
-    if (this._hasOpenConnections()) {
-      dumpn("*** open connections!!!");
-    }
-    if (!this._hasOpenConnections())
-    {
-      dumpn("*** no open connections, notifying async from onStopListening");
-
-      // Notify asynchronously so that any pending teardown in stop() has a
-      // chance to run first.
-      var self = this;
-      var stopEvent =
-        {
-          run: function()
-          {
-            dumpn("*** _notifyStopped async callback");
-            self._notifyStopped();
-          }
-        };
-      gThreadManager.dispatchToMainThread(stopEvent);
-    }
-  },
-
-  // NSIHTTPSERVER
-
-  //
-  // see nsIHttpServer.start
-  //
-  start: function(port)
-  {
-    this._start(port, "localhost")
-  },
-
-  _start: function(port, host)
-  {
-    if (this._socket)
-      throw Cr.NS_ERROR_ALREADY_INITIALIZED;
-
-    this._port = port;
-    this._doQuit = this._socketClosed = false;
-
-    this._host = host;
-
-    // The listen queue needs to be long enough to handle
-    // network.http.max-persistent-connections-per-server or
-    // network.http.max-persistent-connections-per-proxy concurrent
-    // connections, plus a safety margin in case some other process is
-    // talking to the server as well.
-    var prefs = getRootPrefBranch();
-    var maxConnections = 5 + Math.max(
-      prefs.getIntPref("network.http.max-persistent-connections-per-server"),
-      prefs.getIntPref("network.http.max-persistent-connections-per-proxy"));
-
-    try
-    {
-      var loopback = true;
-      if (this._host != "127.0.0.1" && this._host != "localhost") {
-        var loopback = false;
-      }
-
-      // When automatically selecting a port, sometimes the chosen port is
-      // "blocked" from clients. We don't want to use these ports because
-      // tests will intermittently fail. So, we simply keep trying to to
-      // get a server socket until a valid port is obtained. We limit
-      // ourselves to finite attempts just so we don't loop forever.
-      var ios = Cc["@mozilla.org/network/io-service;1"]
-                  .getService(Ci.nsIIOService);
-      var socket;
-      for (var i = 100; i; i--)
-      {
-        var temp = new ServerSocket(this._port,
-                                    loopback, // true = localhost, false = everybody
-                                    maxConnections);
-
-        var allowed = ios.allowPort(temp.port, "http");
-        if (!allowed)
-        {
-          dumpn(">>>Warning: obtained ServerSocket listens on a blocked " +
-                "port: " + temp.port);
-        }
-
-        if (!allowed && this._port == -1)
-        {
-          dumpn(">>>Throwing away ServerSocket with bad port.");
-          temp.close();
-          continue;
-        }
-
-        socket = temp;
-        break;
-      }
-
-      if (!socket) {
-        throw new Error("No socket server available. Are there no available ports?");
-      }
-
-      dumpn(">>> listening on port " + socket.port + ", " + maxConnections +
-            " pending connections");
-      socket.asyncListen(this);
-      this._port = socket.port;
-      this._identity._initialize(socket.port, host, true);
-      this._socket = socket;
-    }
-    catch (e)
-    {
-      dump("\n!!! could not start server on port " + port + ": " + e + "\n\n");
-      throw Cr.NS_ERROR_NOT_AVAILABLE;
-    }
-  },
-
-  //
-  // see nsIHttpServer.stop
-  //
-  stop: function(callback)
-  {
-    if (!callback)
-      throw Cr.NS_ERROR_NULL_POINTER;
-    if (!this._socket)
-      throw Cr.NS_ERROR_UNEXPECTED;
-
-    this._stopCallback = typeof callback === "function"
-                       ? callback
-                       : function() { callback.onStopped(); };
-
-    dumpn(">>> stopping listening on port " + this._socket.port);
-    this._socket.close();
-    this._socket = null;
-
-    // We can't have this identity any more, and the port on which we're running
-    // this server now could be meaningless the next time around.
-    this._identity._teardown();
-
-    this._doQuit = false;
-
-    // socket-close notification and pending request completion happen async
-  },
-
-  //
-  // see nsIHttpServer.registerFile
-  //
-  registerFile: function(path, file)
-  {
-    if (file && (!file.exists() || file.isDirectory()))
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    this._handler.registerFile(path, file);
-  },
-
-  //
-  // see nsIHttpServer.registerDirectory
-  //
-  registerDirectory: function(path, directory)
-  {
-    // XXX true path validation!
-    if (path.charAt(0) != "/" ||
-        path.charAt(path.length - 1) != "/" ||
-        (directory &&
-         (!directory.exists() || !directory.isDirectory())))
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    // XXX determine behavior of nonexistent /foo/bar when a /foo/bar/ mapping
-    //     exists!
-
-    this._handler.registerDirectory(path, directory);
-  },
-
-  //
-  // see nsIHttpServer.registerPathHandler
-  //
-  registerPathHandler: function(path, handler)
-  {
-    this._handler.registerPathHandler(path, handler);
-  },
-
-  //
-  // see nsIHttpServer.registerPrefixHandler
-  //
-  registerPrefixHandler: function(prefix, handler)
-  {
-    this._handler.registerPrefixHandler(prefix, handler);
-  },
-
-  //
-  // see nsIHttpServer.registerErrorHandler
-  //
-  registerErrorHandler: function(code, handler)
-  {
-    this._handler.registerErrorHandler(code, handler);
-  },
-
-  //
-  // see nsIHttpServer.setIndexHandler
-  //
-  setIndexHandler: function(handler)
-  {
-    this._handler.setIndexHandler(handler);
-  },
-
-  //
-  // see nsIHttpServer.registerContentType
-  //
-  registerContentType: function(ext, type)
-  {
-    this._handler.registerContentType(ext, type);
-  },
-
-  //
-  // see nsIHttpServer.serverIdentity
-  //
-  get identity()
-  {
-    return this._identity;
-  },
-
-  //
-  // see nsIHttpServer.getState
-  //
-  getState: function(path, k)
-  {
-    return this._handler._getState(path, k);
-  },
-
-  //
-  // see nsIHttpServer.setState
-  //
-  setState: function(path, k, v)
-  {
-    return this._handler._setState(path, k, v);
-  },
-
-  //
-  // see nsIHttpServer.getSharedState
-  //
-  getSharedState: function(k)
-  {
-    return this._handler._getSharedState(k);
-  },
-
-  //
-  // see nsIHttpServer.setSharedState
-  //
-  setSharedState: function(k, v)
-  {
-    return this._handler._setSharedState(k, v);
-  },
-
-  //
-  // see nsIHttpServer.getObjectState
-  //
-  getObjectState: function(k)
-  {
-    return this._handler._getObjectState(k);
-  },
-
-  //
-  // see nsIHttpServer.setObjectState
-  //
-  setObjectState: function(k, v)
-  {
-    return this._handler._setObjectState(k, v);
-  },
-
-
-  // NSISUPPORTS
-
-  //
-  // see nsISupports.QueryInterface
-  //
-  QueryInterface: function(iid)
-  {
-    if (iid.equals(Ci.nsIHttpServer) ||
-        iid.equals(Ci.nsIServerSocketListener) ||
-        iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-
-
-  // NON-XPCOM PUBLIC API
-
-  /**
-   * Returns true iff this server is not running (and is not in the process of
-   * serving any requests still to be processed when the server was last
-   * stopped after being run).
-   */
-  isStopped: function()
-  {
-    return this._socketClosed && !this._hasOpenConnections();
-  },
-
-  // PRIVATE IMPLEMENTATION
-
-  /** True if this server has any open connections to it, false otherwise. */
-  _hasOpenConnections: function()
-  {
-    //
-    // If we have any open connections, they're tracked as numeric properties on
-    // |this._connections|.  The non-standard __count__ property could be used
-    // to check whether there are any properties, but standard-wise, even
-    // looking forward to ES5, there's no less ugly yet still O(1) way to do
-    // this.
-    //
-    for (var n in this._connections)
-      return true;
-    return false;
-  },
-
-  /** Calls the server-stopped callback provided when stop() was called. */
-  _notifyStopped: function()
-  {
-    NS_ASSERT(this._stopCallback !== null, "double-notifying?");
-    NS_ASSERT(!this._hasOpenConnections(), "should be done serving by now");
-
-    //
-    // NB: We have to grab this now, null out the member, *then* call the
-    //     callback here, or otherwise the callback could (indirectly) futz with
-    //     this._stopCallback by starting and immediately stopping this, at
-    //     which point we'd be nulling out a field we no longer have a right to
-    //     modify.
-    //
-    var callback = this._stopCallback;
-    this._stopCallback = null;
-    try
-    {
-      callback();
-    }
-    catch (e)
-    {
-      // not throwing because this is specified as being usually (but not
-      // always) asynchronous
-      dump("!!! error running onStopped callback: " + e + "\n");
-    }
-  },
-
-  /**
-   * Notifies this server that the given connection has been closed.
-   *
-   * @param connection : Connection
-   *   the connection that was closed
-   */
-  _connectionClosed: function(connection)
-  {
-    NS_ASSERT(connection.number in this._connections,
-              "closing a connection " + this + " that we never added to the " +
-              "set of open connections?");
-    NS_ASSERT(this._connections[connection.number] === connection,
-              "connection number mismatch?  " +
-              this._connections[connection.number]);
-    delete this._connections[connection.number];
-
-    // Fire a pending server-stopped notification if it's our responsibility.
-    if (!this._hasOpenConnections() && this._socketClosed)
-      this._notifyStopped();
-    // Bug 508125: Add a GC here else we'll use gigabytes of memory running
-    // mochitests. We can't rely on xpcshell doing an automated GC, as that
-    // would interfere with testing GC stuff...
-    Components.utils.forceGC();
-  },
-
-  /**
-   * Requests that the server be shut down when possible.
-   */
-  _requestQuit: function()
-  {
-    dumpn(">>> requesting a quit");
-    dumpStack();
-    this._doQuit = true;
-  }
-};
-
-this.HttpServer = nsHttpServer;
-
-//
-// RFC 2396 section 3.2.2:
-//
-// host        = hostname | IPv4address
-// hostname    = *( domainlabel "." ) toplabel [ "." ]
-// domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
-// toplabel    = alpha | alpha *( alphanum | "-" ) alphanum
-// IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit
-//
-
-const HOST_REGEX =
-  new RegExp("^(?:" +
-               // *( domainlabel "." )
-               "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)*" +
-               // toplabel
-               "[a-z](?:[a-z0-9-]*[a-z0-9])?" +
-             "|" +
-               // IPv4 address 
-               "\\d+\\.\\d+\\.\\d+\\.\\d+" +
-             ")$",
-             "i");
-
-
-/**
- * Represents the identity of a server.  An identity consists of a set of
- * (scheme, host, port) tuples denoted as locations (allowing a single server to
- * serve multiple sites or to be used behind both HTTP and HTTPS proxies for any
- * host/port).  Any incoming request must be to one of these locations, or it
- * will be rejected with an HTTP 400 error.  One location, denoted as the
- * primary location, is the location assigned in contexts where a location
- * cannot otherwise be endogenously derived, such as for HTTP/1.0 requests.
- *
- * A single identity may contain at most one location per unique host/port pair;
- * other than that, no restrictions are placed upon what locations may
- * constitute an identity.
- */
-function ServerIdentity()
-{
-  /** The scheme of the primary location. */
-  this._primaryScheme = "http";
-
-  /** The hostname of the primary location. */
-  this._primaryHost = "127.0.0.1"
-
-  /** The port number of the primary location. */
-  this._primaryPort = -1;
-
-  /**
-   * The current port number for the corresponding server, stored so that a new
-   * primary location can always be set if the current one is removed.
-   */
-  this._defaultPort = -1;
-
-  /**
-   * Maps hosts to maps of ports to schemes, e.g. the following would represent
-   * https://example.com:789/ and http://example.org/:
-   *
-   *   {
-   *     "xexample.com": { 789: "https" },
-   *     "xexample.org": { 80: "http" }
-   *   }
-   *
-   * Note the "x" prefix on hostnames, which prevents collisions with special
-   * JS names like "prototype".
-   */
-  this._locations = { "xlocalhost": {} };
-}
-ServerIdentity.prototype =
-{
-  // NSIHTTPSERVERIDENTITY
-
-  //
-  // see nsIHttpServerIdentity.primaryScheme
-  //
-  get primaryScheme()
-  {
-    if (this._primaryPort === -1)
-      throw Cr.NS_ERROR_NOT_INITIALIZED;
-    return this._primaryScheme;
-  },
-
-  //
-  // see nsIHttpServerIdentity.primaryHost
-  //
-  get primaryHost()
-  {
-    if (this._primaryPort === -1)
-      throw Cr.NS_ERROR_NOT_INITIALIZED;
-    return this._primaryHost;
-  },
-
-  //
-  // see nsIHttpServerIdentity.primaryPort
-  //
-  get primaryPort()
-  {
-    if (this._primaryPort === -1)
-      throw Cr.NS_ERROR_NOT_INITIALIZED;
-    return this._primaryPort;
-  },
-
-  //
-  // see nsIHttpServerIdentity.add
-  //
-  add: function(scheme, host, port)
-  {
-    this._validate(scheme, host, port);
-
-    var entry = this._locations["x" + host];
-    if (!entry)
-      this._locations["x" + host] = entry = {};
-
-    entry[port] = scheme;
-  },
-
-  //
-  // see nsIHttpServerIdentity.remove
-  //
-  remove: function(scheme, host, port)
-  {
-    this._validate(scheme, host, port);
-
-    var entry = this._locations["x" + host];
-    if (!entry)
-      return false;
-
-    var present = port in entry;
-    delete entry[port];
-
-    if (this._primaryScheme == scheme &&
-        this._primaryHost == host &&
-        this._primaryPort == port &&
-        this._defaultPort !== -1)
-    {
-      // Always keep at least one identity in existence at any time, unless
-      // we're in the process of shutting down (the last condition above).
-      this._primaryPort = -1;
-      this._initialize(this._defaultPort, host, false);
-    }
-
-    return present;
-  },
-
-  //
-  // see nsIHttpServerIdentity.has
-  //
-  has: function(scheme, host, port)
-  {
-    this._validate(scheme, host, port);
-
-    return "x" + host in this._locations &&
-           scheme === this._locations["x" + host][port];
-  },
-
-  //
-  // see nsIHttpServerIdentity.has
-  //
-  getScheme: function(host, port)
-  {
-    this._validate("http", host, port);
-
-    var entry = this._locations["x" + host];
-    if (!entry)
-      return "";
-
-    return entry[port] || "";
-  },
-
-  //
-  // see nsIHttpServerIdentity.setPrimary
-  //
-  setPrimary: function(scheme, host, port)
-  {
-    this._validate(scheme, host, port);
-
-    this.add(scheme, host, port);
-
-    this._primaryScheme = scheme;
-    this._primaryHost = host;
-    this._primaryPort = port;
-  },
-
-
-  // NSISUPPORTS
-
-  //
-  // see nsISupports.QueryInterface
-  //
-  QueryInterface: function(iid)
-  {
-    if (iid.equals(Ci.nsIHttpServerIdentity) || iid.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-
-
-  // PRIVATE IMPLEMENTATION
-
-  /**
-   * Initializes the primary name for the corresponding server, based on the
-   * provided port number.
-   */
-  _initialize: function(port, host, addSecondaryDefault)
-  {
-    this._host = host;
-    if (this._primaryPort !== -1)
-      this.add("http", host, port);
-    else
-      this.setPrimary("http", "localhost", port);
-    this._defaultPort = port;
-
-    // Only add this if we're being called at server startup
-    if (addSecondaryDefault && host != "127.0.0.1")
-      this.add("http", "127.0.0.1", port);
-  },
-
-  /**
-   * Called at server shutdown time, unsets the primary location only if it was
-   * the default-assigned location and removes the default location from the
-   * set of locations used.
-   */
-  _teardown: function()
-  {
-    if (this._host != "127.0.0.1") {
-      // Not the default primary location, nothing special to do here
-      this.remove("http", "127.0.0.1", this._defaultPort);
-    }
-    
-    // This is a *very* tricky bit of reasoning here; make absolutely sure the
-    // tests for this code pass before you commit changes to it.
-    if (this._primaryScheme == "http" &&
-        this._primaryHost == this._host &&
-        this._primaryPort == this._defaultPort)
-    {
-      // Make sure we don't trigger the readding logic in .remove(), then remove
-      // the default location.
-      var port = this._defaultPort;
-      this._defaultPort = -1;
-      this.remove("http", this._host, port);
-
-      // Ensure a server start triggers the setPrimary() path in ._initialize()
-      this._primaryPort = -1;
-    }
-    else
-    {
-      // No reason not to remove directly as it's not our primary location
-      this.remove("http", this._host, this._defaultPort);
-    }
-  },
-
-  /**
-   * Ensures scheme, host, and port are all valid with respect to RFC 2396.
-   *
-   * @throws NS_ERROR_ILLEGAL_VALUE
-   *   if any argument doesn't match the corresponding production
-   */
-  _validate: function(scheme, host, port)
-  {
-    if (scheme !== "http" && scheme !== "https")
-    {
-      dumpn("*** server only supports http/https schemes: '" + scheme + "'");
-      dumpStack();
-      throw Cr.NS_ERROR_ILLEGAL_VALUE;
-    }
-    if (!HOST_REGEX.test(host))
-    {
-      dumpn("*** unexpected host: '" + host + "'");
-      throw Cr.NS_ERROR_ILLEGAL_VALUE;
-    }
-    if (port < 0 || port > 65535)
-    {
-      dumpn("*** unexpected port: '" + port + "'");
-      throw Cr.NS_ERROR_ILLEGAL_VALUE;
-    }
-  }
-};
-
-
-/**
- * Represents a connection to the server (and possibly in the future the thread
- * on which the connection is processed).
- *
- * @param input : nsIInputStream
- *   stream from which incoming data on the connection is read
- * @param output : nsIOutputStream
- *   stream to write data out the connection
- * @param server : nsHttpServer
- *   the server handling the connection
- * @param port : int
- *   the port on which the server is running
- * @param outgoingPort : int
- *   the outgoing port used by this connection
- * @param number : uint
- *   a serial number used to uniquely identify this connection
- */
-function Connection(input, output, server, port, outgoingPort, number)
-{
-  dumpn("*** opening new connection " + number + " on port " + outgoingPort);
-
-  /** Stream of incoming data. */
-  this.input = input;
-
-  /** Stream for outgoing data. */
-  this.output = output;
-
-  /** The server associated with this request. */
-  this.server = server;
-
-  /** The port on which the server is running. */
-  this.port = port;
-
-  /** The outgoing poort used by this connection. */
-  this._outgoingPort = outgoingPort;
-
-  /** The serial number of this connection. */
-  this.number = number;
-
-  /**
-   * The request for which a response is being generated, null if the
-   * incoming request has not been fully received or if it had errors.
-   */
-  this.request = null;
-
-  /** This allows a connection to disambiguate between a peer initiating a
-   *  close and the socket being forced closed on shutdown.
-   */
-  this._closed = false;
-
-  /** State variable for debugging. */
-  this._processed = false;
-
-  /** whether or not 1st line of request has been received */
-  this._requestStarted = false; 
-}
-Connection.prototype =
-{
-  /** Closes this connection's input/output streams. */
-  close: function()
-  {
-    if (this._closed)
-        return;
-
-    dumpn("*** closing connection " + this.number +
-          " on port " + this._outgoingPort);
-
-    this.input.close();
-    this.output.close();
-    this._closed = true;
-
-    var server = this.server;
-    server._connectionClosed(this);
-
-    // If an error triggered a server shutdown, act on it now
-    if (server._doQuit)
-      server.stop(function() { /* not like we can do anything better */ });
-  },
-
-  /**
-   * Initiates processing of this connection, using the data in the given
-   * request.
-   *
-   * @param request : Request
-   *   the request which should be processed
-   */
-  process: function(request)
-  {
-    NS_ASSERT(!this._closed && !this._processed);
-
-    this._processed = true;
-
-    this.request = request;
-    this.server._handler.handleResponse(this);
-  },
-
-  /**
-   * Initiates processing of this connection, generating a response with the
-   * given HTTP error code.
-   *
-   * @param code : uint
-   *   an HTTP code, so in the range [0, 1000)
-   * @param request : Request
-   *   incomplete data about the incoming request (since there were errors
-   *   during its processing
-   */
-  processError: function(code, request)
-  {
-    NS_ASSERT(!this._closed && !this._processed);
-
-    this._processed = true;
-    this.request = request;
-    this.server._handler.handleError(code, this);
-  },
-
-  /** Converts this to a string for debugging purposes. */
-  toString: function()
-  {
-    return "<Connection(" + this.number +
-           (this.request ? ", " + this.request.path : "") +"): " +
-           (this._closed ? "closed" : "open") + ">";
-  },
-
-  requestStarted: function()
-  {
-    this._requestStarted = true;
-  }
-};
-
-
-
-/** Returns an array of count bytes from the given input stream. */
-function readBytes(inputStream, count)
-{
-  return new BinaryInputStream(inputStream).readByteArray(count);
-}
-
-
-
-/** Request reader processing states; see RequestReader for details. */
-const READER_IN_REQUEST_LINE = 0;
-const READER_IN_HEADERS      = 1;
-const READER_IN_BODY         = 2;
-const READER_FINISHED        = 3;
-
-
-/**
- * Reads incoming request data asynchronously, does any necessary preprocessing,
- * and forwards it to the request handler.  Processing occurs in three states:
- *
- *   READER_IN_REQUEST_LINE     Reading the request's status line
- *   READER_IN_HEADERS          Reading headers in the request
- *   READER_IN_BODY             Reading the body of the request
- *   READER_FINISHED            Entire request has been read and processed
- *
- * During the first two stages, initial metadata about the request is gathered
- * into a Request object.  Once the status line and headers have been processed,
- * we start processing the body of the request into the Request.  Finally, when
- * the entire body has been read, we create a Response and hand it off to the
- * ServerHandler to be given to the appropriate request handler.
- *
- * @param connection : Connection
- *   the connection for the request being read
- */
-function RequestReader(connection)
-{
-  /** Connection metadata for this request. */
-  this._connection = connection;
-
-  /**
-   * A container providing line-by-line access to the raw bytes that make up the
-   * data which has been read from the connection but has not yet been acted
-   * upon (by passing it to the request handler or by extracting request
-   * metadata from it).
-   */
-  this._data = new LineData();
-
-  /**
-   * The amount of data remaining to be read from the body of this request.
-   * After all headers in the request have been read this is the value in the
-   * Content-Length header, but as the body is read its value decreases to zero.
-   */
-  this._contentLength = 0;
-
-  /** The current state of parsing the incoming request. */
-  this._state = READER_IN_REQUEST_LINE;
-
-  /** Metadata constructed from the incoming request for the request handler. */
-  this._metadata = new Request(connection.port);
-
-  /**
-   * Used to preserve state if we run out of line data midway through a
-   * multi-line header.  _lastHeaderName stores the name of the header, while
-   * _lastHeaderValue stores the value we've seen so far for the header.
-   *
-   * These fields are always either both undefined or both strings.
-   */
-  this._lastHeaderName = this._lastHeaderValue = undefined;
-}
-RequestReader.prototype =
-{
-  // NSIINPUTSTREAMCALLBACK
-
-  /**
-   * Called when more data from the incoming request is available.  This method
-   * then reads the available data from input and deals with that data as
-   * necessary, depending upon the syntax of already-downloaded data.
-   *
-   * @param input : nsIAsyncInputStream
-   *   the stream of incoming data from the connection
-   */
-  onInputStreamReady: function(input)
-  {
-    dumpn("*** onInputStreamReady(input=" + input + ") on thread " +
-          gThreadManager.currentThread + " (main is " +
-          gThreadManager.mainThread + ")");
-    dumpn("*** this._state == " + this._state);
-
-    // Handle cases where we get more data after a request error has been
-    // discovered but *before* we can close the connection.
-    var data = this._data;
-    if (!data)
-      return;
-
-    try
-    {
-      data.appendBytes(readBytes(input, input.available()));
-    }
-    catch (e)
-    {
-      if (streamClosed(e))
-      {
-        dumpn("*** WARNING: unexpected error when reading from socket; will " +
-              "be treated as if the input stream had been closed");
-        dumpn("*** WARNING: actual error was: " + e);
-      }
-
-      // We've lost a race -- input has been closed, but we're still expecting
-      // to read more data.  available() will throw in this case, and since
-      // we're dead in the water now, destroy the connection.
-      dumpn("*** onInputStreamReady called on a closed input, destroying " +
-            "connection");
-      this._connection.close();
-      return;
-    }
-
-    switch (this._state)
-    {
-      default:
-        NS_ASSERT(false, "invalid state: " + this._state);
-        break;
-
-      case READER_IN_REQUEST_LINE:
-        if (!this._processRequestLine())
-          break;
-        /* fall through */
-
-      case READER_IN_HEADERS:
-        if (!this._processHeaders())
-          break;
-        /* fall through */
-
-      case READER_IN_BODY:
-        this._processBody();
-    }
-
-    if (this._state != READER_FINISHED)
-      input.asyncWait(this, 0, 0, gThreadManager.currentThread);
-  },
-
-  //
-  // see nsISupports.QueryInterface
-  //
-  QueryInterface: function(aIID)
-  {
-    if (aIID.equals(Ci.nsIInputStreamCallback) ||
-        aIID.equals(Ci.nsISupports))
-      return this;
-
-    throw Cr.NS_ERROR_NO_INTERFACE;
-  },
-
-
-  // PRIVATE API
-
-  /**
-   * Processes unprocessed, downloaded data as a request line.
-   *
-   * @returns boolean
-   *   true iff the request line has been fully processed
-   */
-  _processRequestLine: function()
-  {
-    NS_ASSERT(this._state == READER_IN_REQUEST_LINE);
-
-    // Servers SHOULD ignore any empty line(s) received where a Request-Line
-    // is expected (section 4.1).
-    var data = this._data;
-    var line = {};
-    var readSuccess;
-    while ((readSuccess = data.readLine(line)) && line.value == "")
-      dumpn("*** ignoring beginning blank line...");
-
-    // if we don't have a full line, wait until we do
-    if (!readSuccess)
-      return false;
-
-    // we have the first non-blank line
-    try
-    {
-      this._parseRequestLine(line.value);
-      this._state = READER_IN_HEADERS;
-      this._connection.requestStarted();
-      return true;
-    }
-    catch (e)
-    {
-      this._handleError(e);
-      return false;
-    }
-  },
-
-  /**
-   * Processes stored data, assuming it is either at the beginning or in
-   * the middle of processing request headers.
-   *
-   * @returns boolean
-   *   true iff header data in the request has been fully processed
-   */
-  _processHeaders: function()
-  {
-    NS_ASSERT(this._state == READER_IN_HEADERS);
-
-    // XXX things to fix here:
-    //
-    // - need to support RFC 2047-encoded non-US-ASCII characters
-
-    try
-    {
-      var done = this._parseHeaders();
-      if (done)
-      {
-        var request = this._metadata;
-
-        // XXX this is wrong for requests with transfer-encodings applied to
-        //     them, particularly chunked (which by its nature can have no
-        //     meaningful Content-Length header)!
-        this._contentLength = request.hasHeader("Content-Length")
-                            ? parseInt(request.getHeader("Content-Length"), 10)
-                            : 0;
-        dumpn("_processHeaders, Content-length=" + this._contentLength);
-
-        this._state = READER_IN_BODY;
-      }
-      return done;
-    }
-    catch (e)
-    {
-      this._handleError(e);
-      return false;
-    }
-  },
-
-  /**
-   * Processes stored data, assuming it is either at the beginning or in
-   * the middle of processing the request body.
-   *
-   * @returns boolean
-   *   true iff the request body has been fully processed
-   */
-  _processBody: function()
-  {
-    NS_ASSERT(this._state == READER_IN_BODY);
-
-    // XXX handle chunked transfer-coding request bodies!
-
-    try
-    {
-      if (this._contentLength > 0)
-      {
-        var data = this._data.purge();
-        var count = Math.min(data.length, this._contentLength);
-        dumpn("*** loading data=" + data + " len=" + data.length +
-              " excess=" + (data.length - count));
-
-        var bos = new BinaryOutputStream(this._metadata._bodyOutputStream);
-        bos.writeByteArray(data, count);
-        this._contentLength -= count;
-      }
-
-      dumpn("*** remaining body data len=" + this._contentLength);
-      if (this._contentLength == 0)
-      {
-        this._validateRequest();
-        this._state = READER_FINISHED;
-        this._handleResponse();
-        return true;
-      }
-      
-      return false;
-    }
-    catch (e)
-    {
-      this._handleError(e);
-      return false;
-    }
-  },
-
-  /**
-   * Does various post-header checks on the data in this request.
-   *
-   * @throws : HttpError
-   *   if the request was malformed in some way
-   */
-  _validateRequest: function()
-  {
-    NS_ASSERT(this._state == READER_IN_BODY);
-
-    dumpn("*** _validateRequest");
-
-    var metadata = this._metadata;
-    var headers = metadata._headers;
-
-    // 19.6.1.1 -- servers MUST report 400 to HTTP/1.1 requests w/o Host header
-    var identity = this._connection.server.identity;
-    if (metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
-    {
-      if (!headers.hasHeader("Host"))
-      {
-        dumpn("*** malformed HTTP/1.1 or greater request with no Host header!");
-        throw HTTP_400;
-      }
-
-      // If the Request-URI wasn't absolute, then we need to determine our host.
-      // We have to determine what scheme was used to access us based on the
-      // server identity data at this point, because the request just doesn't
-      // contain enough data on its own to do this, sadly.
-      if (!metadata._host)
-      {
-        var host, port;
-        var hostPort = headers.getHeader("Host");
-        var colon = hostPort.indexOf(":");
-        if (colon < 0)
-        {
-          host = hostPort;
-          port = "";
-        }
-        else
-        {
-          host = hostPort.substring(0, colon);
-          port = hostPort.substring(colon + 1);
-        }
-
-        // NB: We allow an empty port here because, oddly, a colon may be
-        //     present even without a port number, e.g. "example.com:"; in this
-        //     case the default port applies.
-        if (!HOST_REGEX.test(host) || !/^\d*$/.test(port))
-        {
-          dumpn("*** malformed hostname (" + hostPort + ") in Host " +
-                "header, 400 time");
-          throw HTTP_400;
-        }
-
-        // If we're not given a port, we're stuck, because we don't know what
-        // scheme to use to look up the correct port here, in general.  Since
-        // the HTTPS case requires a tunnel/proxy and thus requires that the
-        // requested URI be absolute (and thus contain the necessary
-        // information), let's assume HTTP will prevail and use that.
-        port = +port || 80;
-
-        var scheme = identity.getScheme(host, port);
-        if (!scheme)
-        {
-          dumpn("*** unrecognized hostname (" + hostPort + ") in Host " +
-                "header, 400 time");
-          throw HTTP_400;
-        }
-
-        metadata._scheme = scheme;
-        metadata._host = host;
-        metadata._port = port;
-      }
-    }
-    else
-    {
-      NS_ASSERT(metadata._host === undefined,
-                "HTTP/1.0 doesn't allow absolute paths in the request line!");
-
-      metadata._scheme = identity.primaryScheme;
-      metadata._host = identity.primaryHost;
-      metadata._port = identity.primaryPort;
-    }
-
-    NS_ASSERT(identity.has(metadata._scheme, metadata._host, metadata._port),
-              "must have a location we recognize by now!");
-  },
-
-  /**
-   * Handles responses in case of error, either in the server or in the request.
-   *
-   * @param e
-   *   the specific error encountered, which is an HttpError in the case where
-   *   the request is in some way invalid or cannot be fulfilled; if this isn't
-   *   an HttpError we're going to be paranoid and shut down, because that
-   *   shouldn't happen, ever
-   */
-  _handleError: function(e)
-  {
-    // Don't fall back into normal processing!
-    this._state = READER_FINISHED;
-
-    var server = this._connection.server;
-    if (e instanceof HttpError)
-    {
-      var code = e.code;
-    }
-    else
-    {
-      dumpn("!!! UNEXPECTED ERROR: " + e +
-            (e.lineNumber ? ", line " + e.lineNumber : ""));
-
-      // no idea what happened -- be paranoid and shut down
-      code = 500;
-      server._requestQuit();
-    }
-
-    // make attempted reuse of data an error
-    this._data = null;
-
-    this._connection.processError(code, this._metadata);
-  },
-
-  /**
-   * Now that we've read the request line and headers, we can actually hand off
-   * the request to be handled.
-   *
-   * This method is called once per request, after the request line and all
-   * headers and the body, if any, have been received.
-   */
-  _handleResponse: function()
-  {
-    NS_ASSERT(this._state == READER_FINISHED);
-
-    // We don't need the line-based data any more, so make attempted reuse an
-    // error.
-    this._data = null;
-
-    this._connection.process(this._metadata);
-  },
-
-
-  // PARSING
-
-  /**
-   * Parses the request line for the HTTP request associated with this.
-   *
-   * @param line : string
-   *   the request line
-   */
-  _parseRequestLine: function(line)
-  {
-    NS_ASSERT(this._state == READER_IN_REQUEST_LINE);
-
-    dumpn("*** _parseRequestLine('" + line + "')");
-
-    var metadata = this._metadata;
-
-    // clients and servers SHOULD accept any amount of SP or HT characters
-    // between fields, even though only a single SP is required (section 19.3)
-    var request = line.split(/[ \t]+/);
-    if (!request || request.length != 3)
-    {
-      dumpn("*** No request in line");
-      throw HTTP_400;
-    }
-
-    metadata._method = request[0];
-
-    // get the HTTP version
-    var ver = request[2];
-    var match = ver.match(/^HTTP\/(\d+\.\d+)$/);
-    if (!match)
-    {
-      dumpn("*** No HTTP version in line");
-      throw HTTP_400;
-    }
-
-    // determine HTTP version
-    try
-    {
-      metadata._httpVersion = new nsHttpVersion(match[1]);
-      if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_0))
-        throw new Error("unsupported HTTP version");
-    }
-    catch (e)
-    {
-      // we support HTTP/1.0 and HTTP/1.1 only
-      throw HTTP_501;
-    }
-
-
-    var fullPath = request[1];
-    var serverIdentity = this._connection.server.identity;
-
-    var scheme, host, port;
-
-    if (fullPath.charAt(0) != "/")
-    {
-      // No absolute paths in the request line in HTTP prior to 1.1
-      if (!metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1))
-      {
-        dumpn("*** Metadata version too low");
-        throw HTTP_400;
-      }
-
-      try
-      {
-        var uri = Cc["@mozilla.org/network/io-service;1"]
-                    .getService(Ci.nsIIOService)
-                    .newURI(fullPath);
-        fullPath = uri.pathQueryRef;
-        scheme = uri.scheme;
-        host = metadata._host = uri.asciiHost;
-        port = uri.port;
-        if (port === -1)
-        {
-          if (scheme === "http")
-          {
-            port = 80;
-          }
-          else if (scheme === "https")
-          {
-            port = 443;
-          }
-          else
-          {
-            dumpn("*** Unknown scheme: " + scheme);
-            throw HTTP_400;
-          }
-        }
-      }
-      catch (e)
-      {
-        // If the host is not a valid host on the server, the response MUST be a
-        // 400 (Bad Request) error message (section 5.2).  Alternately, the URI
-        // is malformed.
-        dumpn("*** Threw when dealing with URI: " + e);
-        throw HTTP_400;
-      }
-
-      if (!serverIdentity.has(scheme, host, port) || fullPath.charAt(0) != "/")
-      {
-        dumpn("*** serverIdentity unknown or path does not start with '/'");
-        throw HTTP_400;
-      }
-    }
-
-    var splitter = fullPath.indexOf("?");
-    if (splitter < 0)
-    {
-      // _queryString already set in ctor
-      metadata._path = fullPath;
-    }
-    else
-    {
-      metadata._path = fullPath.substring(0, splitter);
-      metadata._queryString = fullPath.substring(splitter + 1);
-    }
-
-    metadata._scheme = scheme;
-    metadata._host = host;
-    metadata._port = port;
-  },
-
-  /**
-   * Parses all available HTTP headers in this until the header-ending CRLFCRLF,
-   * adding them to the store of headers in the request.
-   *
-   * @throws
-   *   HTTP_400 if the headers are malformed
-   * @returns boolean
-   *   true if all headers have now been processed, false otherwise
-   */
-  _parseHeaders: function()
-  {
-    NS_ASSERT(this._state == READER_IN_HEADERS);
-
-    dumpn("*** _parseHeaders");
-
-    var data = this._data;
-
-    var headers = this._metadata._headers;
-    var lastName = this._lastHeaderName;
-    var lastVal = this._lastHeaderValue;
-
-    var line = {};
-    while (true)
-    {
-      dumpn("*** Last name: '" + lastName + "'");
-      dumpn("*** Last val: '" + lastVal + "'");
-      NS_ASSERT(!((lastVal === undefined) ^ (lastName === undefined)),
-                lastName === undefined ?
-                  "lastVal without lastName?  lastVal: '" + lastVal + "'" :
-                  "lastName without lastVal?  lastName: '" + lastName + "'");
-
-      if (!data.readLine(line))
-      {
-        // save any data we have from the header we might still be processing
-        this._lastHeaderName = lastName;
-        this._lastHeaderValue = lastVal;
-        return false;
-      }
-
-      var lineText = line.value;
-      dumpn("*** Line text: '" + lineText + "'");
-      var firstChar = lineText.charAt(0);
-
-      // blank line means end of headers
-      if (lineText == "")
-      {
-        // we're finished with the previous header
-        if (lastName)
-        {
-          try
-          {
-            headers.setHeader(lastName, lastVal, true);
-          }
-          catch (e)
-          {
-            dumpn("*** setHeader threw on last header, e == " + e);
-            throw HTTP_400;
-          }
-        }
-        else
-        {
-          // no headers in request -- valid for HTTP/1.0 requests
-        }
-
-        // either way, we're done processing headers
-        this._state = READER_IN_BODY;
-        return true;
-      }
-      else if (firstChar == " " || firstChar == "\t")
-      {
-        // multi-line header if we've already seen a header line
-        if (!lastName)
-        {
-          dumpn("We don't have a header to continue!");
-          throw HTTP_400;
-        }
-
-        // append this line's text to the value; starts with SP/HT, so no need
-        // for separating whitespace
-        lastVal += lineText;
-      }
-      else
-      {
-        // we have a new header, so set the old one (if one existed)
-        if (lastName)
-        {
-          try
-          {
-            headers.setHeader(lastName, lastVal, true);
-          }
-          catch (e)
-          {
-            dumpn("*** setHeader threw on a header, e == " + e);
-            throw HTTP_400;
-          }
-        }
-
-        var colon = lineText.indexOf(":"); // first colon must be splitter
-        if (colon < 1)
-        {
-          dumpn("*** No colon or missing header field-name");
-          throw HTTP_400;
-        }
-
-        // set header name, value (to be set in the next loop, usually)
-        lastName = lineText.substring(0, colon);
-        lastVal = lineText.substring(colon + 1);
-      } // empty, continuation, start of header
-    } // while (true)
-  }
-};
-
-
-/** The character codes for CR and LF. */
-const CR = 0x0D, LF = 0x0A;
-
-/**
- * Calculates the number of characters before the first CRLF pair in array, or
- * -1 if the array contains no CRLF pair.
- *
- * @param array : Array
- *   an array of numbers in the range [0, 256), each representing a single
- *   character; the first CRLF is the lowest index i where
- *   |array[i] == "\r".charCodeAt(0)| and |array[i+1] == "\n".charCodeAt(0)|,
- *   if such an |i| exists, and -1 otherwise
- * @param start : uint
- *   start index from which to begin searching in array
- * @returns int
- *   the index of the first CRLF if any were present, -1 otherwise
- */
-function findCRLF(array, start)
-{
-  for (var i = array.indexOf(CR, start); i >= 0; i = array.indexOf(CR, i + 1))
-  {
-    if (array[i + 1] == LF)
-      return i;
-  }
-  return -1;
-}
-
-
-/**
- * A container which provides line-by-line access to the arrays of bytes with
- * which it is seeded.
- */
-function LineData()
-{
-  /** An array of queued bytes from which to get line-based characters. */
-  this._data = [];
-
-  /** Start index from which to search for CRLF. */
-  this._start = 0;
-}
-LineData.prototype =
-{
-  /**
-   * Appends the bytes in the given array to the internal data cache maintained
-   * by this.
-   */
-  appendBytes: function(bytes)
-  {
-    var count = bytes.length;
-    var quantum = 262144; // just above half SpiderMonkey's argument-count limit
-    if (count < quantum)
-    {
-      Array.prototype.push.apply(this._data, bytes);
-      return;
-    }
-
-    // Large numbers of bytes may cause Array.prototype.push to be called with
-    // more arguments than the JavaScript engine supports.  In that case append
-    // bytes in fixed-size amounts until all bytes are appended.
-    for (var start = 0; start < count; start += quantum)
-    {
-      var slice = bytes.slice(start, Math.min(start + quantum, count));
-      Array.prototype.push.apply(this._data, slice);
-    }
-  },
-
-  /**
-   * Removes and returns a line of data, delimited by CRLF, from this.
-   *
-   * @param out
-   *   an object whose "value" property will be set to the first line of text
-   *   present in this, sans CRLF, if this contains a full CRLF-delimited line
-   *   of text; if this doesn't contain enough data, the value of the property
-   *   is undefined
-   * @returns boolean
-   *   true if a full line of data could be read from the data in this, false
-   *   otherwise
-   */
-  readLine: function(out)
-  {
-    var data = this._data;
-    var length = findCRLF(data, this._start);
-    if (length < 0)
-    {
-      this._start = data.length;
-
-      // But if our data ends in a CR, we have to back up one, because
-      // the first byte in the next packet might be an LF and if we
-      // start looking at data.length we won't find it.
-      if (data.length > 0 && data[data.length - 1] === CR)
-        --this._start;
-
-      return false;
-    }
-
-    // Reset for future lines.
-    this._start = 0;
-
-    //
-    // We have the index of the CR, so remove all the characters, including
-    // CRLF, from the array with splice, and convert the removed array
-    // (excluding the trailing CRLF characters) into the corresponding string.
-    //
-    var leading = data.splice(0, length + 2);
-    var quantum = 262144;
-    var line = "";
-    for (var start = 0; start < length; start += quantum)
-    {
-      var slice = leading.slice(start, Math.min(start + quantum, length));
-      line += String.fromCharCode.apply(null, slice);
-    }
-
-    out.value = line;
-    return true;
-  },
-
-  /**
-   * Removes the bytes currently within this and returns them in an array.
-   *
-   * @returns Array
-   *   the bytes within this when this method is called
-   */
-  purge: function()
-  {
-    var data = this._data;
-    this._data = [];
-    return data;
-  }
-};
-
-
-
-/**
- * Creates a request-handling function for an nsIHttpRequestHandler object.
- */
-function createHandlerFunc(handler)
-{
-  return function(metadata, response) { handler.handle(metadata, response); };
-}
-
-
-/**
- * The default handler for directories; writes an HTML response containing a
- * slightly-formatted directory listing.
- */
-function defaultIndexHandler(metadata, response)
-{
-  response.setHeader("Content-Type", "text/html;charset=utf-8", false);
-
-  var path = htmlEscape(decodeURI(metadata.path));
-
-  //
-  // Just do a very basic bit of directory listings -- no need for too much
-  // fanciness, especially since we don't have a style sheet in which we can
-  // stick rules (don't want to pollute the default path-space).
-  //
-
-  var body = '<html>\
-                <head>\
-                  <title>' + path + '</title>\
-                </head>\
-                <body>\
-                  <h1>' + path + '</h1>\
-                  <ol style="list-style-type: none">';
-
-  var directory = metadata.getProperty("directory");
-  NS_ASSERT(directory && directory.isDirectory());
-
-  var fileList = [];
-  var files = directory.directoryEntries;
-  while (files.hasMoreElements())
-  {
-    var f = files.getNext().QueryInterface(Ci.nsIFile);
-    var name = f.leafName;
-    if (!f.isHidden() &&
-        (name.charAt(name.length - 1) != HIDDEN_CHAR ||
-         name.charAt(name.length - 2) == HIDDEN_CHAR))
-      fileList.push(f);
-  }
-
-  fileList.sort(fileSort);
-
-  for (var i = 0; i < fileList.length; i++)
-  {
-    var file = fileList[i];
-    try
-    {
-      var name = file.leafName;
-      if (name.charAt(name.length - 1) == HIDDEN_CHAR)
-        name = name.substring(0, name.length - 1);
-      var sep = file.isDirectory() ? "/" : "";
-
-      // Note: using " to delimit the attribute here because encodeURIComponent
-      //       passes through '.
-      var item = '<li><a href="' + encodeURIComponent(name) + sep + '">' +
-                   htmlEscape(name) + sep +
-                 '</a></li>';
-
-      body += item;
-    }
-    catch (e) { /* some file system error, ignore the file */ }
-  }
-
-  body    += '    </ol>\
-                </body>\
-              </html>';
-
-  response.bodyOutputStream.write(body, body.length);
-}
-
-/**
- * Sorts a and b (nsIFile objects) into an aesthetically pleasing order.
- */
-function fileSort(a, b)
-{
-  var dira = a.isDirectory(), dirb = b.isDirectory();
-
-  if (dira && !dirb)
-    return -1;
-  if (dirb && !dira)
-    return 1;
-
-  var namea = a.leafName.toLowerCase(), nameb = b.leafName.toLowerCase();
-  return nameb > namea ? -1 : 1;
-}
-
-
-/**
- * Converts an externally-provided path into an internal path for use in
- * determining file mappings.
- *
- * @param path
- *   the path to convert
- * @param encoded
- *   true if the given path should be passed through decodeURI prior to
- *   conversion
- * @throws URIError
- *   if path is incorrectly encoded
- */
-function toInternalPath(path, encoded)
-{
-  if (encoded)
-    path = decodeURI(path);
-
-  var comps = path.split("/");
-  for (var i = 0, sz = comps.length; i < sz; i++)
-  {
-    var comp = comps[i];
-    if (comp.charAt(comp.length - 1) == HIDDEN_CHAR)
-      comps[i] = comp + HIDDEN_CHAR;
-  }
-  return comps.join("/");
-}
-
-const PERMS_READONLY = (4 << 6) | (4 << 3) | 4;
-
-/**
- * Adds custom-specified headers for the given file to the given response, if
- * any such headers are specified.
- *
- * @param file
- *   the file on the disk which is to be written
- * @param metadata
- *   metadata about the incoming request
- * @param response
- *   the Response to which any specified headers/data should be written
- * @throws HTTP_500
- *   if an error occurred while processing custom-specified headers
- */
-function maybeAddHeaders(file, metadata, response)
-{
-  var name = file.leafName;
-  if (name.charAt(name.length - 1) == HIDDEN_CHAR)
-    name = name.substring(0, name.length - 1);
-
-  var headerFile = file.parent;
-  headerFile.append(name + HEADERS_SUFFIX);
-
-  if (!headerFile.exists())
-    return;
-
-  const PR_RDONLY = 0x01;
-  var fis = new FileInputStream(headerFile, PR_RDONLY, PERMS_READONLY,
-                                Ci.nsIFileInputStream.CLOSE_ON_EOF);
-
-  try
-  {
-    var lis = new ConverterInputStream(fis, "UTF-8", 1024, 0x0);
-    lis.QueryInterface(Ci.nsIUnicharLineInputStream);
-
-    var line = {value: ""};
-    var more = lis.readLine(line);
-
-    if (!more && line.value == "")
-      return;
-
-
-    // request line
-
-    var status = line.value;
-    if (status.indexOf("HTTP ") == 0)
-    {
-      status = status.substring(5);
-      var space = status.indexOf(" ");
-      var code, description;
-      if (space < 0)
-      {
-        code = status;
-        description = "";
-      }
-      else
-      {
-        code = status.substring(0, space);
-        description = status.substring(space + 1, status.length);
-      }
-    
-      response.setStatusLine(metadata.httpVersion, parseInt(code, 10), description);
-
-      line.value = "";
-      more = lis.readLine(line);
-    }
-
-    // headers
-    while (more || line.value != "")
-    {
-      var header = line.value;
-      var colon = header.indexOf(":");
-
-      response.setHeader(header.substring(0, colon),
-                         header.substring(colon + 1, header.length),
-                         false); // allow overriding server-set headers
-
-      line.value = "";
-      more = lis.readLine(line);
-    }
-  }
-  catch (e)
-  {
-    dumpn("WARNING: error in headers for " + metadata.path + ": " + e);
-    throw HTTP_500;
-  }
-  finally
-  {
-    fis.close();
-  }
-}
-
-
-/**
- * An object which handles requests for a server, executing default and
- * overridden behaviors as instructed by the code which uses and manipulates it.
- * Default behavior includes the paths / and /trace (diagnostics), with some
- * support for HTTP error pages for various codes and fallback to HTTP 500 if
- * those codes fail for any reason.
- *
- * @param server : nsHttpServer
- *   the server in which this handler is being used
- */
-function ServerHandler(server)
-{
-  // FIELDS
-
-  /**
-   * The nsHttpServer instance associated with this handler.
-   */
-  this._server = server;
-
-  /**
-   * A FileMap object containing the set of path->nsIFile mappings for
-   * all directory mappings set in the server (e.g., "/" for /var/www/html/,
-   * "/foo/bar/" for /local/path/, and "/foo/bar/baz/" for /local/path2).
-   *
-   * Note carefully: the leading and trailing "/" in each path (not file) are
-   * removed before insertion to simplify the code which uses this.  You have
-   * been warned!
-   */
-  this._pathDirectoryMap = new FileMap();
-
-  /**
-   * Custom request handlers for the server in which this resides.  Path-handler
-   * pairs are stored as property-value pairs in this property.
-   *
-   * @see ServerHandler.prototype._defaultPaths
-   */
-  this._overridePaths = {};
-
-  /**
-   * Custom request handlers for the path prefixes on the server in which this
-   * resides.  Path-handler pairs are stored as property-value pairs in this
-   * property.
-   *
-   * @see ServerHandler.prototype._defaultPaths
-   */
-  this._overridePrefixes = {};
-
-  /**
-   * Custom request handlers for the error handlers in the server in which this
-   * resides.  Path-handler pairs are stored as property-value pairs in this
-   * property.
-   *
-   * @see ServerHandler.prototype._defaultErrors
-   */
-  this._overrideErrors = {};
-
-  /**
-   * Maps file extensions to their MIME types in the server, overriding any
-   * mapping that might or might not exist in the MIME service.
-   */
-  this._mimeMappings = {};
-
-  /**
-   * The default handler for requests for directories, used to serve directories
-   * when no index file is present.
-   */
-  this._indexHandler = defaultIndexHandler;
-
-  /** Per-path state storage for the server. */
-  this._state = {};
-
-  /** Entire-server state storage. */
-  this._sharedState = {};
-
-  /** Entire-server state storage for nsISupports values. */
-  this._objectState = {};
-}
-ServerHandler.prototype =
-{
-  // PUBLIC API
-
-  /**
-   * Handles a request to this server, responding to the request appropriately
-   * and initiating server shutdown if necessary.
-   *
-   * This method never throws an exception.
-   *
-   * @param connection : Connection
-   *   the connection for this request
-   */
-  handleResponse: function(connection)
-  {
-    var request = connection.request;
-    var response = new Response(connection);
-
-    var path = request.path;
-    dumpn("*** path == " + path);
-
-    try
-    {
-      try
-      {
-        if (path in this._overridePaths)
-        {
-          // explicit paths first, then files based on existing directory mappings,
-          // then (if the file doesn't exist) built-in server default paths
-          dumpn("calling override for " + path);
-          this._overridePaths[path](request, response);
-        }
-        else
-        {
-          var longestPrefix = "";
-          for (let prefix in this._overridePrefixes) {
-            if (prefix.length > longestPrefix.length &&
-                path.substr(0, prefix.length) == prefix)
-            {
-              longestPrefix = prefix;
-            }
-          }
-          if (longestPrefix.length > 0)
-          {
-            dumpn("calling prefix override for " + longestPrefix);
-            this._overridePrefixes[longestPrefix](request, response);
-          }
-          else
-          {
-            this._handleDefault(request, response);
-          }
-        }
-      }
-      catch (e)
-      {
-        if (response.partiallySent())
-        {
-          response.abort(e);
-          return;
-        }
-
-        if (!(e instanceof HttpError))
-        {
-          dumpn("*** unexpected error: e == " + e);
-          throw HTTP_500;
-        }
-        if (e.code !== 404)
-          throw e;
-
-        dumpn("*** default: " + (path in this._defaultPaths));
-
-        response = new Response(connection);
-        if (path in this._defaultPaths)
-          this._defaultPaths[path](request, response);
-        else
-          throw HTTP_404;
-      }
-    }
-    catch (e)
-    {
-      if (response.partiallySent())
-      {
-        response.abort(e);
-        return;
-      }
-
-      var errorCode = "internal";
-
-      try
-      {
-        if (!(e instanceof HttpError))
-          throw e;
-
-        errorCode = e.code;
-        dumpn("*** errorCode == " + errorCode);
-
-        response = new Response(connection);
-        if (e.customErrorHandling)
-          e.customErrorHandling(response);
-        this._handleError(errorCode, request, response);
-        return;
-      }
-      catch (e2)
-      {
-        dumpn("*** error handling " + errorCode + " error: " +
-              "e2 == " + e2 + ", shutting down server");
-
-        connection.server._requestQuit();
-        response.abort(e2);
-        return;
-      }
-    }
-
-    response.complete();
-  },
-
-  //
-  // see nsIHttpServer.registerFile
-  //
-  registerFile: function(path, file)
-  {
-    if (!file)
-    {
-      dumpn("*** unregistering '" + path + "' mapping");
-      delete this._overridePaths[path];
-      return;
-    }
-
-    dumpn("*** registering '" + path + "' as mapping to " + file.path);
-    file = file.clone();
-
-    var self = this;
-    this._overridePaths[path] =
-      function(request, response)
-      {
-        if (!file.exists())
-          throw HTTP_404;
-
-        response.setStatusLine(request.httpVersion, 200, "OK");
-        self._writeFileResponse(request, file, response, 0, file.fileSize);
-      };
-  },
-
-  //
-  // see nsIHttpServer.registerPathHandler
-  //
-  registerPathHandler: function(path, handler)
-  {
-    // XXX true path validation!
-    if (path.charAt(0) != "/")
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    this._handlerToField(handler, this._overridePaths, path);
-  },
-
-  //
-  // see nsIHttpServer.registerPrefixHandler
-  //
-  registerPrefixHandler: function(path, handler)
-  {
-    // XXX true path validation!
-    if (path.charAt(0) != "/" || path.charAt(path.length - 1) != "/")
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    this._handlerToField(handler, this._overridePrefixes, path);
-  },
-
-  //
-  // see nsIHttpServer.registerDirectory
-  //
-  registerDirectory: function(path, directory)
-  {
-    // strip off leading and trailing '/' so that we can use lastIndexOf when
-    // determining exactly how a path maps onto a mapped directory --
-    // conditional is required here to deal with "/".substring(1, 0) being
-    // converted to "/".substring(0, 1) per the JS specification
-    var key = path.length == 1 ? "" : path.substring(1, path.length - 1);
-
-    // the path-to-directory mapping code requires that the first character not
-    // be "/", or it will go into an infinite loop
-    if (key.charAt(0) == "/")
-      throw Cr.NS_ERROR_INVALID_ARG;
-
-    key = toInternalPath(key, false);
-
-    if (directory)
-    {
-      dumpn("*** mapping '" + path + "' to the location " + directory.path);
-      this._pathDirectoryMap.put(key, directory);
-    }
-    else
-    {
-      dumpn("*** removing mapping for '" + path + "'");
-      this._pathDirectoryMap.put(key, null);
-    }
-  },
-
-  //
-  // see nsIHttpServer.registerErrorHandler
-  //
-  registerErrorHandler: function(err, handler)
-  {
-    if (!(err in HTTP_ERROR_CODES))
-      dumpn("*** WARNING: registering non-HTTP/1.1 error code " +
-            "(" + err + ") handler -- was this intentional?");
-
-    this._handlerToField(handler, this._overrideErrors, err);
-  },
-
-  //
-  // see nsIHttpServer.setIndexHandler
-  //
-  setIndexHandler: function(handler)
-  {
-    if (!handler)
-      handler = defaultIndexHandler;
-    else if (typeof(handler) != "function")
-      handler = createHandlerFunc(handler);
-
-    this._indexHandler = handler;
-  },
-
-  //
-  // see nsIHttpServer.registerContentType
-  //
-  registerContentType: function(ext, type)
-  {
-    if (!type)
-      delete this._mimeMappings[ext];
-    else
-      this._mimeMappings[ext] = headerUtils.normalizeFieldValue(type);
-  },
-
-  // PRIVATE API
-
-  /**
-   * Sets or remove (if handler is null) a handler in an object with a key.
-   *
-   * @param handler
-   *   a handler, either function or an nsIHttpRequestHandler
-   * @param dict
-   *   The object to attach the handler to.
-   * @param key
-   *   The field name of the handler.
-   */
-  _handlerToField: function(handler, dict, key)
-  {
-    // for convenience, handler can be a function if this is run from xpcshell
-    if (typeof(handler) == "function")
-      dict[key] = handler;
-    else if (handler)
-      dict[key] = createHandlerFunc(handler);
-    else
-      delete dict[key];
-  },
-
-  /**
-   * Handles a request which maps to a file in the local filesystem (if a base
-   * path has already been set; otherwise the 404 error is thrown).
-   *
-   * @param metadata : Request
-   *   metadata for the incoming request
-   * @param response : Response
-   *   an uninitialized Response to the given request, to be initialized by a
-   *   request handler
-   * @throws HTTP_###
-   *   if an HTTP error occurred (usually HTTP_404); note that in this case the
-   *   calling code must handle post-processing of the response
-   */
-  _handleDefault: function(metadata, response)
-  {
-    dumpn("*** _handleDefault()");
-
-    response.setStatusLine(metadata.httpVersion, 200, "OK");
-
-    var path = metadata.path;
-    NS_ASSERT(path.charAt(0) == "/", "invalid path: <" + path + ">");
-
-    // determine the actual on-disk file; this requires finding the deepest
-    // path-to-directory mapping in the requested URL
-    var file = this._getFileForPath(path);
-
-    // the "file" might be a directory, in which case we either serve the
-    // contained index.html or make the index handler write the response
-    if (file.exists() && file.isDirectory())
-    {
-      file.append("index.html"); // make configurable?
-      if (!file.exists() || file.isDirectory())
-      {
-        metadata._ensurePropertyBag();
-        metadata._bag.setPropertyAsInterface("directory", file.parent);
-        this._indexHandler(metadata, response);
-        return;
-      }
-    }
-
-    // alternately, the file might not exist
-    if (!file.exists())
-      throw HTTP_404;
-
-    var start, end;
-    if (metadata._httpVersion.atLeast(nsHttpVersion.HTTP_1_1) &&
-        metadata.hasHeader("Range") &&
-        this._getTypeFromFile(file) !== SJS_TYPE)
-    {
-      var rangeMatch = metadata.getHeader("Range").match(/^bytes=(\d+)?-(\d+)?$/);
-      if (!rangeMatch)
-      {
-        dumpn("*** Range header bogosity: '" + metadata.getHeader("Range") + "'");
-        throw HTTP_400;
-      }
-
-      if (rangeMatch[1] !== undefined)
-        start = parseInt(rangeMatch[1], 10);
-
-      if (rangeMatch[2] !== undefined)
-        end = parseInt(rangeMatch[2], 10);
-
-      if (start === undefined && end === undefined)
-      {
-        dumpn("*** More Range header bogosity: '" + metadata.getHeader("Range") + "'");
-        throw HTTP_400;
-      }
-
-      // No start given, so the end is really the count of bytes from the
-      // end of the file.
-      if (start === undefined)
-      {
-        start = Math.max(0, file.fileSize - end);
-        end   = file.fileSize - 1;
-      }
-
-      // start and end are inclusive
-      if (end === undefined || end >= file.fileSize)
-        end = file.fileSize - 1;
-
-      if (start !== undefined && start >= file.fileSize) {
-        var HTTP_416 = new HttpError(416, "Requested Range Not Satisfiable");
-        HTTP_416.customErrorHandling = function(errorResponse)
-        {
-          maybeAddHeaders(file, metadata, errorResponse);
-        };
-        throw HTTP_416;
-      }
-
-      if (end < start)
-      {
-        response.setStatusLine(metadata.httpVersion, 200, "OK");
-        start = 0;
-        end = file.fileSize - 1;
-      }
-      else
-      {
-        response.setStatusLine(metadata.httpVersion, 206, "Partial Content");
-        var contentRange = "bytes " + start + "-" + end + "/" + file.fileSize;
-        response.setHeader("Content-Range", contentRange);
-      }
-    }
-    else
-    {
-      start = 0;
-      end = file.fileSize - 1;
-    }
-
-    // finally...
-    dumpn("*** handling '" + path + "' as mapping to " + file.path + " from " +
-          start + " to " + end + " inclusive");
-    this._writeFileResponse(metadata, file, response, start, end - start + 1);
-  },
-
-  /**
-   * Writes an HTTP response for the given file, including setting headers for
-   * file metadata.
-   *
-   * @param metadata : Request
-   *   the Request for which a response is being generated
-   * @param file : nsIFile
-   *   the file which is to be sent in the response
-   * @param response : Response
-   *   the response to which the file should be written
-   * @param offset: uint
-   *   the byte offset to skip to when writing
-   * @param count: uint
-   *   the number of bytes to write
-   */
-  _writeFileResponse: function(metadata, file, response, offset, count)
-  {
-    const PR_RDONLY = 0x01;
-
-    var type = this._getTypeFromFile(file);
-    if (type === SJS_TYPE)
-    {
-      var fis = new FileInputStream(file, PR_RDONLY, PERMS_READONLY,
-                                    Ci.nsIFileInputStream.CLOSE_ON_EOF);
-
-      try
-      {
-        var sis = new ScriptableInputStream(fis);
-        var s = Cu.Sandbox(gGlobalObject);
-        s.importFunction(dump, "dump");
-
-        // Define a basic key-value state-preservation API across requests, with
-        // keys initially corresponding to the empty string.
-        var self = this;
-        var path = metadata.path;
-        s.importFunction(function getState(k)
-        {
-          return self._getState(path, k);
-        });
-        s.importFunction(function setState(k, v)
-        {
-          self._setState(path, k, v);
-        });
-        s.importFunction(function getSharedState(k)
-        {
-          return self._getSharedState(k);
-        });
-        s.importFunction(function setSharedState(k, v)
-        {
-          self._setSharedState(k, v);
-        });
-        s.importFunction(function getObjectState(k, callback)
-        {
-          callback(self._getObjectState(k));
-        });
-        s.importFunction(function setObjectState(k, v)
-        {
-          self._setObjectState(k, v);
-        });
-        s.importFunction(function registerPathHandler(p, h)
-        {
-          self.registerPathHandler(p, h);
-        });
-
-        // Make it possible for sjs files to access their location
-        this._setState(path, "__LOCATION__", file.path);
-
-        try
-        {
-          // Alas, the line number in errors dumped to console when calling the
-          // request handler is simply an offset from where we load the SJS file.
-          // Work around this in a reasonably non-fragile way by dynamically
-          // getting the line number where we evaluate the SJS file.  Don't
-          // separate these two lines!
-          var line = new Error().lineNumber;
-          Cu.evalInSandbox(sis.read(file.fileSize), s, "latest");
-        }
-        catch (e)
-        {
-          dumpn("*** syntax error in SJS at " + file.path + ": " + e);
-          throw HTTP_500;
-        }
-
-        try
-        {
-          s.handleRequest(metadata, response);
-        }
-        catch (e)
-        {
-          dump("*** error running SJS at " + file.path + ": " +
-               e + " on line " +
-               (e instanceof Error
-               ? e.lineNumber + " in httpd.js"
-               : (e.lineNumber - line)) + "\n");
-          throw HTTP_500;
-        }
-      }
-      finally
-      {
-        fis.close();
-      }
-    }
-    else
-    {
-      try
-      {
-        response.setHeader("Last-Modified",
-                           toDateString(file.lastModifiedTime),
-                           false);
-      }
-      catch (e) { /* lastModifiedTime threw, ignore */ }
-
-      response.setHeader("Content-Type", type, false);
-      maybeAddHeaders(file, metadata, response);
-      response.setHeader("Content-Length", "" + count, false);
-
-      var fis = new FileInputStream(file, PR_RDONLY, PERMS_READONLY,
-                                    Ci.nsIFileInputStream.CLOSE_ON_EOF);
-
-      offset = offset || 0;
-      count  = count || file.fileSize;
-      NS_ASSERT(offset === 0 || offset < file.fileSize, "bad offset");
-      NS_ASSERT(count >= 0, "bad count");
-      NS_ASSERT(offset + count <= file.fileSize, "bad total data size");
-
-      try
-      {
-        if (offset !== 0)
-        {
-          // Seek (or read, if seeking isn't supported) to the correct offset so
-          // the data sent to the client matches the requested range.
-          if (fis instanceof Ci.nsISeekableStream)
-            fis.seek(Ci.nsISeekableStream.NS_SEEK_SET, offset);
-          else
-            new ScriptableInputStream(fis).read(offset);
-        }
-      }
-      catch (e)
-      {
-        fis.close();
-        throw e;
-      }
-
-      function writeMore()
-      {
-        gThreadManager.dispatchToMainThread(writeData);
-      }
-
-      var input = new BinaryInputStream(fis);
-      var output = new BinaryOutputStream(response.bodyOutputStream);
-      var writeData =
-        {
-          run: function()
-          {
-            var chunkSize = Math.min(65536, count);
-            count -= chunkSize;
-            NS_ASSERT(count >= 0, "underflow");
-
-            try
-            {
-              var data = input.readByteArray(chunkSize);
-              NS_ASSERT(data.length === chunkSize,
-                        "incorrect data returned?  got " + data.length +
-                        ", expected " + chunkSize);
-              output.writeByteArray(data, data.length);
-              if (count === 0)
-              {
-                fis.close();
-                response.finish();
-              }
-              else
-              {
-                writeMore();
-              }
-            }
-            catch (e)
-            {
-              try
-              {
-                fis.close();
-              }
-              finally
-              {
-                response.finish();
-              }
-              throw e;
-            }
-          }
-        };
-
-      writeMore();
-
-      // Now that we know copying will start, flag the response as async.
-      response.processAsync();
-    }
-  },
-
-  /**
-   * Get the value corresponding to a given key for the given path for SJS state
-   * preservation across requests.
-   *
-   * @param path : string
-   *   the path from which the given state is to be retrieved
-   * @param k : string
-   *   the key whose corresponding value is to be returned
-   * @returns string
-   *   the corresponding value, which is initially the empty string
-   */
-  _getState: function(path, k)
-  {
-    var state = this._state;
-    if (path in state && k in state[path])
-      return state[path][k];
-    return "";
-  },
-
-  /**
-   * Set the value corresponding to a given key for the given path for SJS state
-   * preservation across requests.
-   *
-   * @param path : string
-   *   the path from which the given state is to be retrieved
-   * @param k : string
-   *   the key whose corresponding value is to be set
-   * @param v : string
-   *   the value to be set
-   */
-  _setState: function(path, k, v)
-  {
-    if (typeof v !== "string")
-      throw new Error("non-string value passed");
-    var state = this._state;
-    if (!(path in state))
-      state[path] = {};
-    state[path][k] = v;
-  },
-
-  /**
-   * Get the value corresponding to a given key for SJS state preservation
-   * across requests.
-   *
-   * @param k : string
-   *   the key whose corresponding value is to be returned
-   * @returns string
-   *   the corresponding value, which is initially the empty string
-   */
-  _getSharedState: function(k)
-  {
-    var state = this._sharedState;
-    if (k in state)
-      return state[k];
-    return "";
-  },
-
-  /**
-   * Set the value corresponding to a given key for SJS state preservation
-   * across requests.
-   *
-   * @param k : string
-   *   the key whose corresponding value is to be set
-   * @param v : string
-   *   the value to be set
-   */
-  _setSharedState: function(k, v)
-  {
-    if (typeof v !== "string")
-      throw new Error("non-string value passed");
-    this._sharedState[k] = v;
-  },
-
-  /**
-   * Returns the object associated with the given key in the server for SJS
-   * state preservation across requests.
-   *
-   * @param k : string
-   *  the key whose corresponding object is to be returned
-   * @returns nsISupports
-   *  the corresponding object, or null if none was present
-   */
-  _getObjectState: function(k)
-  {
-    if (typeof k !== "string")
-      throw new Error("non-string key passed");
-    return this._objectState[k] || null;
-  },
-
-  /**
-   * Sets the object associated with the given key in the server for SJS
-   * state preservation across requests.
-   *
-   * @param k : string
-   *  the key whose corresponding object is to be set
-   * @param v : nsISupports
-   *  the object to be associated with the given key; may be null
-   */
-  _setObjectState: function(k, v)
-  {
-    if (typeof k !== "string")
-      throw new Error("non-string key passed");
-    if (typeof v !== "object")
-      throw new Error("non-object value passed");
-    if (v && !("QueryInterface" in v))
-    {
-      throw new Error("must pass an nsISupports; use wrappedJSObject to ease " +
-                      "pain when using the server from JS");
-    }
-
-    this._objectState[k] = v;
-  },
-
-  /**
-   * Gets a content-type for the given file, first by checking for any custom
-   * MIME-types registered with this handler for the file's extension, second by
-   * asking the global MIME service for a content-type, and finally by failing
-   * over to application/octet-stream.
-   *
-   * @param file : nsIFile
-   *   the nsIFile for which to get a file type
-   * @returns string
-   *   the best content-type which can be determined for the file
-   */
-  _getTypeFromFile: function(file)
-  {
-    try
-    {
-      var name = file.leafName;
-      var dot = name.lastIndexOf(".");
-      if (dot > 0)
-      {
-        var ext = name.slice(dot + 1);
-        if (ext in this._mimeMappings)
-          return this._mimeMappings[ext];
-      }
-      return Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
-               .getService(Ci.nsIMIMEService)
-               .getTypeFromFile(file);
-    }
-    catch (e)
-    {
-      return "application/octet-stream";
-    }
-  },
-
-  /**
-   * Returns the nsIFile which corresponds to the path, as determined using
-   * all registered path->directory mappings and any paths which are explicitly
-   * overridden.
-   *
-   * @param path : string
-   *   the server path for which a file should be retrieved, e.g. "/foo/bar"
-   * @throws HttpError
-   *   when the correct action is the corresponding HTTP error (i.e., because no
-   *   mapping was found for a directory in path, the referenced file doesn't
-   *   exist, etc.)
-   * @returns nsIFile
-   *   the file to be sent as the response to a request for the path
-   */
-  _getFileForPath: function(path)
-  {
-    // decode and add underscores as necessary
-    try
-    {
-      path = toInternalPath(path, true);
-    }
-    catch (e)
-    {
-      dumpn("*** toInternalPath threw " + e);
-      throw HTTP_400; // malformed path
-    }
-
-    // next, get the directory which contains this path
-    var pathMap = this._pathDirectoryMap;
-
-    // An example progression of tmp for a path "/foo/bar/baz/" might be:
-    // "foo/bar/baz/", "foo/bar/baz", "foo/bar", "foo", ""
-    var tmp = path.substring(1);
-    while (true)
-    {
-      // do we have a match for current head of the path?
-      var file = pathMap.get(tmp);
-      if (file)
-      {
-        // XXX hack; basically disable showing mapping for /foo/bar/ when the
-        //     requested path was /foo/bar, because relative links on the page
-        //     will all be incorrect -- we really need the ability to easily
-        //     redirect here instead
-        if (tmp == path.substring(1) &&
-            tmp.length != 0 &&
-            tmp.charAt(tmp.length - 1) != "/")
-          file = null;
-        else
-          break;
-      }
-
-      // if we've finished trying all prefixes, exit
-      if (tmp == "")
-        break;
-
-      tmp = tmp.substring(0, tmp.lastIndexOf("/"));
-    }
-
-    // no mapping applies, so 404
-    if (!file)
-      throw HTTP_404;
-
-
-    // last, get the file for the path within the determined directory
-    var parentFolder = file.parent;
-    var dirIsRoot = (parentFolder == null);
-
-    // Strategy here is to append components individually, making sure we
-    // never move above the given directory; this allows paths such as
-    // "<file>/foo/../bar" but prevents paths such as "<file>/../base-sibling";
-    // this component-wise approach also means the code works even on platforms
-    // which don't use "/" as the directory separator, such as Windows
-    var leafPath = path.substring(tmp.length + 1);
-    var comps = leafPath.split("/");
-    for (var i = 0, sz = comps.length; i < sz; i++)
-    {
-      var comp = comps[i];
-
-      if (comp == "..")
-        file = file.parent;
-      else if (comp == "." || comp == "")
-        continue;
-      else
-        file.append(comp);
-
-      if (!dirIsRoot && file.equals(parentFolder))
-        throw HTTP_403;
-    }
-
-    return file;
-  },
-
-  /**
-   * Writes the error page for the given HTTP error code over the given
-   * connection.
-   *
-   * @param errorCode : uint
-   *   the HTTP error code to be used
-   * @param connection : Connection
-   *   the connection on which the error occurred
-   */
-  handleError: function(errorCode, connection)
-  {
-    var response = new Response(connection);
-
-    dumpn("*** error in request: " + errorCode);
-
-    this._handleError(errorCode, new Request(connection.port), response);
-  }, 
-
-  /**
-   * Handles a request which generates the given error code, using the
-   * user-defined error handler if one has been set, gracefully falling back to
-   * the x00 status code if the code has no handler, and failing to status code
-   * 500 if all else fails.
-   *
-   * @param errorCode : uint
-   *   the HTTP error which is to be returned
-   * @param metadata : Request
-   *   metadata for the request, which will often be incomplete since this is an
-   *   error
-   * @param response : Response
-   *   an uninitialized Response should be initialized when this method
-   *   completes with information which represents the desired error code in the
-   *   ideal case or a fallback code in abnormal circumstances (i.e., 500 is a
-   *   fallback for 505, per HTTP specs)
-   */
-  _handleError: function(errorCode, metadata, response)
-  {
-    if (!metadata)
-      throw Cr.NS_ERROR_NULL_POINTER;
-
-    var errorX00 = errorCode - (errorCode % 100);
-
-    try
-    {
-      if (!(errorCode in HTTP_ERROR_CODES))
-        dumpn("*** WARNING: requested invalid error: " + errorCode);
-
-      // RFC 2616 says that we should try to handle an error by its class if we
-      // can't otherwise handle it -- if that fails, we revert to handling it as
-      // a 500 internal server error, and if that fails we throw and shut down
-      // the server
-
-      // actually handle the error
-      try
-      {
-        if (errorCode in this._overrideErrors)
-          this._overrideErrors[errorCode](metadata, response);
-        else
-          this._defaultErrors[errorCode](metadata, response);
-      }
-      catch (e)
-      {
-        if (response.partiallySent())
-        {
-          response.abort(e);
-          return;
-        }
-
-        // don't retry the handler that threw
-        if (errorX00 == errorCode)
-          throw HTTP_500;
-
-        dumpn("*** error in handling for error code " + errorCode + ", " +
-              "falling back to " + errorX00 + "...");
-        response = new Response(response._connection);
-        if (errorX00 in this._overrideErrors)
-          this._overrideErrors[errorX00](metadata, response);
-        else if (errorX00 in this._defaultErrors)
-          this._defaultErrors[errorX00](metadata, response);
-        else
-          throw HTTP_500;
-      }
-    }
-    catch (e)
-    {
-      if (response.partiallySent())
-      {
-        response.abort();
-        return;
-      }
-
-      // we've tried everything possible for a meaningful error -- now try 500
-      dumpn("*** error in handling for error code " + errorX00 + ", falling " +
-            "back to 500...");
-
-      try
-      {
-        response = new Response(response._connection);
-        if (500 in this._overrideErrors)
-          this._overrideErrors[500](metadata, response);
-        else
-          this._defaultErrors[500](metadata, response);
-      }
-      catch (e2)
-      {
-        dumpn("*** multiple errors in default error handlers!");
-        dumpn("*** e == " + e + ", e2 == " + e2);
-        response.abort(e2);
-        return;
-      }
-    }
-
-    response.complete();
-  },
-
-  // FIELDS
-
-  /**
-   * This object contains the default handlers for the various HTTP error codes.
-   */
-  _defaultErrors:
-  {
-    400: function(metadata, response)
-    {