Bug 1446676: Part 2 - Update non-overlay automation extensions to be bootstrapped. r?Mossop draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 16 Mar 2018 22:06:22 -0700
changeset 769183 f6a86f4ef76a23306d58123018dad41bdcd39f88
parent 769182 eef52b4947f3b601a708115c6b3256fb6865d52f
child 769184 788710ae8f01a24843db73e4c9b5d6d19e7cfc1d
push id103061
push usermaglione.k@gmail.com
push dateSun, 18 Mar 2018 22:05:48 +0000
reviewersMossop
bugs1446676
milestone61.0a1
Bug 1446676: Part 2 - Update non-overlay automation extensions to be bootstrapped. r?Mossop In order to remove support for non-bootstrapped extensions, the remaining test automation extensions need to be migrated to bootstrapped extensions. These extensions all work by loading a single component, either with a profile-after-change or command line handler. This is a straightforward conversion of those components to bootstrap.js scripts. MozReview-Commit-ID: 5uyNSqRPIVR
services/sync/tps/extensions/tps/bootstrap.js
services/sync/tps/extensions/tps/chrome.manifest
services/sync/tps/extensions/tps/components/tps-cmdline.js
services/sync/tps/extensions/tps/install.rdf
testing/talos/talos/pageloader/bootstrap.js
testing/talos/talos/pageloader/chrome.manifest
testing/talos/talos/pageloader/components/tp-cmdline.js
testing/talos/talos/pageloader/install.rdf
testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
testing/talos/talos/talos-powers/bootstrap.js
testing/talos/talos/talos-powers/chrome.manifest
testing/talos/talos/talos-powers/components/TalosPowersService.js
testing/talos/talos/talos-powers/install.rdf
tools/quitter/QuitterObserver.js
tools/quitter/bootstrap.js
tools/quitter/chrome.manifest
tools/quitter/install.rdf
tools/quitter/moz.build
tools/quitter/quitter@mozilla.org.xpi
rename from services/sync/tps/extensions/tps/components/tps-cmdline.js
rename to services/sync/tps/extensions/tps/bootstrap.js
--- a/services/sync/tps/extensions/tps/components/tps-cmdline.js
+++ b/services/sync/tps/extensions/tps/bootstrap.js
@@ -1,40 +1,52 @@
 /* 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/. */
 
-const TPS_ID                         = "tps@mozilla.org";
-const TPS_CMDLINE_CONTRACTID         = "@mozilla.org/commandlinehandler/general-startup;1?type=tps";
-const TPS_CMDLINE_CLSID              = Components.ID("{4e5bd3f0-41d3-11df-9879-0800200c9a66}");
-const CATMAN_CONTRACTID              = "@mozilla.org/categorymanager;1";
-const nsISupports                    = Ci.nsISupports;
-
-const nsICategoryManager             = Ci.nsICategoryManager;
-const nsICmdLineHandler              = Ci.nsICmdLineHandler;
-const nsICommandLine                 = Ci.nsICommandLine;
-const nsICommandLineHandler          = Ci.nsICommandLineHandler;
-const nsIComponentRegistrar          = Ci.nsIComponentRegistrar;
-const nsISupportsString              = Ci.nsISupportsString;
-const nsIWindowWatcher               = Ci.nsIWindowWatcher;
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/osfile.jsm");
 
-function TPSCmdLineHandler() {}
+XPCOMUtils.defineLazyServiceGetter(this, "categoryManager",
+                                   "@mozilla.org/categorymanager;1",
+                                   "nsICategoryManager");
+
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
+
+const CATEGORY_NAME = "command-line-handler";
+const CATEGORY_ENTRY = "m-tps";
+
+function TPSCmdLine() {}
 
-TPSCmdLineHandler.prototype = {
-  classDescription: "TPSCmdLineHandler",
-  classID: TPS_CMDLINE_CLSID,
-  contractID: TPS_CMDLINE_CONTRACTID,
+TPSCmdLine.prototype = {
+  factory: XPCOMUtils._getFactory(TPSCmdLine),
+  classDescription: "TPSCmdLine",
+  classID: Components.ID("{4e5bd3f0-41d3-11df-9879-0800200c9a66}"),
+  contractID: "@mozilla.org/commandlinehandler/general-startup;1?type=tps",
+
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 
-  QueryInterface: XPCOMUtils.generateQI([nsISupports,
-                                         nsICommandLineHandler,
-                                         nsICmdLineHandler]),   /* nsISupports */
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
+
+    categoryManager.addCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                     this.contractID, false, true);
+  },
+
+  unregister() {
+    categoryManager.deleteCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                        this.contractID, false);
+
+    Cm.unregisterFactory(this.classID, this.factory);
+  },
 
   /* nsICmdLineHandler */
   commandLineArgument: "-tps",
   prefNameForStartup: "general.startup.tps",
   helpText: "Run TPS tests with the given test file.",
   handlesArgs: true,
   defaultArgs: "",
   openWindowWithArgs: true,
@@ -70,78 +82,18 @@ TPSCmdLineHandler.prototype = {
   },
 
   helpInfo: "  --tps <file>              Run TPS tests with the given test file.\n" +
             "  --tpsphase <phase>        Run the specified phase in the TPS test.\n" +
             "  --tpslogfile <file>       Logfile for TPS output.\n" +
             "  --ignore-unused-engines   Don't load engines not used in tests.\n",
 };
 
-
-var TPSCmdLineFactory = {
-  createInstance(outer, iid) {
-    if (outer != null) {
-      throw new Error(Cr.NS_ERROR_NO_AGGREGATION);
-    }
-
-    return new TPSCmdLineHandler().QueryInterface(iid);
-  }
-};
-
-
-var TPSCmdLineModule = {
-  registerSelf(compMgr, fileSpec, location, type) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.registerFactoryLocation(TPS_CMDLINE_CLSID,
-                                    "TPS CommandLine Service",
-                                    TPS_CMDLINE_CONTRACTID,
-                                    fileSpec,
-                                    location,
-                                    type);
-
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.addCategoryEntry("command-line-argument-handlers",
-                            "TPS command line handler",
-                            TPS_CMDLINE_CONTRACTID, true, true);
-    catman.addCategoryEntry("command-line-handler",
-                            "m-tps",
-                            TPS_CMDLINE_CONTRACTID, true, true);
-  },
-
-  unregisterSelf(compMgr, fileSpec, location) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
+function startup(data, reason) {
+  TPSCmdLine.prototype.register();
+}
 
-    compMgr.unregisterFactoryLocation(TPS_CMDLINE_CLSID, fileSpec);
-    let catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.deleteCategoryEntry("command-line-argument-handlers",
-                               "TPS command line handler", true);
-    catman.deleteCategoryEntry("command-line-handler",
-                               "m-tps", true);
-  },
-
-  getClassObject(compMgr, cid, iid) {
-    if (cid.equals(TPS_CMDLINE_CLSID)) {
-      return TPSCmdLineFactory;
-    }
-
-    if (!iid.equals(Ci.nsIFactory)) {
-      throw new Error(Cr.NS_ERROR_NOT_IMPLEMENTED);
-    }
+function shutdown(data, reason) {
+  TPSCmdLine.prototype.unregister();
+}
 
-    throw new Error(Cr.NS_ERROR_NO_INTERFACE);
-  },
-
-  canUnload(compMgr) {
-    return true;
-  }
-};
-
-/**
-* XPCOMUtils.generateNSGetFactory was introduced in Mozilla 2 (Firefox 4).
-* XPCOMUtils.generateNSGetModule is for Mozilla 1.9.2 (Firefox 3.6).
-*/
-if (XPCOMUtils.generateNSGetFactory)
-    var NSGetFactory = XPCOMUtils.generateNSGetFactory([TPSCmdLineHandler]);
-
-function NSGetModule(compMgr, fileSpec) {
-  return TPSCmdLineModule;
-}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/services/sync/tps/extensions/tps/chrome.manifest
+++ b/services/sync/tps/extensions/tps/chrome.manifest
@@ -1,5 +1,1 @@
 resource tps resource/
-
-component {4e5bd3f0-41d3-11df-9879-0800200c9a66} components/tps-cmdline.js
-contract @mozilla.org/commandlinehandler/general-startup;1?type=tps {4e5bd3f0-41d3-11df-9879-0800200c9a66}
-category command-line-handler m-tps @mozilla.org/commandlinehandler/general-startup;1?type=tps
--- a/services/sync/tps/extensions/tps/install.rdf
+++ b/services/sync/tps/extensions/tps/install.rdf
@@ -3,16 +3,17 @@
    - 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/. -->
 
 <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>tps@mozilla.org</em:id>
     <em:version>0.5</em:version>
+    <em:bootstrap>true</em:bootstrap>
 
     <em:targetApplication>
       <!-- Firefox -->
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>24.0.*</em:minVersion>
         <em:maxVersion>31.0.*</em:maxVersion>
       </Description>
rename from testing/talos/talos/pageloader/components/tp-cmdline.js
rename to testing/talos/talos/pageloader/bootstrap.js
--- a/testing/talos/talos/pageloader/components/tp-cmdline.js
+++ b/testing/talos/talos/pageloader/bootstrap.js
@@ -35,42 +35,52 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // This only implements nsICommandLineHandler, since it needs
 // to handle multiple arguments.
 
-const TP_CMDLINE_CONTRACTID     = "@mozilla.org/commandlinehandler/general-startup;1?type=tp";
-const TP_CMDLINE_CLSID          = Components.ID("{8AF052F5-8EFE-4359-8266-E16498A82E8B}");
-const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
-const nsISupports               = Ci.nsISupports;
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "categoryManager",
+                                   "@mozilla.org/categorymanager;1",
+                                   "nsICategoryManager");
 
-const nsICategoryManager        = Ci.nsICategoryManager;
-const nsICommandLine            = Ci.nsICommandLine;
-const nsICommandLineHandler     = Ci.nsICommandLineHandler;
-const nsIComponentRegistrar     = Ci.nsIComponentRegistrar;
-const nsISupportsString         = Ci.nsISupportsString;
-const nsIWindowWatcher          = Ci.nsIWindowWatcher;
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
+const CATMAN_CONTRACTID         = "@mozilla.org/categorymanager;1";
+
+const CATEGORY_NAME = "command-line-handler";
+const CATEGORY_ENTRY = "m-tp";
 
-ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-function PageLoaderCmdLineHandler() {}
-PageLoaderCmdLineHandler.prototype =
+function PageLoaderCmdLine() {}
+PageLoaderCmdLine.prototype =
 {
-  /* nsISupports */
-  QueryInterface: function handler_QI(iid) {
-    if (iid.equals(nsISupports))
-      return this;
+  factory: XPCOMUtils._getFactory(PageLoaderCmdLine),
+  classDescription: "Loads pages. Tests them.",
+  classID:          Components.ID("{8AF052F5-8EFE-4359-8266-E16498A82E8B}"),
+  contractID:       "@mozilla.org/commandlinehandler/general-startup;1?type=tp",
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
+
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
 
-    if (nsICommandLineHandler && iid.equals(nsICommandLineHandler))
-      return this;
+    categoryManager.addCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                     this.contractID, false, true);
+  },
 
-    throw Cr.NS_ERROR_NO_INTERFACE;
+  unregister() {
+    categoryManager.deleteCategoryEntry(CATEGORY_NAME, CATEGORY_ENTRY,
+                                        this.contractID, false);
+
+    Cm.unregisterFactory(this.classID, this.factory);
   },
 
   /* nsICommandLineHandler */
   handle: function handler_handle(cmdLine) {
     var args = {};
 
     var tpmanifest = Services.prefs.getCharPref("talos.tpmanifest", null);
     if (tpmanifest == null) {
@@ -88,67 +98,18 @@ PageLoaderCmdLineHandler.prototype =
     Services.ww.openWindow(null, chromeURL, "_blank",
                             "chrome,dialog=no,all", args);
 
     // Don't pass command line to the default app processor
     cmdLine.preventDefault = true;
   },
 };
 
-
-var PageLoaderCmdLineFactory =
-{
-  createInstance(outer, iid) {
-    if (outer != null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-
-    return new PageLoaderCmdLineHandler().QueryInterface(iid);
-  }
-};
-
-function NSGetFactory(cid) {
-  if (!cid.equals(TP_CMDLINE_CLSID))
-    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
-
-  return PageLoaderCmdLineFactory;
+function startup(data, reason) {
+  PageLoaderCmdLine.prototype.register();
 }
 
-var PageLoaderCmdLineModule =
-{
-  registerSelf(compMgr, fileSpec, location, type) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.registerFactoryLocation(TP_CMDLINE_CLSID,
-                                    "PageLoader CommandLine Service",
-                                    TP_CMDLINE_CONTRACTID,
-                                    fileSpec,
-                                    location,
-                                    type);
-
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.addCategoryEntry("command-line-handler",
-                            "m-tp",
-                            TP_CMDLINE_CONTRACTID, true, true);
-  },
+function shutdown(data, reason) {
+  PageLoaderCmdLine.prototype.unregister();
+}
 
-  unregisterSelf(compMgr, fileSpec, location) {
-    compMgr = compMgr.QueryInterface(nsIComponentRegistrar);
-
-    compMgr.unregisterFactoryLocation(TP_CMDLINE_CLSID, fileSpec);
-    var catman = Cc[CATMAN_CONTRACTID].getService(nsICategoryManager);
-    catman.deleteCategoryEntry("command-line-handler",
-                               "m-tp", true);
-  },
-
-  getClassObject(compMgr, cid, iid) {
-    return NSGetFactory(cid);
-  },
-
-  canUnload(compMgr) {
-    return true;
-  }
-};
-
-
-function NSGetModule(compMgr, fileSpec) {
-  return PageLoaderCmdLineModule;
-}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/pageloader/chrome.manifest
+++ b/testing/talos/talos/pageloader/chrome.manifest
@@ -1,4 +1,1 @@
 content pageloader chrome/
-component {8AF052F5-8EFE-4359-8266-E16498A82E8B} components/tp-cmdline.js
-contract @mozilla.org/commandlinehandler/general-startup;1?type=tp {8AF052F5-8EFE-4359-8266-E16498A82E8B}
-category command-line-handler m-tp @mozilla.org/commandlinehandler/general-startup;1?type=tp
--- a/testing/talos/talos/pageloader/install.rdf
+++ b/testing/talos/talos/pageloader/install.rdf
@@ -1,15 +1,16 @@
 <?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>pageloader@mozilla.org</em:id>
     <em:version>1.0.32</em:version>
+    <em:bootstrap>true</em:bootstrap>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
rename from testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
rename to testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
--- a/testing/talos/talos/startup_test/sessionrestore/addon/SessionRestoreTalosTest.js
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/bootstrap.js
@@ -11,43 +11,30 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "setTimeout",
   "resource://gre/modules/Timer.jsm");
 ChromeUtils.defineModuleGetter(this, "StartupPerformance",
   "resource:///modules/sessionstore/StartupPerformance.jsm");
 
 // Observer Service topics.
-const STARTUP_TOPIC = "profile-after-change";
 const WINDOW_READY_TOPIC = "browser-delayed-startup-finished";
 
 // Process Message Manager topics.
 const MSG_REQUEST = "session-restore-test?duration";
 const MSG_PROVIDE = "session-restore-test:duration";
 
-function nsSessionRestoreTalosTest() { }
-
-nsSessionRestoreTalosTest.prototype = {
-  classID: Components.ID("{716346e5-0c45-4aa2-b601-da36f3c74bd8}"),
-
-  _xpcom_factory: XPCOMUtils.generateSingletonFactory(nsSessionRestoreTalosTest),
-
-  // ////////////////////////////////////////////////////////////////////////////
-  // // nsISupports
-
+const sessionRestoreTest = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   // ////////////////////////////////////////////////////////////////////////////
   // // nsIObserver
 
   observe: function DS_observe(aSubject, aTopic, aData) {
     switch (aTopic) {
-      case STARTUP_TOPIC:
-        this.init();
-        break;
       case StartupPerformance.RESTORED_TOPIC:
         this.onReady(true);
         break;
       case WINDOW_READY_TOPIC:
         Services.obs.removeObserver(this, WINDOW_READY_TOPIC);
         this.onWindow(aSubject);
         break;
       default:
@@ -142,12 +129,16 @@ nsSessionRestoreTalosTest.prototype = {
       let url = new URL(args.queryElementAt(0, Ci.nsISupportsString).data);
       queryString = url.search;
     }
 
     win.gBrowser.addTab("chrome://session-restore-test/content/index.html" + queryString);
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // Module
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSessionRestoreTalosTest]);
+function startup(data, reason) {
+  sessionRestoreTest.init();
+}
+
+function shutdown(data, reason) {}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/chrome.manifest
@@ -1,8 +1,1 @@
-# Register a component to be informed of startup. This component can then register
-# itself to watch sessionstore-windows-restored. Once it has observed
-# sessionstore-windows-restored, it will open the webpage with the harness.
-component {716346e5-0c45-4aa2-b601-da36f3c74bd8} SessionRestoreTalosTest.js
-contract @mozilla.org/talos/session-restore-test;1 {716346e5-0c45-4aa2-b601-da36f3c74bd8}
-category profile-after-change nsSessionRestoreTalosTest @mozilla.org/talos/session-restore-test;1
-
 content session-restore-test content/
--- a/testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
+++ b/testing/talos/talos/startup_test/sessionrestore/addon/install.rdf
@@ -1,14 +1,15 @@
 <?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">
 
 <!-- Required Items -->
 <em:id>session-restore-test-2@mozilla.org</em:id>
 <em:name>Session Restore Startup Performance Test</em:name>
 <em:version>2.0.11</em:version>
+<em:bootstrap>true</em:bootstrap>
 
 <em:targetApplication>
     <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>1.5</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
     </Description>
 </em:targetApplication>
rename from testing/talos/talos/talos-powers/components/TalosPowersService.js
rename to testing/talos/talos/talos-powers/bootstrap.js
--- a/testing/talos/talos/talos-powers/components/TalosPowersService.js
+++ b/testing/talos/talos/talos-powers/bootstrap.js
@@ -3,53 +3,51 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "OS",
   "resource://gre/modules/osfile.jsm");
 
+const Cm = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+
 const FRAME_SCRIPT = "chrome://talos-powers/content/talos-powers-content.js";
 
 function TalosPowersService() {
   this.wrappedJSObject = this;
+
+  this.init();
 }
 
 TalosPowersService.prototype = {
+  factory: XPCOMUtils._getFactory(TalosPowersService),
   classDescription: "Talos Powers",
   classID: Components.ID("{f5d53443-d58d-4a2f-8df0-98525d4f91ad}"),
   contractID: "@mozilla.org/talos/talos-powers-service;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
+  QueryInterface: XPCOMUtils.generateQI([]),
+
+  register() {
+    Cm.registerFactory(this.classID, this.classDescription,
+                       this.contractID, this.factory);
 
-  observe(subject, topic, data) {
-    switch (topic) {
-      case "profile-after-change":
-        // Note that this observation is registered in the chrome.manifest
-        // for this add-on.
-        this.init();
-        break;
-      case "xpcom-shutdown":
-        this.uninit();
-        break;
-    }
+    void Cc[this.contractID].getService();
+  },
+
+  unregister() {
+    Cm.unregisterFactory(this.classID, this.factory);
   },
 
   init() {
     Services.mm.loadFrameScript(FRAME_SCRIPT, true);
     Services.mm.addMessageListener("Talos:ForceQuit", this);
     Services.mm.addMessageListener("TalosContentProfiler:Command", this);
     Services.mm.addMessageListener("TalosPowersContent:ForceCCAndGC", this);
     Services.mm.addMessageListener("TalosPowersContent:GetStartupInfo", this);
     Services.mm.addMessageListener("TalosPowers:ParentExec:QueryMsg", this);
-    Services.obs.addObserver(this, "xpcom-shutdown");
-  },
-
-  uninit() {
-    Services.obs.removeObserver(this, "xpcom-shutdown");
   },
 
   receiveMessage(message) {
     switch (message.name) {
       case "Talos:ForceQuit": {
         this.forceQuit(message.data);
         break;
       }
@@ -322,9 +320,17 @@ TalosPowersService.prototype = {
     if (!this.ParentExecServices.hasOwnProperty(command.name))
       throw new Error("TalosPowers:ParentExec: Invalid service '" + command.name + "'");
 
     this.ParentExecServices[command.name](command.data, sendResult, msg.target.ownerGlobal);
   },
 
 };
 
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TalosPowersService]);
+function startup(data, reason) {
+  TalosPowersService.prototype.register();
+}
+
+function shutdown(data, reason) {
+  TalosPowersService.prototype.unregister();
+}
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/testing/talos/talos/talos-powers/chrome.manifest
+++ b/testing/talos/talos/talos-powers/chrome.manifest
@@ -1,5 +1,2 @@
 content talos-powers chrome/
 content talos-powers-content content/ contentaccessible=yes
-component {f5d53443-d58d-4a2f-8df0-98525d4f91ad} components/TalosPowersService.js
-contract @mozilla.org/talos/talos-powers-service;1 {f5d53443-d58d-4a2f-8df0-98525d4f91ad}
-category profile-after-change TalosPowersService @mozilla.org/talos/talos-powers-service;1
--- a/testing/talos/talos/talos-powers/install.rdf
+++ b/testing/talos/talos/talos-powers/install.rdf
@@ -1,15 +1,16 @@
 <?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>talos-powers@mozilla.org</em:id>
     <em:version>1.0.14</em:version>
+    <em:bootstrap>true</em:bootstrap>
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>44.0</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <!-- Front End MetaData -->
rename from tools/quitter/QuitterObserver.js
rename to tools/quitter/bootstrap.js
--- a/tools/quitter/QuitterObserver.js
+++ b/tools/quitter/bootstrap.js
@@ -1,63 +1,43 @@
 /* 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/. */
 
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 
 const CHILD_SCRIPT = "chrome://quitter/content/contentscript.js";
 
-/* XPCOM gunk */
-function QuitterObserver() {}
-
-QuitterObserver.prototype = {
-  classDescription: "Quitter Observer for use in testing.",
-  classID:          Components.ID("{c235a986-5ac1-4f28-ad73-825dae9bad90}"),
-  contractID:       "@mozilla.org/quitter-observer;1",
-  QueryInterface:   XPCOMUtils.generateQI([Ci.nsIObserver]),
-  _xpcom_categories: [{category: "profile-after-change", service: true }],
-  isFrameScriptLoaded: false,
-
-  observe(aSubject, aTopic, aData) {
-    if (aTopic == "profile-after-change") {
-      this.init();
-    } else if (!this.isFrameScriptLoaded &&
-               aTopic == "chrome-document-global-created") {
-
-      var messageManager = Cc["@mozilla.org/globalmessagemanager;1"].
-                           getService(Ci.nsIMessageBroadcaster);
-      // Register for any messages our API needs us to handle
-      messageManager.addMessageListener("Quitter.Quit", this);
-
-      messageManager.loadFrameScript(CHILD_SCRIPT, true);
-      this.isFrameScriptLoaded = true;
-    } else if (aTopic == "xpcom-shutdown") {
-      this.uninit();
-    }
-  },
-
+const quitterObserver = {
   init() {
-    var obs = Services.obs;
-    obs.addObserver(this, "xpcom-shutdown");
-    obs.addObserver(this, "chrome-document-global-created");
+    Services.mm.addMessageListener("Quitter.Quit", this);
+    Services.mm.loadFrameScript(CHILD_SCRIPT, true);
   },
 
   uninit() {
-    var obs = Services.obs;
-    obs.removeObserver(this, "chrome-document-global-created");
+    Services.obs.removeObserver(this, "chrome-document-global-created");
+    Services.mm.removeMessageListener("Quitter.Quit", this);
+    Services.mm.removeDelayedFrameScript(CHILD_SCRIPT, true);
   },
 
   /**
    * messageManager callback function
    * This will get requests from our API in the window and process them in chrome for it
    **/
   receiveMessage(aMessage) {
     switch (aMessage.name) {
       case "Quitter.Quit":
         Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
         break;
     }
   }
 };
 
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([QuitterObserver]);
+function startup(data, reason) {
+  quitterObserver.init();
+}
+
+function shutdown(data, reason) {
+  quitterObserver.uninit();
+}
+
+function install(data, reason) {}
+function uninstall(data, reason) {}
--- a/tools/quitter/chrome.manifest
+++ b/tools/quitter/chrome.manifest
@@ -1,4 +1,1 @@
-category profile-after-change @mozilla.org/quitter-observer;1 @mozilla.org/quitter-observer;1
-component {c235a986-5ac1-4f28-ad73-825dae9bad90} components/QuitterObserver.js
 content quitter chrome/quitter/content/
-contract @mozilla.org/quitter-observer;1 {c235a986-5ac1-4f28-ad73-825dae9bad90}
--- a/tools/quitter/install.rdf
+++ b/tools/quitter/install.rdf
@@ -1,17 +1,18 @@
 <?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>quitter@mozilla.org</em:id>
-    <em:version>2016.03.10</em:version>
+    <em:version>2018.03.19</em:version>
     <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
 
     <!-- Target Application this extension can install into,
          with minimum and maximum supported versions. -->
     <em:targetApplication>
       <Description>
         <!-- Firefox -->
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
         <em:minVersion>45.0</em:minVersion>
--- a/tools/quitter/moz.build
+++ b/tools/quitter/moz.build
@@ -1,21 +1,18 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-EXTRA_COMPONENTS += [
-    'QuitterObserver.js',
-]
-
 XPI_NAME = 'quitter'
 
 JAR_MANIFESTS += ['jar.mn']
 
 USE_EXTENSION_MANIFEST = True
 NO_JS_MANIFEST = True
 
 FINAL_TARGET_FILES += [
+    'bootstrap.js',
     'chrome.manifest',
     'install.rdf',
 ]
index 5d2c0ef6e00658aaef22a5d7ea130f8bf87c8872..9db483065e9639d0eeee270bad7bec356e6ee978
GIT binary patch
literal 7355
zc$}SC1y~ztw+<GHyF+mrq`12kC{WxzxJw95@!|!FJCxD_1qy`X?!~=9+5*Mht=Oga
z-+%k>-rf7$y=OAdmy=}P_sry-bIv!Pni3K+Apih)0B|dZC|}%8au8tw0Cu<lz|T*g
zJ<*bS{8UAb!^y?h&e0Lf4si!h>-q>zInDFOkj2)36U7`-mjpi3DuL)^Q(-Aw{i$SN
z1|{w@ja0{3FBs#MN%+n<ou%%ftSv0;=-}u?OjT_E{Ner;+{?f3YGMD{82+3Z?m>0#
zW73C~pigCXf)6h0;?IzDbtTT2Mx?3EMGBQ9^#x$RNwEwMY5;VP5~>krxM9#t)*@Ld
zJS9fPL=4>&^o|$T?f1jS;=D;gH7|UN5Q5J2Am|~GE21;O%v}=`r`-cUnxG(4P;oq6
zDv01z5Fs*-w7#m$U}gz8ks=Hxyy1Co=dIH|6Y8B2CZT}K>EX#BNI;3AOeNZ!bBIl<
zE_tyCK<?kZqz~x>7rLc!5TNBwI7@s;VDc3-k3+l;oPL5MP1PuUatLkDyWl}lg(6*G
z^MEUZD1odouhNo|>gFN_+9cbr_FrD(<jaKA@Nt2HZUF7Cl*485J22LjaVuRt>*K()
z)P2-nJ9+Pl(L#}D0(d_iRF_EDAcAF0=!N`zguJsa-a>;giLX71X$;68kPS&!-{m1F
z14C_DXp7jD`HnPA1p6PJD>Qi**!xa&L^f%rz#Hz2tjCj{S!ya?rb<-9xHb5XwpMsk
zo^%E-4aq!3!qc_h24e<mQyV&^_&Dn;=6yFNRVES<@sM@8R&rFThz;w5WVe2t*-&d?
z^gA)DOcK{$srFWj@>*wg+S0ITGyobp?nduG2XDw*9Z6nsrn*$mO`v@a&s+SC_S`)l
zd1L{`Z}G#43C-{IiTSCsr=PN_Ep0@Q_-M=4w!kid#)>?Tw<jzUy;K}HS{49`7g%+!
z6XZQ+Fw#R|mDfu!{b&VVIWuALdz1Yw=tx~zA=Z1SoQ`2^VuEQ3y4ft7V=K9Coce8K
z)0G91C^W}$T+8%=-p|`cthW+QM7Zkt%-aI-;h?*nCu~4ag>>5MEp7a1ed<Vbu+mLV
zLPNy1)=S^i;&}|;SJ4s0Jy>}adu0scX_j@N>9)+ZHZwL($bAWN{HBC{I93zch&9FQ
z?%UR}WiukZpVCK{lb6Np>>I?mlGpt+E420C3Z;(q&q8}BKNn;tYiSmJXsz3=D+}za
z(Bx5+#?^4SJXGn4SPqM*PBZ{RHEoy0+!o9RIhd@!Mx!^UjZ+R$EH!2BPOPurP$ZGy
zjp3UQaDipmU(OUr6C5ti;R^U^HvC9ysE$!a@1UUcW?3!N8XVDJjQ0`8pDc04CFVj6
z53-ePkZ$iFh)6$1ml8sldhD6}!z))zuK&uggpz*4XrLL#+59rE9!<zwOx^tvzk6X(
z<LCUSmZ)tvEEM;QUJFX-%$%EwXA|6tc&%UXIQIOoFnNiFpd+#pOJI0vCiu*1eJ3U|
zDTE|lwW%2|u~~ECz@R$eL!uVnqaFFKhiyp!c!TbzHG3-QXI)G@DQ)ko8y_jykG+op
z3+}V{U^#3bW>znguQi1L&>o*5&;K~Jx;#zxIVH<Qzj|`OlkqaXEJT<8@uncsw5ka@
zXX~Y(O*f>lpf2kTrs1UQ)$rK2Sk9;3Q2p%K1!Icx*5%c&&0!hnVk+hZz<Ju-m=3G)
z&6qs#*25P=KR6`u@DIc6S$+^@kE53_TfqGS*P^I2)M}{36S@UpAIR2|msz!y7ZM&%
zd$(rz9@n}JXNV~Gb6EJNg#*QlJG~$K_rNxGO`Id3U!J=lfMk#@uBT$dT4>zjMIPz?
zh{k2mtqT7D1BOy~MZ_?wSB4?qJ+&|bImN^5@!5}?pnDf}uBrC3C&z2~e)#8XgO`uq
z0DZm)Y-#YyT4=_9Y+@aOJ<~hwU2VSI*#0O)*%qwVlu<-lcq}-Sf}>J@gcYYdJ7UQ?
z@$${F;3eM^0W+&B*f%eG4`vnlE8)!;_?C;O_X*ScD9h3!|K0|W3F|OZiWu)*68x%m
z+~7#ph?e1GCEp=Pva<JN$O-Q~e7p{0lD1SgAm%EYb%xTIjv!d%upB_sHGZWrawyYF
zTgE#UsB;i>r-`tR>K*t%a3ECSM0(lH_Pi}|Tu|UUHLMI71ULc!K!dEe39ESrZMGfP
zk7xrm9CHZpjNO_AF(E|`4ZGFTy&>m^#OiHs(fjo`+D0#L-}1!cI={&=T3%4y3vWFf
z7o!*wufZtYA6$ob8w3oi?)sk8Tal5w&@`hHH`vMPF4(5x3DusC=`esQ7v`R?y_*xe
zxe{t}?2j6WIfFP8Y9N^0<`83<qFiB7wY`0Pg)~)JU&WZVs*wlpZY7pk`mEJBt8+n<
za$P&rpG4XO*W?(`kk}%m=pYmu+R-3@w)#TEnq;0m`+T;e(XO(G<a`$HCS8T`eJSo6
z@axBte9m1>#=c$+1w!qLPgG2!EaicFXJ9wy5$n5I&#{Oi@N$69_i*2$7%##gCyUeI
zx@Qjg(7^%vqaO1wB#;v$Q)sx+31{~esEXBT!(M`op|<KtR)lG_{@v$`v0IRCW!b8?
zTrCKmie&ieyN1k4#40LGJHo)P-u8(uXA*k8rQ(!AcZ|hp`e!dlYU)CC#^hWUk0)UU
zIsbG<m<d_*+NMN|5zZ~XlwUJFPwa=lq48Ari4~L4Wsy^nIW+UuzIN5>M%mU0ySN6G
zu9^x>&%yF$zbwIOrB)OY%<ykbu5~pjN1Na<eKVy7srm%yOt~7KqC=lSgzQxWY2K@d
zrG}zIBpWMdza?g&;RZwVq~RLoLcRm^QCER;QMeF2hQ*TwG3i}b$Z&Yv;a1f_+$P>3
zwX_QG38JMMsNI`pO#$>6fDn8JSVQWD-J!hLBOn6iV^@Acutp{|gC=s~K7LGzcp0kP
zJfuc=V#*PeUqH=D2f}!u*w$k*-R#{_YMHu7udbiS)U6wqrucpk8+`!dI*>_>3>k67
z?8FmXBn37!paE$SGVZLbu704SKW-~|6x!FnDE2|INu(Y@4t4iX$|G2Fb}k5z;gaWt
z%z+w0@*}8OkRvgotKtzt0QY{I>IDggrc=paai5gXmYNy5>Gea9$rqNULh0xylW+?b
zyzXu>L(O<9Es7o8!M4!7;FFG(^<pftP@A#hqw4)Ak}Zs-z5^?~&ZRWEf(_qCHNuos
zX=_#{#K6SPoDV3x@&`Pa>matzX@~M>FTU)sb84j8cxkD*NoM%N);EUV^BWu1_jc0o
z*3K%cz}3@V8g1*QvHNE0u%?`51LMe-32nSs{GyWW<;aXHna|;?v8`XNUw<Te(OZWe
zKs&$(!FW3Xj|HMp#;ucewbp!x=zI2yX^>cPaB2bzcf~j}8cn8NyG1YHeSMi*Um*5f
z(N5?`xNWrlw5?tsNBvjxToeDC(AUo-zSvZ%qaD_VRlNIP!)h!jwZgrhZyC*?iHWfC
zL0wlo{)>NGJrW(bF&BRimg4n@@;0PpavEh!R3b~YDAKk3;MunStDLch37Ipj<d}==
z9Fz2?Rj1C42G=C11G4;4&2MsNqjqFErra+q-HAil(>J&1AE*W^+f`g7h~}AkT_LW@
zRXM^XA?1eJL}$EZWk83Ctd>C?(BeCTS-Gc36#1IDYrA{9<!*z=ft4Ac@@|#(ZbmCA
zB%$XxsElZ}mpP84?_;iA75fmE4S61&nb>$C`ZlgAI8?q_W7FnaSaB{fd<%9}dl(FI
zT%@w>an#I!A4e}4PZooGZS8?F;h^2ChYipDkdd|T&dc&l+2-<c*$0UiuYJ%%E~mdE
zh)U3ZBu#Dep+{kr+^`{xp4H82N$HEmA;vuGz1lrn%<<arl=vom8e@e#F5PdIS@2Q7
z1cJe|#zB7C7=STqUqPO(iO49+^mul5#O3YEyNNTgmr{`<GyKWUd=l>J%*N>{-e2^}
zg3z2uqVFyUm*msqkyWBIznOk$i$A2Om%7sTd0Mob5&N=hvX&bTCfO!YjHFd2c*#bA
zitt){B!&wKqFd{hd~hf{)s-Rj30ohOUG3<~mDe%rp{@{QcO~5s6~@qGQDyg;o3Y9|
z!!b(WRXGt8`D=zwp(ky^ab#6VU(@_;g|QrONE=B-xkXdV)l0XeG(Og5xez1YJZ3H>
zLNo=!bmMztnRv9^ImH#uF^60U(V5e?F~)HD!h~vf8@1mBQ0R<DbB4{GXMM{x*J5jV
z&A%U*Q9Kt_Or=d@?dv(%<6oM}jkr_!9^0O2HiA8##J^>anwqk@prgtp><O8Ga}AI(
zb?0%)u&MXi-lY5a<yp+FDw8QurndeY-)Q3>EReK?4D?R!U`&E#c_I!CaU%Z&4zP=1
zhVVNxrb;KZ(H+0qiBM-6yK9X(C97FD8mBgs$2rM79zkDtnDa$;vCPBsCgH4(4u(sE
zE2l^oO{nA@&{LbwKjn&7wgjQHpWs|%muj<GgTU|m^V_P(iI-P-kE~f25}`INeT82@
zSPn4@@dx@Y0xsiN@lZaO4e=<jPM99L<HsJQ1fX1M=T*7ZOu;DDvFy9f8NOQtwV%@{
zq@U9$Q4ff+WoW36G$H`df(!s)0vG`1E-p}aC<N@vZtso`paJ|e1OO=@C<%2Rp=}ZY
zpgVr>bNsiTqdDk2&xzZ-%}OlH94<p7#<W4}iaQk)+UViCQIcO=(<4hqv^ODVaIw&o
z$Oh-qpee@oO%SQB?ot;Iju^l%^Tz~&*ObCUsL2!fqI>AcfoJVRh!(aFt{d;_&)Xc0
z9rSt&YMFx3*vh2j1z(hh#BYU$T$1yWF0@i|4WjJu1|MU-WyG$HjAh(m)73C5d80pX
zAQ*7*Ku+WU#eo$kBA<+9?TlqK>vi1`I0?gs{VN0|N%X0;_5oIajbRe(**21mo#d7c
z!6H+B(4ZduDl4X;y7Jbm%#-iJPh-8hIj=-bzuX!Pw+^S_9H41T@}Qpy84#mFm@S~9
z;{C|;u!KVSXqnZtkU|t7_%a8eXCu_KVTuqpoF%sjYnG>L>3HECf-RF8Kn2n|S1xK1
zpgW}0_cQ*6@^$e&$*UZD61B*g(6dR|z44avc9KFw{(zV_i)9W1RPt?XEm1F(eH%)i
zzus0NP#Y|H>+*oy`_?@Z!9S)ZpyNC~MU{za5;^nrc8ezj2S2xw{i9Ea2Q<9gOGZ2I
zG^Y@i{}b+k5FJ;C0Taqov@dMy5RK;sUY}C}Q0G#{fE;ushR%(<9b|e}fK)$oH0lRA
zQhwPIlM!j-ki_gP^tkPT{@7)vNONiL-RWuYb~nhJO0f1lhCYAw!1(n$C*26`WK+0V
zgc#`;;}?`OlLrm^{z_-~)8oW~xYlp2#ZvHieFP$f2dl`B+;etR$F(ip`dg61fd_oS
zDH3vVTa;~ghT}`O>c^=6)*}D_Hijqz{=-o3^=M%WadEQZ_)jSU+DZ;LTJI%DS7UR2
zKmObQ355RNKq?LpWjj~m4bc7jpF7U)K<rLnXFF>vcjzAgxf?Bi0tGqndi^)xZ@z_#
zGt|l%O5^5X2ZdTeXnu?3H<#nLuQ|~F{tSK*|9;f}^-TU6kmP>?{vO6Z0Df@)q7}V3
zIJU63zxNC7@BK%A5B%HcZUM1#h5jim03=`8*GCWhx^%x0S!s6Mrv=QGE7r*D#P*a3
zDuSKla>)qbZUVTAbBAUSTF{Yd6cwFDba}3xy3EgNCW(7_adDzRqIBUq_Ry1G@I_@6
zQD?cwW7naGBLNmfm?SE)G~BoH)OB{Qt<jD_G#ob063Y0+;YF_nwmiaqj|hSnpMqMg
z$TPn9^D!lyUVN>&q)989vV1tyEa>djyU$qe*Ods#yk<&?nK+>|XxOq}--G6+4E5?b
z(yJGpUj$jbvg*Mf6PO#r%A}92FYtu*P*h~^*#=R)4SgAobN!{(!db?|6|d2N<zzcq
z7w$8yuwP_ZuL7LFDuM}<KA9uGz~|*!@JAS(6&ma<-N<HCD#C8K7DDp$>|;-V-W@E1
zKGMFk9(l`W*d=5$MX-PxCa<}xBIh*j*U)#l(@8O^k3G7Ml4fb6qd{o*;rb~lW{{;M
z_O}ow+f_70WRh4gLOW9*xC$*i$O?vIBAY6rl1{Mriol1>QZCUs-VGv3fYvJW)}h=?
z4wj8|EhgQCB!^Vv@rp6-Zn^8Mi9cmm0NbkUq2RJ-74|o@waDbRSiH=e5s1{xim}4e
zdV{{py$p-g_%1CAid_%i;sHLr|3Nta6$d6LdS!~u8Xqe(1v{+QYs;KhIJNdiwR;al
z{YIpGWBOzrBAAFAR4=R=l}LtpHkn)K1)0QPLm^Eem4z8;=?#vJ3A}vX$&|g3vm;z4
zzW*@XRL4J~(GjtNy<#(mRz#KC<jmRQ6+JtiI`@))Ec+22^*+apx5+YaMu>X)fDZey
zi@f|b`X>}ooKdCi%Yi8V3_qt&yv-hGIKQ;4bzjFw()d{c_ge0_*D}VvmhGI~p<qWx
zc8I0*AIg}U6dK~s^7W^2SnFAQ7AJ1YF{{y;&a|2ML>LI%q|sO>_VK-MUOPh-p`$$x
z*8Kas7BhV5WU*5%)5>qnhgm)kt9>0y>93-C70W*d5I(r$I&Yqa5A$r(4ScvkQg6ZR
zn%pGJPL#}gPHLr394#1Y;XFW9R}r1RIv{@Wa63)O$lN2zaMSe28`(>eO_tnz+D76c
zhti@HYp(NCW+OMLqlb(`8<)M$h=HONTAaK|aH7b^DXUXO*0NOCP#|yOgW;m6UKUDe
z`rR)U4`XccA{ipN<r~`R<4qifEJ)nvxhkhK*~p6Bxv_*hiH?ACA|tZ`oPG>vT5x&&
zAcsio32sL;?TQ|BwVf|&=ZrVt%5u|3Pf>NAGM2tG&sWru+CHl-ad3JtIA}E+<R;EM
zU!o#=eEeF|=2-oc_766!J*Y@7kK2g=F~+ONuh}G3fZPCOFVT7Q6?H^3%k<%-CqLGE
zSCl+;Z_cYrHra6FcsiUL#!L>*kq*&~ws7{zN!izT!|!G>w9sP&$^i<|`h@b$VNOGu
z!Ca=YC<j8)qVr3&k#vV``fgNxHgAZkM!$kuXgYuooY&-}UR<Uv-PCtca)u8^Eo$l;
z0Lua$%cO-jU=)rtI#9$JyQxa~?eM0mPYO87!Ze`{cEJS9`#(0?J82U5F9#2zsSZPY
zyuMa+?op@s1^z2B{{C#4(2W5)h5!JFBK`T<@^96H-N`y<{8@YfCu#d(Q(mVC8Q%Dh
zL~lu4GI=wtu}-W)b05}^L}RLL%X=e^+_}~qPMOzvOl_jpYKuJP*Q-IGuEKPWw<c|q
zRUwqajrC@tpI{GPj!<Fs#VhxlOLMiYIDY1<QTK8IO)QhfO0F;896ieNnAWWm=cY&9
z9*Z7dbUZEHHO?3ni4U%@w<+1%=6uIYi8`-C+}me?Z$z8DGQ5AZ46o3Eh_N$I`YoDb
zi0~Rmxq_ut%5Yz=3x4xOsKj4^XjFUOq6r#<`qeq^Vy>CZpGW5FoZ!I9C>bzyh2C%V
z6Ciq{&Fr81isWbsXo9-xUbj@8#=NP1)SXz|^;*@R!J7s#{6Xk$tq#uyZ;kNq0+_*}
zvBp8s>JSGHzmu#;YF24R73DGUe!9VC58m?%d-utYQe=T78&M9;e(i?SO9*Tm^DVp@
zhSoF9Z&gDqIb6H7Z0a^K9uq!`aTRQ)D5Tj;)jYRGm4r!?Y&Kuk0;?L$NAQSL3m1zQ
z^8`fHjgIcxojTo!k30B=Q7ROX!gS^!$6;MrZwUB8vK~*L${Gi|bG_p#mRAetozC2j
z?(3dugswix6*?QLEg3z~a8TT!c3lhQ|Cl&$eyumk@ka&R@YQi=+<UF}JHcPAF1TAe
z4L-vN;RFONHMMm%={X6}c7(o5&RFWp^dQWHCG)LyU+%|z@bJUg*Q|;Yuuq&~(u&*Z
z5hEz$mm{VXF{h$R$>Gbc$vYT2b=^EdNVO}IVwY6*GOFx6f4M~(Byq+3h0axFg9z7%
za=^~u0oAE-N=KUH$}Qd3&)?r+p!t<9Ovwtff7T~g3{ETRp+Mb5(TVTQSlXfJrBG8s
zKqN%^`<0S^TMz=^Z`MtIB1j<p{UqUEMiW#REPs#tPp1sO(EqyS`<LMc?MlIM0ROB3
z{0aQ`E#R-PX>bAmpN8;%iyY?<k!So)@DCfmzb7F11Hsn+B=~2I;IDu9uUf%hmr4fj
zZ;Adtjp2V1|5e@oMT~Q=)qhyU|E&B!=kZ_4HzNM)to~<&Kj(p82qvU|nHAKOP=G&w
PfPTL{zo!L}{q+6|P6DnE