Bug 1415957 - Remove MozMill from TPS. r=tcsc
authorEdouard Oger <eoger@fastmail.com>
Thu, 09 Nov 2017 15:34:06 -0500
changeset 444364 c60bbbbc53d3b798cec0b578ea3c4b7e41f720bd
parent 444363 6fe2a24e51cad359aa5d42f8792b434f61a38bb6
child 444365 0489e522ece134137434a449539228dad4849678
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcsc
bugs1415957
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
-
-      //