Merge mozilla-central to inbound. a=merge CLOSED TREE
authorshindli <shindli@mozilla.com>
Wed, 17 Oct 2018 03:59:39 +0300
changeset 500052 89189817c169f830f2b880df11ac88569582a67e
parent 500051 0522e105ea10e64fcd421dd082e0ba1cd02dfae1 (current diff)
parent 500027 778427bb6353f85c1656f4ebcd2041560cd70c16 (diff)
child 500053 fdfa6fafe6a92e227839353e4eb2195016eca135
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.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
Merge mozilla-central to inbound. a=merge CLOSED TREE
js/xpconnect/tests/components/native/xpctest.manifest
testing/web-platform/meta/payment-request/PaymentItem/type_member.https.html.ini
testing/web-platform/tests/payment-request/PaymentItem/type_member.https.html
xpcom/tests/unit/xpcomtest.manifest
--- a/browser/actors/NetErrorChild.jsm
+++ b/browser/actors/NetErrorChild.jsm
@@ -9,16 +9,18 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 
 ChromeUtils.defineModuleGetter(this, "BrowserUtils",
                                "resource://gre/modules/BrowserUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
                                "resource://gre/modules/WebNavigationFrames.jsm");
 
+XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
+
 XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
   return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
 });
 XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
   return Services.strings.createBundle("chrome://branding/locale/brand.properties");
 });
 XPCOMUtils.defineLazyPreferenceGetter(this, "newErrorPagesEnabled",
   "browser.security.newcerterrorpage.enabled");
@@ -76,16 +78,24 @@ class NetErrorChild extends ActorChild {
   isAboutNetError(doc) {
     return doc.documentURI.startsWith("about:neterror");
   }
 
   isAboutCertError(doc) {
     return doc.documentURI.startsWith("about:certerror");
   }
 
+  getParams(doc) {
+    let searchParams = new URL(doc.documentURI).searchParams;
+    return {
+      cssClass: searchParams.get("s"),
+      error: searchParams.get("e"),
+    };
+  }
+
   _getCertValidityRange(docShell) {
     let {securityInfo} = docShell.failedChannel;
     securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
     let notBefore = 0;
     let notAfter = Number.MAX_SAFE_INTEGER;
     for (let cert of securityInfo.failedCertChain.getEnumerator()) {
       notBefore = Math.max(notBefore, cert.validity.notBefore);
       notAfter = Math.min(notAfter, cert.validity.notAfter);
@@ -93,19 +103,17 @@ class NetErrorChild extends ActorChild {
     // nsIX509Cert reports in PR_Date terms, which uses microseconds. Convert:
     notBefore /= 1000;
     notAfter /= 1000;
     return {notBefore, notAfter};
   }
 
   _setTechDetails(input, doc) {
     // CSS class and error code are set from nsDocShell.
-    let searchParams = new URLSearchParams(doc.documentURI.split("?")[1]);
-    let cssClass = searchParams.get("s");
-    let error = searchParams.get("e");
+    let {cssClass, error} = this.getParams(doc);
     let technicalInfo = doc.getElementById("badCertTechnicalInfo");
     technicalInfo.textContent = "";
 
     let uri = Services.io.newURI(input.data.url);
     let hostString = uri.host;
     if (uri.port != 443 && uri.port != -1) {
       hostString = uri.hostPort;
     }
@@ -348,16 +356,19 @@ class NetErrorChild extends ActorChild {
     this._setTechDetails(msg, doc);
     let learnMoreLink = doc.getElementById("learnMoreLink");
     let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
     let errWhatToDo = doc.getElementById("es_nssBadCert_" + msg.data.codeString);
     let es = doc.getElementById("errorWhatToDoText");
     let errWhatToDoTitle = doc.getElementById("edd_nssBadCert");
     let est = doc.getElementById("errorWhatToDoTitleText");
 
+    // This is set to true later if the user's system clock is at fault for this error.
+    let clockSkew = false;
+
     switch (msg.data.code) {
       case SSL_ERROR_BAD_CERT_DOMAIN:
       case SEC_ERROR_OCSP_INVALID_SIGNING_CERT:
       case SEC_ERROR_UNKNOWN_ISSUER:
         if (!newErrorPagesEnabled) {
           break;
         }
         if (es) {
@@ -402,17 +413,16 @@ class NetErrorChild extends ActorChild {
       case SEC_ERROR_EXPIRED_CERTIFICATE:
       case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
       case SEC_ERROR_OCSP_FUTURE_RESPONSE:
       case SEC_ERROR_OCSP_OLD_RESPONSE:
       case MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
       case MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
 
         learnMoreLink.href = baseURL + "time-errors";
-        let clockSkew = false;
         // We check against the remote-settings server time first if available, because that allows us
         // to give the user an approximation of what the correct time is.
         let difference = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_CLOCK_SKEW_SECONDS, 0);
         let lastFetched = Services.prefs.getIntPref(PREF_SERVICES_SETTINGS_LAST_FETCHED, 0) * 1000;
 
         let now = Date.now();
         let certRange = this._getCertValidityRange(docShell);
 
@@ -503,16 +513,32 @@ class NetErrorChild extends ActorChild {
               // eslint-disable-next-line no-unsanitized/property
               est.textContent = errWhatToDoTitle.textContent;
               est.style.fontWeight = "bold";
             }
             updateContainerPosition();
         }
         break;
     }
+
+    // Add slightly more alarming UI unless there are indicators that
+    // show that the error is harmless or can not be skipped anyway.
+    if (newErrorPagesEnabled) {
+      let {cssClass} = this.getParams(doc);
+      // Don't alarm users when they can't continue to the website anyway...
+      if (cssClass != "badStsCert" &&
+          // Errors in iframes can't be skipped either...
+          doc.ownerGlobal.parent == doc.ownerGlobal &&
+          // Also don't bother if it's just the user's clock being off...
+          !clockSkew &&
+          // Symantec distrust is likely harmless as well.
+          msg.data.code != MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED) {
+        doc.body.classList.add("caution");
+      }
+    }
   }
 
   handleEvent(aEvent) {
     // Documents have a null ownerDocument.
     let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
 
     switch (aEvent.type) {
     case "AboutNetErrorLoad":
--- a/browser/base/content/aboutNetError-new.xhtml
+++ b/browser/base/content/aboutNetError-new.xhtml
@@ -27,16 +27,17 @@
     <link rel="icon" id="favicon" href="chrome://global/skin/icons/warning.svg"/>
   </head>
 
   <body dir="&locale.dir;">
     <!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
     <div id="errorContainer">
       <div id="errorPageTitlesContainer">
         <span id="ept_nssBadCert">&certerror.pagetitle2;</span>
+        <span id="ept_nssBadCert_sts">&certerror.sts.pagetitle;</span>
         <span id="ept_captivePortal">&captivePortal.title;</span>
         <span id="ept_dnsNotFound">&dnsNotFound.pageTitle;</span>
         <span id="ept_malformedURI">&malformedURI.pageTitle;</span>
         <span id="ept_blockedByPolicy">&blockedByPolicy.title;</span>
       </div>
       <div id="errorTitlesContainer">
         <h1 id="et_generic">&generic.title;</h1>
         <h1 id="et_captivePortal">&captivePortal.title;</h1>
@@ -55,16 +56,17 @@
         <h1 id="et_netInterrupt">&netInterrupt.title;</h1>
         <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
         <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1>
         <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1>
         <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1>
         <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1>
         <h1 id="et_nssFailure2">&nssFailure2.title;</h1>
         <h1 id="et_nssBadCert">&certerror.longpagetitle2;</h1>
+        <h1 id="et_nssBadCert_sts">&certerror.sts.longpagetitle;</h1>
         <h1 id="et_cspBlocked">&cspBlocked.title;</h1>
         <h1 id="et_remoteXUL">&remoteXUL.title;</h1>
         <h1 id="et_corruptedContentErrorv2">&corruptedContentErrorv2.title;</h1>
         <h1 id="et_sslv3Used">&sslv3Used.title;</h1>
         <h1 id="et_inadequateSecurityError">&inadequateSecurityError.title;</h1>
         <h1 id="et_blockedByPolicy">&blockedByPolicy.title;</h1>
         <h1 id="et_clockSkewError">&clockSkewError.title;</h1>
       </div>
@@ -86,16 +88,17 @@
         <div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
         <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
         <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div>
         <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
         <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
         <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
         <div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
         <div id="ed_nssBadCert">&certerror.introPara2;</div>
+        <div id="ed_nssBadCert_sts">&certerror.sts.introPara;</div>
         <div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
         <div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
         <div id="ed_corruptedContentErrorv2">&corruptedContentErrorv2.longDesc;</div>
         <div id="ed_sslv3Used">&sslv3Used.longDesc2;</div>
         <div id="ed_inadequateSecurityError">&inadequateSecurityError.longDesc;</div>
         <div id="ed_blockedByPolicy"></div>
         <div id="ed_clockSkewError">&clockSkewError.longDesc;</div>
       </div>
@@ -111,16 +114,20 @@
         <div id="es_nssBadCert_SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
         <div id="es_nssBadCert_SEC_ERROR_OCSP_FUTURE_RESPONSE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
         <div id="es_nssBadCert_SEC_ERROR_OCSP_OLD_RESPONSE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
         <div id="es_nssBadCert_MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
         <div id="es_nssBadCert_MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
         <div id="es_nssBadCert_SSL_ERROR_BAD_CERT_DOMAIN">&certerror.badCertDomain.whatCanYouDoAboutIt;</div>
         <div id="es_nssBadCert_SEC_ERROR_OCSP_INVALID_SIGNING_CERT">&certerror.badCertDomain.whatCanYouDoAboutIt;</div>
       </div>
+      <!-- Stores an alternative text for when we don't want to add "Recommended" to the
+           return button. This is one of many l10n atrocities in this file and should be
+           removed when we finally switch to Fluent. -->
+      <span id="stsReturnButtonText">&returnToPreviousPage.label;</span>
     </div>
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer" class="container">
       <div id="text-container">
         <!-- Error Title -->
         <div class="title">
           <h1 class="title-text"/>
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -123,16 +123,20 @@ function disallowCertOverridesIfNeeded()
   // Disallow overrides if this is a Strict-Transport-Security
   // host and the cert is bad (STS Spec section 7.3) or if the
   // certerror is in a frame (bug 633691).
   if (cssClass == "badStsCert" || window != top) {
     document.getElementById("exceptionDialogButton").setAttribute("hidden", "true");
   }
   if (cssClass == "badStsCert") {
     document.getElementById("badStsCertExplanation").removeAttribute("hidden");
+
+    let stsReturnButtonText = document.getElementById("stsReturnButtonText").textContent;
+    document.getElementById("returnButton").textContent = stsReturnButtonText;
+    document.getElementById("advancedPanelReturnButton").textContent = stsReturnButtonText;
   }
 }
 
 function initPage() {
   var err = getErrorCode();
   // List of error pages with an illustration.
   let illustratedErrors = [
     "malformedURI", "dnsNotFound", "connectionFailure", "netInterrupt",
@@ -147,25 +151,35 @@ function initPage() {
 
   gIsCertError = (err == "nssBadCert");
   // Only worry about captive portals if this is a cert error.
   let showCaptivePortalUI = isCaptive() && gIsCertError;
   if (showCaptivePortalUI) {
     err = "captivePortal";
   }
 
-  let pageTitle = document.getElementById("ept_" + err);
+  let l10nErrId = err;
+  let className = getCSSClass();
+  if (className) {
+    document.body.classList.add(className);
+  }
+
+  if (gIsCertError && className == "badStsCert") {
+    l10nErrId += "_sts";
+  }
+
+  let pageTitle = document.getElementById("ept_" + l10nErrId);
   if (pageTitle) {
     document.title = pageTitle.textContent;
   }
 
   // if it's an unknown error or there's no title or description
   // defined, get the generic message
-  var errTitle = document.getElementById("et_" + err);
-  var errDesc  = document.getElementById("ed_" + err);
+  var errTitle = document.getElementById("et_" + l10nErrId);
+  var errDesc  = document.getElementById("ed_" + l10nErrId);
   if (!errTitle || !errDesc) {
     errTitle = document.getElementById("et_generic");
     errDesc  = document.getElementById("ed_generic");
   }
 
   // eslint-disable-next-line no-unsanitized/property
   document.querySelector(".title-text").innerHTML = errTitle.innerHTML;
 
@@ -203,17 +217,16 @@ function initPage() {
     learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
     document.body.className = "certerror";
   }
 
   // remove undisplayed errors to avoid bug 39098
   var errContainer = document.getElementById("errorContainer");
   errContainer.remove();
 
-  var className = getCSSClass();
   if (className && className != "expertBadCert") {
     // Associate a CSS class with the root of the page, if one was passed in,
     // to allow custom styling.
     // Not "expertBadCert" though, don't want to deal with the favicon
     document.documentElement.className = className;
 
     // Also, if they specified a CSS class, they must supply their own
     // favicon.  In order to trigger the browser to repaint though, we
@@ -317,17 +330,17 @@ function initPageCaptivePortal() {
   // When the portal is freed, an event is generated by the frame script
   // that we can pick up and attempt to reload the original page.
   window.addEventListener("AboutNetErrorCaptivePortalFreed", () => {
     document.location.reload();
   });
 }
 
 function initPageCertError() {
-  document.body.className = "certerror";
+  document.body.classList.add("certerror");
   for (let host of document.querySelectorAll(".hostname")) {
     host.textContent = document.location.hostname;
   }
 
   addAutofocus("returnButton");
   setupAdvancedButton();
 
   document.getElementById("learnMoreContainer").style.display = "block";
--- a/browser/base/content/test/about/browser_aboutCertError.js
+++ b/browser/base/content/test/about/browser_aboutCertError.js
@@ -488,16 +488,41 @@ add_task(async function checkUnknownIssu
       return learnMoreLink.href;
     });
     ok(href.endsWith("security-error"), "security-error in the Learn More URL");
 
     BrowserTestUtils.removeTab(gBrowser.selectedTab);
   }
 });
 
+add_task(async function checkCautionClass() {
+  info("Checking that are potentially more dangerous get a 'caution' class");
+  for (let useFrame of [false, true]) {
+    let tab = await openErrorPage(UNKNOWN_ISSUER, useFrame);
+    let browser = tab.linkedBrowser;
+
+    await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
+      let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
+      is(doc.body.classList.contains("caution"), !frame, `Cert error body has ${frame ? "no" : ""} caution class`);
+    });
+
+    BrowserTestUtils.removeTab(gBrowser.selectedTab);
+
+    tab = await openErrorPage(BAD_STS_CERT, useFrame);
+    browser = tab.linkedBrowser;
+
+    await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
+      let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
+      ok(!doc.body.classList.contains("caution"), "Cert error body has no caution class");
+    });
+
+    BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  }
+});
+
 function getCertChain(securityInfoAsString) {
   let certChain = "";
   const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
                        .getService(Ci.nsISerializationHelper);
   let securityInfo = serhelper.deserializeObject(securityInfoAsString);
   securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
   for (let cert of securityInfo.failedCertChain.getEnumerator()) {
     certChain += getPEMString(cert);
--- a/browser/base/content/test/performance/browser_preferences_usage.js
+++ b/browser/base/content/test/performance/browser_preferences_usage.js
@@ -96,16 +96,20 @@ add_task(async function startup() {
     },
     "network.loadinfo.skip_type_assertion": {
       // This is accessed in debug only.
     },
     "extensions.getAddons.cache.enabled": {
       min: 5,
       max: 55,
     },
+    "chrome.override_package.global": {
+      min: 0,
+      max: 50,
+    },
   };
 
   let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
   await startupRecorder.done;
 
   ok(startupRecorder.data.prefStats, "startupRecorder has prefStats");
 
   checkPrefGetters(startupRecorder.data.prefStats, max, whitelist);
--- a/browser/base/content/test/static/browser_misused_characters_in_strings.js
+++ b/browser/base/content/test/static/browser_misused_characters_in_strings.js
@@ -13,16 +13,20 @@ let gWhitelist = [{
     key: "certerror.introPara",
     type: "single-quote",
   }, {
     file: "netError.dtd",
     key: "certerror.introPara2",
     type: "single-quote",
   }, {
     file: "netError.dtd",
+    key: "certerror.sts.introPara",
+    type: "single-quote",
+  }, {
+    file: "netError.dtd",
     key: "certerror.expiredCert.whatCanYouDoAboutIt2",
     type: "single-quote",
   }, {
     file: "netError.dtd",
     key: "certerror.whatShouldIDo.badStsCertExplanation1",
     type: "single-quote",
   }, {
     file: "netError.dtd",
--- a/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_telemetry.js
@@ -35,17 +35,18 @@ add_task(async function setup() {
   let enabledCounts =
     Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED").snapshot().counts;
   is(enabledCounts[0], 1, "TP was not enabled on start up");
 
   let scalars = Services.telemetry.snapshotScalars(
     Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTOUT, false).parent;
 
   is(scalars["contentblocking.enabled"], true, "CB was enabled at startup");
-  is(scalars["contentblocking.fastblock_enabled"], true, "FB was enabled at startup");
+  is(scalars["contentblocking.fastblock_enabled"], AppConstants.NIGHTLY_BUILD,
+     "FB is enabled in Nightly");
   is(scalars["contentblocking.exceptions"], 0, "no CB exceptions at startup");
 });
 
 
 add_task(async function testShieldHistogram() {
   Services.prefs.setBoolPref(PREF, true);
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
 
--- a/browser/components/enterprisepolicies/Policies.jsm
+++ b/browser/components/enterprisepolicies/Policies.jsm
@@ -543,33 +543,51 @@ var Policies = {
     },
   },
 
   "Homepage": {
     onBeforeUIStartup(manager, param) {
       // |homepages| will be a string containing a pipe-separated ('|') list of
       // URLs because that is what the "Home page" section of about:preferences
       // (and therefore what the pref |browser.startup.homepage|) accepts.
-      let homepages = param.URL.href;
-      if (param.Additional && param.Additional.length > 0) {
-        homepages += "|" + param.Additional.map(url => url.href).join("|");
+      if (param.URL) {
+        let homepages = param.URL.href;
+        if (param.Additional && param.Additional.length > 0) {
+          homepages += "|" + param.Additional.map(url => url.href).join("|");
+        }
+        if (param.Locked) {
+          setAndLockPref("browser.startup.homepage", homepages);
+          setAndLockPref("pref.browser.homepage.disable_button.current_page", true);
+          setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
+          setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
+        } else {
+          setDefaultPref("browser.startup.homepage", homepages);
+          runOncePerModification("setHomepage", homepages, () => {
+            Services.prefs.clearUserPref("browser.startup.homepage");
+          });
+        }
       }
-      if (param.Locked) {
-        setAndLockPref("browser.startup.homepage", homepages);
-        setAndLockPref("browser.startup.page", 1);
-        setAndLockPref("pref.browser.homepage.disable_button.current_page", true);
-        setAndLockPref("pref.browser.homepage.disable_button.bookmark_page", true);
-        setAndLockPref("pref.browser.homepage.disable_button.restore_default", true);
-      } else {
-        setDefaultPref("browser.startup.homepage", homepages);
-        setDefaultPref("browser.startup.page", 1);
-        runOncePerModification("setHomepage", homepages, () => {
-          Services.prefs.clearUserPref("browser.startup.homepage");
-          Services.prefs.clearUserPref("browser.startup.page");
-        });
+      if (param.StartPage) {
+        let prefValue;
+        switch (param.StartPage) {
+          case "none":
+            prefValue = 0;
+            break;
+          case "homepage":
+            prefValue = 1;
+            break;
+          case "previous-session":
+            prefValue = 3;
+            break;
+        }
+        if (param.Locked) {
+          setAndLockPref("browser.startup.page", prefValue);
+        } else {
+          setDefaultPref("browser.startup.page", prefValue);
+        }
       }
     },
   },
 
   "InstallAddonsPermission": {
     onBeforeUIStartup(manager, param) {
       if ("Allow" in param) {
         addAllowDenyPermissions("install", param.Allow, null);
--- a/browser/components/enterprisepolicies/schemas/policies-schema.json
+++ b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -343,19 +343,22 @@
           "type": "boolean"
         },
         "Additional": {
           "type": "array",
           "strict": false,
           "items": {
             "type": "URL"
           }
+        },
+        "StartPage": {
+          "type": "string",
+          "enum": ["none", "homepage", "previous-session"]
         }
-      },
-      "required": ["URL"]
+      }
     },
 
     "InstallAddonsPermission": {
       "type": "object",
       "properties": {
         "Allow": {
           "type": "array",
           "strict": false,
--- a/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js
+++ b/browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js
@@ -5,41 +5,51 @@
 ChromeUtils.defineModuleGetter(this, "HomePage",
                                "resource:///modules/HomePage.jsm");
 
 registerCleanupFunction(function restore_pref_values() {
   // These two prefs are set as user prefs in case the "Locked"
   // option from this policy was not used. In this case, it won't
   // be tracked nor restored by the PoliciesPrefTracker.
   Services.prefs.clearUserPref("browser.startup.homepage");
-  Services.prefs.clearUserPref("browser.startup.page");
 });
 
-async function check_homepage({expectedURL, expectedPageVal = 1, locked = false}) {
-  is(HomePage.get(),
-     expectedURL, "Homepage URL should match expected");
-  is(Services.prefs.getIntPref("browser.startup.page", -1), expectedPageVal,
-     "Pref page value should match expected");
-  is(Services.prefs.prefIsLocked("browser.startup.homepage"), locked,
-     "Lock status of browser.startup.homepage should match expected");
-  is(Services.prefs.prefIsLocked("browser.startup.page"), locked,
-     "Lock status of browser.startup.page should match expected");
+async function check_homepage({expectedURL, expectedPageVal = -1, locked = false}) {
+  if (expectedURL) {
+    is(HomePage.get(),
+       expectedURL, "Homepage URL should match expected");
+    is(Services.prefs.prefIsLocked("browser.startup.homepage"), locked,
+       "Lock status of browser.startup.homepage should match expected");
+  }
+  if (expectedPageVal != -1) {
+    is(Services.prefs.getIntPref("browser.startup.page", -1), expectedPageVal,
+       "Pref page value should match expected");
+    is(Services.prefs.prefIsLocked("browser.startup.page"), locked,
+       "Lock status of browser.startup.page should match expected");
+  }
 
   // Test that UI is disabled when the Locked property is enabled
   let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences");
   await ContentTask.spawn(tab.linkedBrowser, {expectedURL, expectedPageVal, locked},
                           // eslint-disable-next-line no-shadow
                           async function({expectedURL, expectedPageVal, locked}) {
-    let browserRestoreSessionCheckbox = content.document.getElementById("browserRestoreSession");
-    is(browserRestoreSessionCheckbox.disabled, locked,
-       "Disabled status of session restore status should match expected");
-    let shouldBeChecked = expectedPageVal === 3;
-    is(browserRestoreSessionCheckbox.checked, shouldBeChecked,
-       "Session restore status checkbox should be: " + (shouldBeChecked ? "checked" : "unchecked"));
+    if (expectedPageVal != -1) {
+      // Only check restore checkbox for StartPage
+      let browserRestoreSessionCheckbox = content.document.getElementById("browserRestoreSession");
+      is(browserRestoreSessionCheckbox.disabled, locked,
+         "Disabled status of session restore status should match expected");
+      let shouldBeChecked = expectedPageVal === 3;
+      is(browserRestoreSessionCheckbox.checked, shouldBeChecked,
+         "Session restore status checkbox should be: " + (shouldBeChecked ? "checked" : "unchecked"));
+    }
 
+    if (!expectedURL) {
+      // If only StartPage was changed, no need to check these
+      return;
+    }
     content.document.getElementById("category-home").click();
 
     let homepageTextbox = content.document.getElementById("homePageUrl");
     // Unfortunately this test does not work because the new UI does not fill
     // default values into the URL box at the moment.
     // is(homepageTextbox.value, expectedURL,
     //    "Homepage URL should match expected");
 
@@ -83,16 +93,17 @@ add_task(async function homepage_test_re
     "policies": {
       "Homepage": {
         "URL": "http://example1.com/",
       },
     },
   });
   await check_homepage({expectedURL: "http://example2.com/",
                        expectedPageVal: 3});
+  Services.prefs.clearUserPref("browser.startup.page");
 });
 
 add_task(async function homepage_test_different_policy_value() {
   // This policy is a change from the policy's previous value. This should
   // override the user's homepage
   await setupPolicyEngineWithJson({
     "policies": {
       "Homepage": {
@@ -160,8 +171,79 @@ add_task(async function homepage_test_an
     "policies": {
       "Homepage": {
         "URL": "http://example1.com/#test",
       },
     },
   });
   await check_homepage({expectedURL: "http://example1.com/#test"});
 });
+
+add_task(async function homepage_test_startpage_homepage() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "URL": "http://example1.com/#test",
+        "StartPage": "homepage",
+      },
+    },
+  });
+  await check_homepage({expectedURL: "http://example1.com/#test", expectedPageVal: 1});
+});
+
+add_task(async function homepage_test_startpage_homepage_locked() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "URL": "http://example1.com/#test",
+        "StartPage": "homepage",
+        "Locked": true,
+      },
+    },
+  });
+  await check_homepage({expectedURL: "http://example1.com/#test", expectedPageVal: 1, locked: true});
+});
+
+add_task(async function homepage_test_startpage_none() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "StartPage": "none",
+      },
+    },
+  });
+  await check_homepage({expectedPageVal: 0});
+});
+
+add_task(async function homepage_test_startpage_none_locked() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "StartPage": "none",
+        "Locked": true,
+      },
+    },
+  });
+  await check_homepage({expectedPageVal: 0, locked: true});
+});
+
+add_task(async function homepage_test_startpage_restore() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "StartPage": "previous-session",
+      },
+    },
+  });
+  await check_homepage({expectedPageVal: 3});
+});
+
+add_task(async function homepage_test_startpage_restore_locked() {
+  await setupPolicyEngineWithJson({
+    "policies": {
+      "Homepage": {
+        "StartPage": "previous-session",
+        "Locked": true,
+      },
+    },
+  });
+  await check_homepage({expectedPageVal: 3, locked: true});
+});
--- a/browser/components/migration/tests/marionette/test_refresh_firefox.py
+++ b/browser/components/migration/tests/marionette/test_refresh_firefox.py
@@ -572,18 +572,17 @@ class TestFirefoxRefresh(MarionetteTestC
           container.append(arguments[0]);
           return container.path;
         """, script_args=(profileLeafName,))  # NOQA: E501
 
         self.assertTrue(os.path.isdir(self.reset_profile_path),
                         "Reset profile path should be present")
         self.assertTrue(os.path.isdir(self.desktop_backup_path),
                         "Backup profile path should be present")
-        self.assertTrue(self.profileNameToRemove in self.reset_profile_path,
-                        "Reset profile path should contain profile name to remove")
+        self.assertIn(self.profileNameToRemove, self.reset_profile_path)
 
     def testReset(self):
         self.checkProfile()
 
         self.doReset()
 
         # Now check that we're doing OK...
         self.checkProfile(hasMigrated=True)
--- a/browser/components/search/searchplugins/google-2018.xml
+++ b/browser/components/search/searchplugins/google-2018.xml
@@ -4,15 +4,13 @@
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Google</ShortName>
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///zD9/f2W/f392P39/fn9/f35/f391/39/ZT+/v4uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Cf39/Zn///////////////////////////////////////////39/ZX///8IAAAAAAAAAAAAAAAA/v7+Cf39/cH/////+v35/7TZp/92ul3/WKs6/1iqOv9yuFn/rNWd//j79v///////f39v////wgAAAAAAAAAAP39/Zn/////7PXp/3G3WP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP+Or1j//vDo///////9/f2VAAAAAP///zD/////+vz5/3G3V/9TqDT/WKo6/6LQkf/U6cz/1urO/6rUm/+Zo0r/8IZB//adZ////v7///////7+/i79/f2Y/////4nWzf9Lqkj/Vqo4/9Xqzv///////////////////////ebY//SHRv/0hUL//NjD///////9/f2U/f392v////8sxPH/Ebzt/43RsP/////////////////////////////////4roL/9IVC//i1jf///////f391/39/fr/////Cr37/wW8+/+16/7/////////////////9IVC//SFQv/0hUL/9IVC//SFQv/3pnX///////39/fn9/f36/////wu++/8FvPv/tuz+//////////////////SFQv/0hUL/9IVC//SFQv/0hUL/96p7///////9/f35/f392/////81yfz/CrL5/2uk9v///////////////////////////////////////////////////////f392P39/Zn/////ks/7/zdS7P84Rur/0NT6///////////////////////9/f////////////////////////39/Zb+/v4y//////n5/v9WYu3/NUPq/ztJ6/+VnPT/z9L6/9HU+v+WnfT/Ul7t/+Hj/P////////////////////8wAAAAAP39/Z3/////6Or9/1hj7v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9sdvD////////////9/f2YAAAAAAAAAAD///8K/f39w//////5+f7/paz2/11p7v88Suv/Okfq/1pm7v+iqfX/+fn+///////9/f3B/v7+CQAAAAAAAAAAAAAAAP///wr9/f2d///////////////////////////////////////////9/f2Z/v7+CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f2Z/f392/39/fr9/f36/f392v39/Zj///8wAAAAAAAAAAAAAAAAAAAAAPAPAADAAwAAgAEAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/g3+/v5X/f39mf39/cj9/f3q/f39+f39/fn9/f3q/f39yP39/Zn+/v5W////DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f2c/f399f/////////////////////////////////////////////////////9/f31/f39mv7+/iMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/gn9/f2K/f39+////////////////////////////////////////////////////////////////////////////f39+v39/Yf///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4k/f390v////////////////////////////////////////////////////////////////////////////////////////////////39/dD///8iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////MP39/er//////////////////////////+r05v+v16H/gsBs/2WxSf9Wqjj/Vqk3/2OwRv99vWX/pdKV/97u2P////////////////////////////39/ej+/v4vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f3q/////////////////////+v15/+Pxnv/VKk2/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/36+Z//d7tf///////////////////////39/ej///8iAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K/f390//////////////////////E4bn/XKw+/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1apN/+x0pv///////////////////////39/dD///8IAAAAAAAAAAAAAAAAAAAAAP39/Yv/////////////////////sdij/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/YKU1/8qOPv/5wZ////////////////////////39/YcAAAAAAAAAAAAAAAD+/v4l/f39+////////////////8Lgt/9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9utlT/n86N/7faqv+426v/pdKV/3u8ZP9UqDX/U6g0/3egN//jiUH/9IVC//SFQv/82MP//////////////////f39+v7+/iMAAAAAAAAAAP39/Z3////////////////q9Ob/W6w+/1OoNP9TqDT/U6g0/1OoNP9nskz/zOXC/////////////////////////////////+Dv2v+osWP/8YVC//SFQv/0hUL/9IVC//WQVP/++fb//////////////////f39mgAAAAD+/v4O/f399v///////////////4LHj/9TqDT/U6g0/1OoNP9TqDT/dblc//L58P/////////////////////////////////////////////8+v/3p3f/9IVC//SFQv/0hUL/9IVC//rIqf/////////////////9/f31////DP7+/ln////////////////f9v7/Cbz2/zOwhv9TqDT/U6g0/2KwRv/v9+z///////////////////////////////////////////////////////738//1kFT/9IVC//SFQv/0hUL/9plg///////////////////////+/v5W/f39nP///////////////4jf/f8FvPv/Bbz7/yG1s/9QqDz/vN2w//////////////////////////////////////////////////////////////////rHqP/0hUL/9IVC//SFQv/0hUL//vDn//////////////////39/Zn9/f3L////////////////R878/wW8+/8FvPv/Bbz7/y7C5P/7/fr//////////////////////////////////////////////////////////////////ere//SFQv/0hUL/9IVC//SFQv/718H//////////////////f39yP39/ez///////////////8cwvv/Bbz7/wW8+/8FvPv/WNL8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//rIqv/////////////////9/f3q/f39+v///////////////we9+/8FvPv/Bbz7/wW8+/993P3///////////////////////////////////////SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/+cGf//////////////////39/fn9/f36////////////////B737/wW8+/8FvPv/Bbz7/33c/f//////////////////////////////////////9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/6xaX//////////////////f39+f39/e3///////////////8cwvv/Bbz7/wW8+/8FvPv/WdP8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//vVv//////////////////9/f3q/f39y////////////////0bN/P8FvPv/Bbz7/wW8+/8hrvn/+/v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////39/cj9/f2c////////////////ht/9/wW8+/8FvPv/FZP1/zRJ6/+zuPf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////f39mf7+/lr////////////////d9v7/B7n7/yB38f81Q+r/NUPq/0hV7P/u8P3////////////////////////////////////////////////////////////////////////////////////////////////////////////+/v5X////D/39/ff///////////////9tkPT/NUPq/zVD6v81Q+r/NUPq/2Fs7//y8v7////////////////////////////////////////////09f7//////////////////////////////////////////////////f399f7+/g0AAAAA/f39n////////////////+Tm/P89Suv/NUPq/zVD6v81Q+r/NUPq/1Bc7f/IzPn/////////////////////////////////x8v5/0xY7P+MlPP////////////////////////////////////////////9/f2cAAAAAAAAAAD+/v4n/f39/P///////////////7W69/81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9ZZe7/k5v0/6609/+vtff/lJv0/1pm7v81Q+r/NUPq/zVD6v+GjvL//v7//////////////////////////////f39+/7+/iQAAAAAAAAAAAAAAAD9/f2N/////////////////////6Cn9f81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v+BivL////////////////////////////9/f2KAAAAAAAAAAAAAAAAAAAAAP7+/gv9/f3V/////////////////////7W69/8+S+v/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/P0zr/7q/+P///////////////////////f390v7+/gkAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3r/////////////////////+Xn/P94gfH/NkTq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NkTq/3Z/8f/l5/z///////////////////////39/er+/v4kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f3r///////////////////////////k5vz/nqX1/2p08P9IVez/OEbq/zdF6v9GU+z/aHLv/5qh9f/i5Pz////////////////////////////9/f3q////MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3V/////////////////////////////////////////////////////////////////////////////////////////////////f390v7+/iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr9/f2N/f39/P///////////////////////////////////////////////////////////////////////////f39+/39/Yv+/v4JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4n/f39n/39/ff//////////////////////////////////////////////////////f399v39/Z3+/v4lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Dv7+/lr9/f2c/f39y/39/e39/f36/f39+v39/ez9/f3L/f39nP7+/ln+/v4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAcAAAAPAAAAD4AAAB/AAAA/4AAAf/AAAP/8AAP//wAP/</Image>
 <Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
 <Url type="text/html" method="GET" template="https://www.google.com/search" rel="searchform">
-  <Param name="q" value="{searchTerms}"/>
-  <Param name="ie" value="utf-8"/>
-  <Param name="oe" value="utf-8"/>
   <MozParam name="client" condition="purpose" purpose="keyword" value="firefox-b-1-ab"/>
   <MozParam name="client" condition="purpose" purpose="searchbar" value="firefox-b-1"/>
+  <Param name="q" value="{searchTerms}"/>
 </Url>
 </SearchPlugin>
--- a/browser/components/search/searchplugins/google.xml
+++ b/browser/components/search/searchplugins/google.xml
@@ -4,15 +4,13 @@
 
 <SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
 <ShortName>Google</ShortName>
 <Description>Google Search</Description>
 <InputEncoding>UTF-8</InputEncoding>
 <Image width="16" height="16">data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///zD9/f2W/f392P39/fn9/f35/f391/39/ZT+/v4uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Cf39/Zn///////////////////////////////////////////39/ZX///8IAAAAAAAAAAAAAAAA/v7+Cf39/cH/////+v35/7TZp/92ul3/WKs6/1iqOv9yuFn/rNWd//j79v///////f39v////wgAAAAAAAAAAP39/Zn/////7PXp/3G3WP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP+Or1j//vDo///////9/f2VAAAAAP///zD/////+vz5/3G3V/9TqDT/WKo6/6LQkf/U6cz/1urO/6rUm/+Zo0r/8IZB//adZ////v7///////7+/i79/f2Y/////4nWzf9Lqkj/Vqo4/9Xqzv///////////////////////ebY//SHRv/0hUL//NjD///////9/f2U/f392v////8sxPH/Ebzt/43RsP/////////////////////////////////4roL/9IVC//i1jf///////f391/39/fr/////Cr37/wW8+/+16/7/////////////////9IVC//SFQv/0hUL/9IVC//SFQv/3pnX///////39/fn9/f36/////wu++/8FvPv/tuz+//////////////////SFQv/0hUL/9IVC//SFQv/0hUL/96p7///////9/f35/f392/////81yfz/CrL5/2uk9v///////////////////////////////////////////////////////f392P39/Zn/////ks/7/zdS7P84Rur/0NT6///////////////////////9/f////////////////////////39/Zb+/v4y//////n5/v9WYu3/NUPq/ztJ6/+VnPT/z9L6/9HU+v+WnfT/Ul7t/+Hj/P////////////////////8wAAAAAP39/Z3/////6Or9/1hj7v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9sdvD////////////9/f2YAAAAAAAAAAD///8K/f39w//////5+f7/paz2/11p7v88Suv/Okfq/1pm7v+iqfX/+fn+///////9/f3B/v7+CQAAAAAAAAAAAAAAAP///wr9/f2d///////////////////////////////////////////9/f2Z/v7+CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f2Z/f392/39/fr9/f36/f392v39/Zj///8wAAAAAAAAAAAAAAAAAAAAAPAPAADAAwAAgAEAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/g3+/v5X/f39mf39/cj9/f3q/f39+f39/fn9/f3q/f39yP39/Zn+/v5W////DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f2c/f399f/////////////////////////////////////////////////////9/f31/f39mv7+/iMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/gn9/f2K/f39+////////////////////////////////////////////////////////////////////////////f39+v39/Yf///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4k/f390v////////////////////////////////////////////////////////////////////////////////////////////////39/dD///8iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////MP39/er//////////////////////////+r05v+v16H/gsBs/2WxSf9Wqjj/Vqk3/2OwRv99vWX/pdKV/97u2P////////////////////////////39/ej+/v4vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f3q/////////////////////+v15/+Pxnv/VKk2/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/36+Z//d7tf///////////////////////39/ej///8iAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K/f390//////////////////////E4bn/XKw+/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1apN/+x0pv///////////////////////39/dD///8IAAAAAAAAAAAAAAAAAAAAAP39/Yv/////////////////////sdij/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/YKU1/8qOPv/5wZ////////////////////////39/YcAAAAAAAAAAAAAAAD+/v4l/f39+////////////////8Lgt/9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9utlT/n86N/7faqv+426v/pdKV/3u8ZP9UqDX/U6g0/3egN//jiUH/9IVC//SFQv/82MP//////////////////f39+v7+/iMAAAAAAAAAAP39/Z3////////////////q9Ob/W6w+/1OoNP9TqDT/U6g0/1OoNP9nskz/zOXC/////////////////////////////////+Dv2v+osWP/8YVC//SFQv/0hUL/9IVC//WQVP/++fb//////////////////f39mgAAAAD+/v4O/f399v///////////////4LHj/9TqDT/U6g0/1OoNP9TqDT/dblc//L58P/////////////////////////////////////////////8+v/3p3f/9IVC//SFQv/0hUL/9IVC//rIqf/////////////////9/f31////DP7+/ln////////////////f9v7/Cbz2/zOwhv9TqDT/U6g0/2KwRv/v9+z///////////////////////////////////////////////////////738//1kFT/9IVC//SFQv/0hUL/9plg///////////////////////+/v5W/f39nP///////////////4jf/f8FvPv/Bbz7/yG1s/9QqDz/vN2w//////////////////////////////////////////////////////////////////rHqP/0hUL/9IVC//SFQv/0hUL//vDn//////////////////39/Zn9/f3L////////////////R878/wW8+/8FvPv/Bbz7/y7C5P/7/fr//////////////////////////////////////////////////////////////////ere//SFQv/0hUL/9IVC//SFQv/718H//////////////////f39yP39/ez///////////////8cwvv/Bbz7/wW8+/8FvPv/WNL8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//rIqv/////////////////9/f3q/f39+v///////////////we9+/8FvPv/Bbz7/wW8+/993P3///////////////////////////////////////SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/+cGf//////////////////39/fn9/f36////////////////B737/wW8+/8FvPv/Bbz7/33c/f//////////////////////////////////////9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/6xaX//////////////////f39+f39/e3///////////////8cwvv/Bbz7/wW8+/8FvPv/WdP8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//vVv//////////////////9/f3q/f39y////////////////0bN/P8FvPv/Bbz7/wW8+/8hrvn/+/v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////39/cj9/f2c////////////////ht/9/wW8+/8FvPv/FZP1/zRJ6/+zuPf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////f39mf7+/lr////////////////d9v7/B7n7/yB38f81Q+r/NUPq/0hV7P/u8P3////////////////////////////////////////////////////////////////////////////////////////////////////////////+/v5X////D/39/ff///////////////9tkPT/NUPq/zVD6v81Q+r/NUPq/2Fs7//y8v7////////////////////////////////////////////09f7//////////////////////////////////////////////////f399f7+/g0AAAAA/f39n////////////////+Tm/P89Suv/NUPq/zVD6v81Q+r/NUPq/1Bc7f/IzPn/////////////////////////////////x8v5/0xY7P+MlPP////////////////////////////////////////////9/f2cAAAAAAAAAAD+/v4n/f39/P///////////////7W69/81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9ZZe7/k5v0/6609/+vtff/lJv0/1pm7v81Q+r/NUPq/zVD6v+GjvL//v7//////////////////////////////f39+/7+/iQAAAAAAAAAAAAAAAD9/f2N/////////////////////6Cn9f81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v+BivL////////////////////////////9/f2KAAAAAAAAAAAAAAAAAAAAAP7+/gv9/f3V/////////////////////7W69/8+S+v/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/P0zr/7q/+P///////////////////////f390v7+/gkAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3r/////////////////////+Xn/P94gfH/NkTq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NkTq/3Z/8f/l5/z///////////////////////39/er+/v4kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f3r///////////////////////////k5vz/nqX1/2p08P9IVez/OEbq/zdF6v9GU+z/aHLv/5qh9f/i5Pz////////////////////////////9/f3q////MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3V/////////////////////////////////////////////////////////////////////////////////////////////////f390v7+/iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr9/f2N/f39/P///////////////////////////////////////////////////////////////////////////f39+/39/Yv+/v4JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4n/f39n/39/ff//////////////////////////////////////////////////////f399v39/Z3+/v4lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Dv7+/lr9/f2c/f39y/39/e39/f36/f39+v39/ez9/f3L/f39nP7+/ln+/v4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAcAAAAPAAAAD4AAAB/AAAA/4AAAf/AAAP/8AAP//wAP/</Image>
 <Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
 <Url type="text/html" method="GET" template="https://www.google.com/search" rel="searchform">
-  <Param name="q" value="{searchTerms}"/>
-  <Param name="ie" value="utf-8"/>
-  <Param name="oe" value="utf-8"/>
   <MozParam name="client" condition="purpose" purpose="keyword" value="firefox-b-ab"/>
   <MozParam name="client" condition="purpose" purpose="searchbar" value="firefox-b"/>
+  <Param name="q" value="{searchTerms}"/>
 </Url>
 </SearchPlugin>
--- a/browser/components/search/test/browser_google.js
+++ b/browser/components/search/test/browser_google.js
@@ -6,17 +6,17 @@
  */
 
 "use strict";
 
 let expectedEngine = {
   name: "Google",
   alias: null,
   description: "Google Search",
-  searchForm: "https://www.google.com/search?q=&ie=utf-8&oe=utf-8",
+  searchForm: "https://www.google.com/search?",
   hidden: false,
   wrappedJSObject: {
     queryCharset: "UTF-8",
     "_iconURL": "data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///zD9/f2W/f392P39/fn9/f35/f391/39/ZT+/v4uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Cf39/Zn///////////////////////////////////////////39/ZX///8IAAAAAAAAAAAAAAAA/v7+Cf39/cH/////+v35/7TZp/92ul3/WKs6/1iqOv9yuFn/rNWd//j79v///////f39v////wgAAAAAAAAAAP39/Zn/////7PXp/3G3WP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP+Or1j//vDo///////9/f2VAAAAAP///zD/////+vz5/3G3V/9TqDT/WKo6/6LQkf/U6cz/1urO/6rUm/+Zo0r/8IZB//adZ////v7///////7+/i79/f2Y/////4nWzf9Lqkj/Vqo4/9Xqzv///////////////////////ebY//SHRv/0hUL//NjD///////9/f2U/f392v////8sxPH/Ebzt/43RsP/////////////////////////////////4roL/9IVC//i1jf///////f391/39/fr/////Cr37/wW8+/+16/7/////////////////9IVC//SFQv/0hUL/9IVC//SFQv/3pnX///////39/fn9/f36/////wu++/8FvPv/tuz+//////////////////SFQv/0hUL/9IVC//SFQv/0hUL/96p7///////9/f35/f392/////81yfz/CrL5/2uk9v///////////////////////////////////////////////////////f392P39/Zn/////ks/7/zdS7P84Rur/0NT6///////////////////////9/f////////////////////////39/Zb+/v4y//////n5/v9WYu3/NUPq/ztJ6/+VnPT/z9L6/9HU+v+WnfT/Ul7t/+Hj/P////////////////////8wAAAAAP39/Z3/////6Or9/1hj7v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9sdvD////////////9/f2YAAAAAAAAAAD///8K/f39w//////5+f7/paz2/11p7v88Suv/Okfq/1pm7v+iqfX/+fn+///////9/f3B/v7+CQAAAAAAAAAAAAAAAP///wr9/f2d///////////////////////////////////////////9/f2Z/v7+CQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f2Z/f392/39/fr9/f36/f392v39/Zj///8wAAAAAAAAAAAAAAAAAAAAAPAPAADAAwAAgAEAAIABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIABAACAAQAAwAMAAPAPAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/g3+/v5X/f39mf39/cj9/f3q/f39+f39/fn9/f3q/f39yP39/Zn+/v5W////DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f2c/f399f/////////////////////////////////////////////////////9/f31/f39mv7+/iMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/gn9/f2K/f39+////////////////////////////////////////////////////////////////////////////f39+v39/Yf///8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4k/f390v////////////////////////////////////////////////////////////////////////////////////////////////39/dD///8iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////MP39/er//////////////////////////+r05v+v16H/gsBs/2WxSf9Wqjj/Vqk3/2OwRv99vWX/pdKV/97u2P////////////////////////////39/ej+/v4vAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/iT9/f3q/////////////////////+v15/+Pxnv/VKk2/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/36+Z//d7tf///////////////////////39/ej///8iAAAAAAAAAAAAAAAAAAAAAAAAAAD///8K/f390//////////////////////E4bn/XKw+/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1apN/+x0pv///////////////////////39/dD///8IAAAAAAAAAAAAAAAAAAAAAP39/Yv/////////////////////sdij/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9TqDT/YKU1/8qOPv/5wZ////////////////////////39/YcAAAAAAAAAAAAAAAD+/v4l/f39+////////////////8Lgt/9TqDT/U6g0/1OoNP9TqDT/U6g0/1OoNP9utlT/n86N/7faqv+426v/pdKV/3u8ZP9UqDX/U6g0/3egN//jiUH/9IVC//SFQv/82MP//////////////////f39+v7+/iMAAAAAAAAAAP39/Z3////////////////q9Ob/W6w+/1OoNP9TqDT/U6g0/1OoNP9nskz/zOXC/////////////////////////////////+Dv2v+osWP/8YVC//SFQv/0hUL/9IVC//WQVP/++fb//////////////////f39mgAAAAD+/v4O/f399v///////////////4LHj/9TqDT/U6g0/1OoNP9TqDT/dblc//L58P/////////////////////////////////////////////8+v/3p3f/9IVC//SFQv/0hUL/9IVC//rIqf/////////////////9/f31////DP7+/ln////////////////f9v7/Cbz2/zOwhv9TqDT/U6g0/2KwRv/v9+z///////////////////////////////////////////////////////738//1kFT/9IVC//SFQv/0hUL/9plg///////////////////////+/v5W/f39nP///////////////4jf/f8FvPv/Bbz7/yG1s/9QqDz/vN2w//////////////////////////////////////////////////////////////////rHqP/0hUL/9IVC//SFQv/0hUL//vDn//////////////////39/Zn9/f3L////////////////R878/wW8+/8FvPv/Bbz7/y7C5P/7/fr//////////////////////////////////////////////////////////////////ere//SFQv/0hUL/9IVC//SFQv/718H//////////////////f39yP39/ez///////////////8cwvv/Bbz7/wW8+/8FvPv/WNL8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//rIqv/////////////////9/f3q/f39+v///////////////we9+/8FvPv/Bbz7/wW8+/993P3///////////////////////////////////////SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/+cGf//////////////////39/fn9/f36////////////////B737/wW8+/8FvPv/Bbz7/33c/f//////////////////////////////////////9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/6xaX//////////////////f39+f39/e3///////////////8cwvv/Bbz7/wW8+/8FvPv/WdP8///////////////////////////////////////0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//SFQv/0hUL/9IVC//vVv//////////////////9/f3q/f39y////////////////0bN/P8FvPv/Bbz7/wW8+/8hrvn/+/v///////////////////////////////////////////////////////////////////////////////////////////////////////////////////39/cj9/f2c////////////////ht/9/wW8+/8FvPv/FZP1/zRJ6/+zuPf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////f39mf7+/lr////////////////d9v7/B7n7/yB38f81Q+r/NUPq/0hV7P/u8P3////////////////////////////////////////////////////////////////////////////////////////////////////////////+/v5X////D/39/ff///////////////9tkPT/NUPq/zVD6v81Q+r/NUPq/2Fs7//y8v7////////////////////////////////////////////09f7//////////////////////////////////////////////////f399f7+/g0AAAAA/f39n////////////////+Tm/P89Suv/NUPq/zVD6v81Q+r/NUPq/1Bc7f/IzPn/////////////////////////////////x8v5/0xY7P+MlPP////////////////////////////////////////////9/f2cAAAAAAAAAAD+/v4n/f39/P///////////////7W69/81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v9ZZe7/k5v0/6609/+vtff/lJv0/1pm7v81Q+r/NUPq/zVD6v+GjvL//v7//////////////////////////////f39+/7+/iQAAAAAAAAAAAAAAAD9/f2N/////////////////////6Cn9f81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v+BivL////////////////////////////9/f2KAAAAAAAAAAAAAAAAAAAAAP7+/gv9/f3V/////////////////////7W69/8+S+v/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/P0zr/7q/+P///////////////////////f390v7+/gkAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3r/////////////////////+Xn/P94gfH/NkTq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NUPq/zVD6v81Q+r/NkTq/3Z/8f/l5/z///////////////////////39/er+/v4kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/jL9/f3r///////////////////////////k5vz/nqX1/2p08P9IVez/OEbq/zdF6v9GU+z/aHLv/5qh9f/i5Pz////////////////////////////9/f3q////MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7+/ib9/f3V/////////////////////////////////////////////////////////////////////////////////////////////////f390v7+/iQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wr9/f2N/f39/P///////////////////////////////////////////////////////////////////////////f39+/39/Yv+/v4JAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+/v4n/f39n/39/ff//////////////////////////////////////////////////////f399v39/Z3+/v4lAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7+Dv7+/lr9/f2c/f39y/39/e39/f36/f39+v39/ez9/f3L/f39nP7+/ln+/v4OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/AA///AAD//AAAP/gAAB/wAAAP4AAAB8AAAAPAAAADgAAAAYAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABgAAAAcAAAAPAAAAD4AAAB/AAAA/4AAAf/AAAP/8AAP//wAP/",
     _urls: [
       {
         type: "application/x-suggestions+json",
         method: "GET",
@@ -28,90 +28,83 @@ let expectedEngine = {
         method: "GET",
         template: "https://www.google.com/search",
         params: [
           {
             "name": "q",
             "value": "{searchTerms}",
             "purpose": undefined,
           },
-          {
-            "name": "ie",
-            "value": "utf-8",
-            "purpose": undefined,
-          },
-          {
-            "name": "oe",
-            "value": "utf-8",
-            "purpose": undefined,
-          },
         ],
         mozparams: {
         },
       },
     ],
   },
 };
 
 function test() {
   let engine = Services.search.getEngineByName("Google");
   ok(engine, "Found Google search engine");
 
   let region = Services.prefs.getCharPref("browser.search.region");
   let code = "";
+  let keywordCode = "";
   switch (region) {
     case "US":
       code = "firefox-b-1";
       break;
     case "DE":
       code = "firefox-b";
       break;
     case "RU":
       // Covered by test but doesn't use a code
       break;
   }
 
-  let base = "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8";
-  // Keyword uses a slightly different code
-  let keywordBase = base;
   if (code) {
-    let suffix = `&client=${code}`;
-    base += suffix;
-    keywordBase += `${suffix}-ab`;
-    expectedEngine.searchForm += suffix;
+    expectedEngine.searchForm += `client=${code}&`;
+    keywordCode = `${code}-ab`;
     let urlParams = expectedEngine.wrappedJSObject._urls[1].params;
-    urlParams.push({
-      name: "client",
-      value: `${code}-ab`,
-      purpose: "keyword",
-    });
-    urlParams.push({
+    urlParams.unshift({
       name: "client",
       value: code,
       purpose: "searchbar",
     });
+    urlParams.unshift({
+      name: "client",
+      value: keywordCode,
+      purpose: "keyword",
+    });
   }
+  expectedEngine.searchForm += "q=";
 
   let url;
 
   // Test search URLs (including purposes).
   let purposes = ["", "contextmenu", "searchbar", "homepage", "newtab"];
+  let urlParams;
   for (let purpose of purposes) {
     url = engine.getSubmission("foo", null, purpose).uri.spec;
-    is(url, base, `Check ${purpose} search URL for 'foo'`);
+    urlParams = new URLSearchParams(url.split("?")[1]);
+    is(urlParams.get("client"), code, "Check ${purpose} search URL for code");
+    is(urlParams.get("q"), "foo", `Check ${purpose} search URL for 'foo'`);
   }
   url = engine.getSubmission("foo", null, "keyword").uri.spec;
-  is(url, keywordBase, "Check keyword search URL for 'foo'");
+  urlParams = new URLSearchParams(url.split("?")[1]);
+  is(urlParams.get("client"), keywordCode, "Check keyword search URL for code");
+  is(urlParams.get("q"), "foo", `Check keyword search URL for 'foo'`);
 
   // Check search suggestion URL.
   url = engine.getSubmission("foo", "application/x-suggestions+json").uri.spec;
   is(url, "https://www.google.com/complete/search?client=firefox&q=foo", "Check search suggestion URL for 'foo'");
 
   // Check result parsing and alternate domains.
-  let alternateBase = base.replace("www.google.com", "www.google.fr");
+  let base = "https://www.google.com/search?q=foo";
   is(Services.search.parseSubmissionURL(base).terms, "foo",
      "Check result parsing");
+  let alternateBase = base.replace("www.google.com", "www.google.fr");
   is(Services.search.parseSubmissionURL(alternateBase).terms, "foo",
      "Check alternate domain");
 
   // Check all other engine properties.
   isSubObjectOf(expectedEngine, engine, "Google");
 }
--- a/browser/components/search/test/browser_google_behavior.js
+++ b/browser/components/search/test/browser_google_behavior.js
@@ -6,17 +6,16 @@
  * TODO: This test is a near duplicate of browser_searchEngine_behaviors.js but
  * specific to Google. This is required due to bug 1315953.
  */
 
 "use strict";
 
 let searchEngineDetails = [{
   alias: "g",
-  baseURL: "https://www.google.com/search?q=foo&ie=utf-8&oe=utf-8",
   codes: {
     context: "",
     keyword: "",
     newTab: "",
     submission: "",
   },
   name: "Google",
 }];
@@ -29,21 +28,20 @@ switch (region) {
     break;
   case "DE":
     code = "firefox-b";
     break;
 }
 
 if (code) {
   let codes = searchEngineDetails[0].codes;
-  let suffix = `&client=${code}`;
-  codes.context = suffix;
-  codes.newTab = suffix;
-  codes.submission = suffix;
-  codes.keyword = `${suffix}-ab`;
+  codes.context = code;
+  codes.newTab = code;
+  codes.submission = code;
+  codes.keyword = `${code}-ab`;
 }
 
 function promiseContentSearchReady(browser) {
   return ContentTask.spawn(browser, {}, async function(args) {
     return new Promise(resolve => {
       if (content.wrappedJSObject.gContentSearchController) {
         let searchController = content.wrappedJSObject.gContentSearchController;
         if (searchController.defaultEngine) {
@@ -75,70 +73,69 @@ for (let engine of searchEngineDetails) 
 
 async function testSearchEngine(engineDetails) {
   let engine = Services.search.getEngineByName(engineDetails.name);
   Assert.ok(engine, `${engineDetails.name} is installed`);
 
   Services.search.currentEngine = engine;
   engine.alias = engineDetails.alias;
 
-  let base = engineDetails.baseURL;
-
   // Test search URLs (including purposes).
   let url = engine.getSubmission("foo").uri.spec;
-  Assert.equal(url, base + engineDetails.codes.submission, "Check search URL for 'foo'");
+  let urlParams = new URLSearchParams(url.split("?")[1]);
+  Assert.equal(urlParams.get("q"), "foo", "Check search URL for 'foo'");
 
   let engineTests = [
     {
       name: "context menu search",
-      searchURL: base + engineDetails.codes.context,
+      code: engineDetails.codes.context,
       run() {
         // Simulate a contextmenu search
         // FIXME: This is a bit "low-level"...
         BrowserSearch._loadSearch("foo", false, "contextmenu", Services.scriptSecurityManager.getSystemPrincipal());
       },
     },
     {
       name: "keyword search",
-      searchURL: base + engineDetails.codes.keyword,
+      code: engineDetails.codes.keyword,
       run() {
         gURLBar.value = "? foo";
         gURLBar.focus();
         EventUtils.synthesizeKey("KEY_Enter");
       },
     },
     {
       name: "keyword search with alias",
-      searchURL: base + engineDetails.codes.keyword,
+      code: engineDetails.codes.keyword,
       run() {
         gURLBar.value = `${engineDetails.alias} foo`;
         gURLBar.focus();
         EventUtils.synthesizeKey("KEY_Enter");
       },
     },
     {
       name: "search bar search",
-      searchURL: base + engineDetails.codes.submission,
+      code: engineDetails.codes.submission,
       async preTest() {
         await gCUITestUtils.addSearchBar();
       },
       run() {
         let sb = BrowserSearch.searchBar;
         sb.focus();
         sb.value = "foo";
         EventUtils.synthesizeKey("KEY_Enter");
       },
       postTest() {
         BrowserSearch.searchBar.value = "";
         gCUITestUtils.removeSearchBar();
       },
     },
     {
       name: "new tab search",
-      searchURL: base + engineDetails.codes.newTab,
+      code: engineDetails.codes.newTab,
       async preTest(tab) {
         let browser = tab.linkedBrowser;
         await BrowserTestUtils.loadURI(browser, "about:newtab");
         await BrowserTestUtils.browserLoaded(browser);
 
         await promiseContentSearchReady(browser);
       },
       async run(tab) {
@@ -162,17 +159,19 @@ async function testSearchEngine(engineDe
     }
 
     let stateChangePromise = promiseStateChangeURI();
 
     await test.run(tab);
 
     let receivedURI = await stateChangePromise;
 
-    Assert.equal(receivedURI, test.searchURL);
+    let receivedURLParams = new URLSearchParams(receivedURI.split("?")[1]);
+
+    Assert.equal(receivedURLParams.get("client"), test.code);
 
     if (test.postTest) {
       await test.postTest(tab);
     }
   }
 
   engine.alias = undefined;
   BrowserTestUtils.removeTab(tab);
--- a/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
+++ b/browser/extensions/formautofill/FormAutofillDoorhanger.jsm
@@ -234,17 +234,17 @@ let FormAutofillDoorhanger = {
    * @param  {string} link
    *         Makes it possible to open and highlight a section in preferences
    */
   _appendPrivacyPanelLink(content, message, link) {
     let chromeDoc = content.ownerDocument;
     let privacyLinkElement = chromeDoc.createXULElement("label");
     privacyLinkElement.className = "text-link";
     privacyLinkElement.setAttribute("useoriginprincipal", true);
-    privacyLinkElement.setAttribute("href", link || "about:preferences#privacy");
+    privacyLinkElement.setAttribute("href", link || "about:preferences#privacy-form-autofill");
     privacyLinkElement.setAttribute("value", message);
     content.appendChild(privacyLinkElement);
   },
 
   /**
    * Append the description section to the popupnotificationcontent.
    * @param  {XULElement} content
    *         popupnotificationcontent
--- a/browser/extensions/formautofill/FormAutofillParent.jsm
+++ b/browser/extensions/formautofill/FormAutofillParent.jsm
@@ -242,17 +242,17 @@ FormAutofillParent.prototype = {
         break;
       }
       case "FormAutofill:OnFormSubmit": {
         await this._onFormSubmit(data, target);
         break;
       }
       case "FormAutofill:OpenPreferences": {
         const win = BrowserWindowTracker.getTopWindow();
-        win.openPreferences("panePrivacy", {origin: "autofillFooter"});
+        win.openPreferences("privacy-form-autofill", {origin: "autofillFooter"});
         break;
       }
       case "FormAutofill:GetDecryptedString": {
         let {cipherText, reauth} = data;
         let string;
         try {
           string = await MasterPassword.decrypt(cipherText, reauth);
         } catch (e) {
--- a/browser/extensions/formautofill/content/autofillEditForms.js
+++ b/browser/extensions/formautofill/content/autofillEditForms.js
@@ -118,16 +118,17 @@ class EditAutofillForm {
 class EditAddress extends EditAutofillForm {
   /**
    * @param {HTMLElement[]} elements
    * @param {object} record
    * @param {object} config
    * @param {string[]} config.DEFAULT_REGION
    * @param {function} config.getFormFormat Function to return form layout info for a given country.
    * @param {string[]} config.countries
+   * @param {boolean} [config.noValidate=undefined] Whether to validate the form
    */
   constructor(elements, record, config) {
     super(elements);
 
     Object.assign(this, config);
     let {form} = this._elements;
     Object.assign(this._elements, {
       addressLevel3Label: form.querySelector("#address-level3-container > .label-text"),
@@ -138,19 +139,17 @@ class EditAddress extends EditAutofillFo
     });
 
     this.populateCountries();
     // Need to populate the countries before trying to set the initial country.
     // Also need to use this._record so it has the default country selected.
     this.loadRecord(record);
     this.attachEventListeners();
 
-    if (config.novalidate) {
-      this.form.setAttribute("novalidate", "true");
-    }
+    form.noValidate = !!config.noValidate;
   }
 
   loadRecord(record) {
     this._record = record;
     if (!record) {
       record = {
         country: this.DEFAULT_REGION,
       };
--- a/browser/extensions/formautofill/content/editAddress.xhtml
+++ b/browser/extensions/formautofill/content/editAddress.xhtml
@@ -85,27 +85,30 @@
 
     let {
       DEFAULT_REGION,
       countries,
     } = FormAutofill;
     let {
       getFormFormat,
     } = FormAutofillUtils;
-    let record = window.arguments && window.arguments[0];
-    let novalidate = window.arguments && window.arguments[1] == "novalidate";
+    let args = window.arguments || [];
+    let {
+      record,
+      noValidate,
+    } = args[0] || {};
 
     /* import-globals-from autofillEditForms.js */
     var fieldContainer = new EditAddress({
       form: document.getElementById("form"),
     }, record, {
       DEFAULT_REGION,
       getFormFormat: getFormFormat.bind(FormAutofillUtils),
       countries,
-      novalidate,
+      noValidate,
     });
 
     /* import-globals-from editDialog.js */
     new EditAddressDialog({
       title: document.querySelector("title"),
       fieldContainer,
       controlsContainer: document.getElementById("controls-container"),
       cancel: document.getElementById("cancel"),
--- a/browser/extensions/formautofill/content/editCreditCard.xhtml
+++ b/browser/extensions/formautofill/content/editCreditCard.xhtml
@@ -77,17 +77,21 @@
     "use strict";
 
     (async () => {
       let {
         getAddressLabel,
         isCCNumber,
         getCreditCardNetworks,
       } = FormAutofillUtils;
-      let record = window.arguments && window.arguments[0];
+      let args = window.arguments || [];
+      let {
+        record,
+      } = args[0] || {};
+
       let addresses = {};
       for (let address of await formAutofillStorage.addresses.getAll()) {
         addresses[address.guid] = address;
       }
 
       /* import-globals-from autofillEditForms.js */
       let fieldContainer = new EditCreditCard({
         form: document.getElementById("form"),
--- a/browser/extensions/formautofill/content/formautofill.xml
+++ b/browser/extensions/formautofill/content/formautofill.xml
@@ -154,17 +154,17 @@
     </xbl:content>
 
     <handlers>
       <handler event="click" button="0"><![CDATA[
         if (this._warningTextBox.contains(event.originalTarget)) {
           return;
         }
 
-        window.openPreferences("panePrivacy", {origin: "autofillFooter"});
+        window.openPreferences("privacy-form-autofill", {origin: "autofillFooter"});
       ]]></handler>
     </handlers>
 
     <implementation implements="nsIDOMXULSelectControlItemElement">
       <constructor>
         <![CDATA[
           this._itemBox = document.getAnonymousElementByAttribute(
             this, "anonid", "autofill-footer"
--- a/browser/extensions/formautofill/content/manageDialog.js
+++ b/browser/extensions/formautofill/content/manageDialog.js
@@ -289,17 +289,22 @@ class ManageAddresses extends ManageReco
   }
 
   /**
    * Open the edit address dialog to create/edit an address.
    *
    * @param  {object} address [optional]
    */
   openEditDialog(address) {
-    this.prefWin.gSubDialog.open(EDIT_ADDRESS_URL, null, address, "novalidate");
+    this.prefWin.gSubDialog.open(EDIT_ADDRESS_URL, null, {
+      record: address,
+      // Don't validate in preferences since it's fine for fields to be missing
+      // for autofill purposes. For PaymentRequest addresses get more validation.
+      noValidate: true,
+    });
   }
 
   getLabel(address) {
     return FormAutofillUtils.getAddressLabel(address);
   }
 }
 
 class ManageCreditCards extends ManageRecords {
@@ -324,17 +329,19 @@ class ManageCreditCards extends ManageRe
     // If master password is set, ask for password if user is trying to edit an
     // existing credit card.
     if (!creditCard || !this._hasMasterPassword || await MasterPassword.ensureLoggedIn(true)) {
       let decryptedCCNumObj = {};
       if (creditCard) {
         decryptedCCNumObj["cc-number"] = await MasterPassword.decrypt(creditCard["cc-number-encrypted"]);
       }
       let decryptedCreditCard = Object.assign({}, creditCard, decryptedCCNumObj);
-      this.prefWin.gSubDialog.open(EDIT_CREDIT_CARD_URL, "resizable=no", decryptedCreditCard);
+      this.prefWin.gSubDialog.open(EDIT_CREDIT_CARD_URL, "resizable=no", {
+        record: decryptedCreditCard,
+      });
     }
   }
 
   /**
    * Get credit card display label. It should display masked numbers and the
    * cardholder's name, separated by a comma. If `showCreditCards` is set to
    * true, decrypted credit card numbers are shown instead.
    *
--- a/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js
+++ b/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js
@@ -96,27 +96,49 @@ add_task(async function test_saveAddress
 
 add_task(async function test_editAddress() {
   let addresses = await getAddresses();
   await testDialog(EDIT_ADDRESS_DIALOG_URL, win => {
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_RIGHT", {}, win);
     EventUtils.synthesizeKey("test", {}, win);
     win.document.querySelector("#save").click();
-  }, addresses[0]);
+  }, {
+    record: addresses[0],
+  });
   addresses = await getAddresses();
 
   is(addresses.length, 1, "only one address is in storage");
   is(addresses[0]["given-name"], TEST_ADDRESS_1["given-name"] + "test", "given-name changed");
   await removeAddresses([addresses[0].guid]);
 
   addresses = await getAddresses();
   is(addresses.length, 0, "Address storage is empty");
 });
 
+add_task(async function test_editSparseAddress() {
+  let record = {...TEST_ADDRESS_1};
+  info("delete some usually required properties");
+  delete record["street-address"];
+  delete record["address-level1"];
+  delete record["address-level2"];
+  await testDialog(EDIT_ADDRESS_DIALOG_URL, win => {
+    is(win.document.querySelectorAll(":-moz-ui-invalid").length, 0,
+       "Check no fields are visually invalid");
+    EventUtils.synthesizeKey("VK_TAB", {}, win);
+    EventUtils.synthesizeKey("VK_RIGHT", {}, win);
+    EventUtils.synthesizeKey("test", {}, win);
+    is(win.document.querySelector("#save").disabled, false,
+       "Save button should be enabled after an edit");
+    win.document.querySelector("#cancel").click();
+  }, {
+    record,
+  });
+});
+
 add_task(async function test_saveAddressCA() {
   await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => {
     let doc = win.document;
     // Change country to verify labels
     doc.querySelector("#country").focus();
     EventUtils.synthesizeKey("Canada", {}, win);
 
     await TestUtils.waitForCondition(() => {
@@ -297,18 +319,21 @@ add_task(async function test_countryFiel
         delete labelEl.dataset.localization;
       }
 
       info(`Selecting '${countryOption.label}' (${countryOption.value})`);
       EventUtils.synthesizeKey(countryOption.label, {}, win);
 
       // Check that the labels were filled
       for (let labelEl of mutatableLabels) {
-        await TestUtils.waitForCondition(() => labelEl.textContent,
-                                         "Wait for label to be populated by the mutation observer");
+        if (!labelEl.textContent) {
+          await TestUtils.waitForCondition(() => labelEl.textContent,
+                                           "Wait for label to be populated by the mutation observer",
+                                           10);
+        }
         isnot(labelEl.textContent, "",
               "Ensure textContent is non-empty for: " + countryOption.value);
         is(labelEl.dataset.localization, undefined,
            "Ensure data-localization was removed: " + countryOption.value);
       }
     }
 
     doc.querySelector("#cancel").click();
--- a/browser/extensions/formautofill/test/browser/browser_editCreditCardDialog.js
+++ b/browser/extensions/formautofill/test/browser/browser_editCreditCardDialog.js
@@ -133,17 +133,19 @@ add_task(async function test_editCreditC
   await testDialog(EDIT_CREDIT_CARD_DIALOG_URL, (win) => {
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_RIGHT", {}, win);
     EventUtils.synthesizeKey("test", {}, win);
     win.document.querySelector("#save").click();
-  }, creditCards[0]);
+  }, {
+    record: creditCards[0],
+  });
   ok(true, "Edit credit card dialog is closed");
   creditCards = await getCreditCards();
 
   is(creditCards.length, 1, "only one credit card is in storage");
   is(creditCards[0]["cc-name"], TEST_CREDIT_CARD_1["cc-name"] + "test", "cc name changed");
   await removeCreditCards([creditCards[0].guid]);
 
   creditCards = await getCreditCards();
@@ -163,17 +165,19 @@ add_task(async function test_editCreditC
   await testDialog(EDIT_CREDIT_CARD_DIALOG_URL, (win) => {
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_RIGHT", {}, win);
     EventUtils.synthesizeKey("test", {}, win);
     win.document.querySelector("#save").click();
-  }, creditCards[0]);
+  }, {
+    record: creditCards[0],
+  });
   ok(true, "Edit credit card dialog is closed");
   creditCards = await getCreditCards();
 
   is(creditCards.length, 1, "only one credit card is in storage");
   is(creditCards[0]["cc-name"], TEST_CREDIT_CARD["cc-name"] + "test", "cc name changed");
   is(creditCards[0].billingAddressGUID, undefined,
      "unknown GUID removed upon manual save");
   await removeCreditCards([creditCards[0].guid]);
@@ -223,17 +227,19 @@ add_task(async function test_editCardWit
   await testDialog(EDIT_CREDIT_CARD_DIALOG_URL, (win) => {
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_TAB", {}, win);
     EventUtils.synthesizeKey("VK_RIGHT", {}, win);
     EventUtils.synthesizeKey("test", {}, win);
     win.document.querySelector("#save").click();
-  }, creditCards[0]);
+  }, {
+    record: creditCards[0],
+  });
   ok(true, "Edit credit card dialog is closed");
   creditCards = await getCreditCards();
 
   is(creditCards.length, 1, "only one credit card is in storage");
   is(creditCards[0]["cc-name"], TEST_CREDIT_CARD["cc-name"] + "test", "cc name changed");
   is(creditCards[0]["cc-type"], undefined,
      "unknown cc-type removed upon manual save");
   await removeCreditCards([creditCards[0].guid]);
--- a/browser/extensions/formautofill/test/browser/head.js
+++ b/browser/extensions/formautofill/test/browser/head.js
@@ -359,19 +359,19 @@ async function removeAllRecords() {
 async function waitForFocusAndFormReady(win) {
   return Promise.all([
     new Promise(resolve => waitForFocus(resolve, win)),
     BrowserTestUtils.waitForEvent(win, "FormReady"),
   ]);
 }
 
 async function testDialog(url, testFn, arg = undefined) {
-  if (url == EDIT_CREDIT_CARD_DIALOG_URL && arg) {
-    arg = Object.assign({}, arg, {
-      "cc-number": await MasterPassword.decrypt(arg["cc-number-encrypted"]),
+  if (url == EDIT_CREDIT_CARD_DIALOG_URL && arg && arg.record) {
+    arg.record = Object.assign({}, arg.record, {
+      "cc-number": await MasterPassword.decrypt(arg.record["cc-number-encrypted"]),
     });
   }
   let win = window.openDialog(url, null, "width=600,height=600", arg);
   await waitForFocusAndFormReady(win);
   let unloadPromise = BrowserTestUtils.waitForEvent(win, "unload");
   await testFn(win);
   return unloadPromise;
 }
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -145,21 +145,23 @@
 <ul>
   <li>The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.</li>
   <li>Please contact the website owners to inform them of this problem.</li>
 </ul>
 ">
 
 <!ENTITY certerror.longpagetitle1 "Your connection is not secure">
 <!ENTITY certerror.longpagetitle2 "Warning: Potential Security Risk Ahead">
+<!ENTITY certerror.sts.longpagetitle  "Did Not Connect: Potential Security Issue">
 <!-- Localization note (certerror.introPara, certerror.introPara2) - The text content of the span tag
 will be replaced at runtime with the name of the server to which the user
 was trying to connect. -->
 <!ENTITY certerror.introPara "The owner of <span class='hostname'/> has configured their website improperly.  To protect your information from being stolen, &brandShortName; has not connected to this website.">
 <!ENTITY certerror.introPara2 "&brandShortName; detected a potential security threat and did not continue to <span class='hostname'/>. If you visit this site, attackers could try to steal information like your passwords, emails, or credit card details.">
+<!ENTITY certerror.sts.introPara "&brandShortName; detected a potential security threat and did not continue to <span class='hostname'/> because this website requires a secure connection.">
 
 <!ENTITY certerror.expiredCert.secondPara "This issue is most likely because your computer clock is set to the wrong time, which would prevent &brandShortName; from connecting securely.">
 
 <!ENTITY certerror.whatCanYouDoAboutItTitle "What can you do about it?">
 
 <!ENTITY certerror.unknownIssuer.whatCanYouDoAboutIt "
 <p>The issue is most likely with the website, and there is nothing you can do to resolve it.</p>
 <p>If you are on a corporate network or using anti-virus software, you can reach out to the support teams for assistance. You can also notify the website’s administrator about the problem.</p>
@@ -209,16 +211,17 @@ was trying to connect. -->
 <!-- LOCALIZATION NOTE (certerror.wrongSystemTime2,
                         certerror.wrongSystemTimeWithoutReference) - The <span id='..' />
      tags will be injected with actual values, please leave them unchanged. -->
 <!ENTITY certerror.wrongSystemTime2 "<p> &brandShortName; did not connect to <span id='wrongSystemTime_URL'/> because your computer’s clock appears to show the wrong time and this is preventing a secure connection.</p> <p>Your computer is set to <span id='wrongSystemTime_systemDate'/>, when it should be <span id='wrongSystemTime_actualDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>">
 <!ENTITY certerror.wrongSystemTimeWithoutReference "<p>&brandShortName; did not connect to <span id='wrongSystemTimeWithoutReference_URL'/> because your computer’s clock appears to show the wrong time and this is preventing a secure connection.</p> <p>Your computer is set to <span id='wrongSystemTimeWithoutReference_systemDate'/>. To fix this problem, change your date and time settings to match the correct time.</p>">
 
 <!ENTITY certerror.pagetitle1  "Insecure Connection">
 <!ENTITY certerror.pagetitle2  "Warning: Potential Security Risk Ahead">
+<!ENTITY certerror.sts.pagetitle  "Did Not Connect: Potential Security Issue">
 <!ENTITY certerror.whatShouldIDo.badStsCertExplanation "This site uses HTTP
 Strict Transport Security (HSTS) to specify that &brandShortName; may only connect
 to it securely. As a result, it is not possible to add an exception for this
 certificate.">
 <!ENTITY certerror.whatShouldIDo.badStsCertExplanation1 "<span class='hostname'></span> has a security policy called HTTP Strict Transport Security (HSTS), which means that &brandShortName; can only connect to it securely. You can’t add an exception to visit this site.">
 <!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">
 
 <!ENTITY inadequateSecurityError.title "Your connection is not secure">
--- a/browser/themes/shared/aboutNetError-new.css
+++ b/browser/themes/shared/aboutNetError-new.css
@@ -4,21 +4,24 @@
 
 @import url("chrome://browser/skin/error-pages.css");
 
 :root {
   --exception-button-container-background: #F5F5F7;
 }
 
 body.certerror {
+  width: 100%;
+  justify-content: normal;
+}
+
+body.caution {
   border-style: solid;
   border-color: #ffe900;
   border-width: 16px;
-  width: 100%;
-  justify-content: normal;
 }
 
 body.captiveportal .title {
   background-image: url("wifi.svg");
 }
 
 body.certerror .title {
   background-image: url("cert-error-new.svg");
@@ -90,25 +93,25 @@ body:not(.captiveportal) #openPortalLogi
 body:not(.clockSkewError) #errorTryAgain {
   display: none;
 }
 
 body:not(.clockSkewError) #advancedPanelErrorTryAgain {
   display: none;
 }
 
-body:not(.clockSkewError) #moreInformationButton {
+body:not(:-moz-any(.clockSkewError,.badStsCert)) #moreInformationButton {
   display: none;
 }
 
 #openPortalLoginPageButton {
   margin-inline-start: 0;
 }
 
-body:not(.neterror):not(.clockSkewError) #advancedButton {
+body:not(:-moz-any(.clockSkewError,.badStsCert,.neterror)) #advancedButton {
   display: block;
 }
 
 #certificateErrorReporting {
   display: none;
   padding-bottom: 10px;
 }
 
--- a/devtools/client/framework/components/ToolboxToolbar.js
+++ b/devtools/client/framework/components/ToolboxToolbar.js
@@ -227,29 +227,32 @@ class ToolboxToolbar extends Component {
     }
 
     return div({id: `toolbox-buttons-${isStart ? "start" : "end"}`}, ...children);
   }
 
   renderFrameButton(command) {
     const {
       id,
+      isChecked,
       disabled,
       description
     } = command;
 
     const { toolbox } = this.props;
 
     return MenuButton(
       {
         id,
         disabled,
         menuId: id + "-panel",
         doc: toolbox.doc,
-        className: "command-button devtools-button ",
+        className: `devtools-button command-button ${
+          isChecked ? "command-button-checked " : ""
+        }`,
         ref: "frameMenuButton",
         title: description,
         onCloseButton: toolbox.highlighterUtils.unhighlight,
       },
       this.createFrameList
     );
   }
 
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -681,31 +681,16 @@ Toolbox.prototype = {
   get sourceMapService() {
     if (!Services.prefs.getBoolPref("devtools.source-map.client-service.enabled")) {
       return null;
     }
     return this._createSourceMapService();
   },
 
   /**
-   * A common access point for the client-side parser service that any panel can use.
-   */
-  get parserService() {
-    if (this._parserService) {
-      return this._parserService;
-    }
-
-    this._parserService =
-      this.browserRequire("devtools/client/debugger/new/src/workers/parser/index");
-    this._parserService
-      .start("resource://devtools/client/debugger/new/dist/parser-worker.js", this.win);
-    return this._parserService;
-  },
-
-  /**
    * Clients wishing to use source maps but that want the toolbox to
    * track the source and style sheet actor mapping can use this
    * source map service.  This is a higher-level service than the one
    * returned by |sourceMapService|, in that it automatically tracks
    * source and style sheet actor IDs.
    */
   get sourceMapURLService() {
     if (this._sourceMapURLService) {
@@ -1453,16 +1438,21 @@ Toolbox.prototype = {
       // the button and set an appropriate description.
       this.frameButton.disabled = true;
       this.frameButton.description = L10N.getStr("toolbox.frames.disabled.tooltip");
     } else {
       // Otherwise, enable the button and update the description.
       this.frameButton.disabled = false;
       this.frameButton.description = L10N.getStr("toolbox.frames.tooltip");
     }
+
+    // Highlight the button when a child frame is selected
+    const selectedFrame = this.frameMap.get(this.selectedFrameId) || {};
+    this.frameButton.isChecked = selectedFrame.parentID != null;
+
     this.frameButton.isVisible = this._commandIsVisible(this.frameButton);
   },
 
   /**
    * Ensure the visibility of each toolbox button matches the preference value.
    */
   _commandIsVisible: function(button) {
     const {
@@ -2406,28 +2396,16 @@ Toolbox.prototype = {
     // frame by default. Note that there might be more top level
     // frames in case of the BrowserToolbox.
     if (!this.selectedFrameId) {
       const frames = [...this.frameMap.values()];
       const topFrames = frames.filter(frame => !frame.parentID);
       this.selectedFrameId = topFrames.length ? topFrames[0].id : null;
     }
 
-    // Check out whether top frame is currently selected.
-    // Note that only child frame has parentID.
-    const frame = this.frameMap.get(this.selectedFrameId);
-    const topFrameSelected = frame ? !frame.parentID : false;
-    this._framesButtonChecked = false;
-
-    // If non-top level frame is selected the toolbar button is
-    // marked as 'checked' indicating that a child frame is active.
-    if (!topFrameSelected && this.selectedFrameId) {
-      this._framesButtonChecked = false;
-    }
-
     // We may need to hide/show the frames button now.
     const wasVisible = this.frameButton.isVisible;
     const wasDisabled = this.frameButton.disabled;
     this.updateFrameButton();
 
     const toolbarUpdate = () => {
       if (this.frameButton.isVisible === wasVisible &&
           this.frameButton.disabled === wasDisabled) {
@@ -2870,21 +2848,16 @@ Toolbox.prototype = {
       this._sourceMapURLService.destroy();
       this._sourceMapURLService = null;
     }
     if (this._sourceMapService) {
       this._sourceMapService.stopSourceMapWorker();
       this._sourceMapService = null;
     }
 
-    if (this._parserService) {
-      this._parserService.stop();
-      this._parserService = null;
-    }
-
     if (this.webconsolePanel) {
       this._saveSplitConsoleHeight();
       this.webconsolePanel.removeEventListener("resize",
         this._saveSplitConsoleHeight);
       this.webconsolePanel = null;
     }
     if (this.textBoxContextMenuPopup) {
       this.textBoxContextMenuPopup.removeEventListener("popupshowing",
--- a/devtools/client/themes/images/command-frames.svg
+++ b/devtools/client/themes/images/command-frames.svg
@@ -1,6 +1,8 @@
 <!-- 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/. -->
 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="context-fill #0b0b0b">
-  <path d="M14.2 2h-12.4c-.4 0-.8.4-.8.9v11.2c0 .4.3.9.8.9h12.4c.4 0 .8-.4.8-.9v-11.2c0-.4-.3-.9-.8-.9zM8 14H2v-4h6v4zm6 0H9v-4h5v4zm0-5H2V3h12v6z"/>
+  <style>#filled:target{fill-opacity:0.3}</style>
+  <path id="filled" fill-opacity="0" d="M6 7h8v6H6z"/>
+  <path d="M6 7v6H5V7H2V6h12v1H6zm7-6a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V4a3 3 0 0 1 3-3h10zM3 3a1 1 0 0 0-1 1v8c0 .6.4 1 1 1h10c.6 0 1-.4 1-1V4c0-.6-.4-1-1-1H3z"/>
 </svg>
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -17,16 +17,17 @@
   --command-paintflashing-image: url(images/command-paintflashing.svg);
   --command-screenshot-image: url(images/command-screenshot.svg);
   --command-responsive-image: url(images/command-responsivemode.svg);
   --command-replay-image: url(images/command-replay.svg);
   --command-scratchpad-image: url(images/tool-scratchpad.svg);
   --command-pick-image: url(images/command-pick.svg);
   --command-pick-accessibility-image: url(images/command-pick-accessibility.svg);
   --command-frames-image: url(images/command-frames.svg);
+  --command-frames-active-image: url(images/command-frames.svg#filled);
   --command-rulers-image: url(images/command-rulers.svg);
   --command-measure-image: url(images/command-measure.svg);
   --command-chevron-image: url(images/command-chevron.svg);
 }
 
 /* Toolbox tabbar */
 
 .devtools-tabbar {
@@ -334,44 +335,22 @@
 }
 
 #command-button-measure::before {
   background-image: var(--command-measure-image);
 }
 
 #command-button-frames::before {
   background-image: var(--command-frames-image);
-}
-
-#command-button-frames {
-  background-image: url("chrome://devtools/skin/images/dropmarker.svg");
-  background-repeat: no-repeat;
-
-  /* Override background-size from the command-button.
-   The drop down arrow is smaller */
-  background-size: 8px 4px !important;
-  min-width: 32px;
+  fill: var(--theme-toolbar-photon-icon-color);
 }
 
-#command-button-frames::before {
-  /* The frames button has a drop-down arrow making it asymmetrical.
-   * Drop the margin on the non-arrow side to make it fit more symmetrical. */
-  margin-inline-start: 0px;
-  /* The direction of devtools-button is forced to 'ltr' for text-as-image
-   * buttons. We don't need that here (there's no text in this button) and we
-   * want the logical properties to reflect the text direction so unset it. */
-  direction: unset;
-}
-
-#command-button-frames:-moz-locale-dir(ltr) {
-  background-position: right 2px top 14px;
-}
-
-#command-button-frames:-moz-locale-dir(rtl) {
-  background-position: left 2px top 14px;
+#command-button-frames.command-button-checked::before {
+  background-image: var(--command-frames-active-image);
+  fill: var(--theme-toolbar-checked-color);
 }
 
 /* Tooltip of frames menu  */
 
 #command-button-frames-panel > .tooltip-panel {
   max-width: 500px;
   overflow-y: auto;
 }
--- a/devtools/client/webconsole/test/components/console-api-call.test.js
+++ b/devtools/client/webconsole/test/components/console-api-call.test.js
@@ -322,17 +322,20 @@ describe("ConsoleAPICall component:", ()
         .toBe(filepath);
 
       // it should not be collapsible.
       expect(wrapper.find(`.theme-twisty`).length).toBe(0);
     });
     it("render with arguments", () => {
       const message = stubPreparedMessages.get(
         "console.trace('bar', {'foo': 'bar'}, [1,2,3])");
-      const wrapper = render(ConsoleApiCall({ message, serviceContainer, open: true }));
+      // We need to wrap the ConsoleApiElement in a Provider in order for the
+      // ObjectInspector to work.
+      const wrapper = render(Provider({ store: setupStore() },
+        ConsoleApiCall({ message, serviceContainer, open: true })));
 
       const filepath = "http://example.com/browser/devtools/client/webconsole/" +
                        "test/fixtures/stub-generators/test-console-api.html";
 
       expect(wrapper.find(".message-body").text())
         .toBe("console.trace() bar Object { foo: \"bar\" } Array(3) [ 1, 2, 3 ]");
 
       const frameLinks = wrapper.find(
--- a/devtools/client/webconsole/test/fixtures/serviceContainer.js
+++ b/devtools/client/webconsole/test/fixtures/serviceContainer.js
@@ -1,15 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 module.exports = {
   attachRefToHud: () => {},
+  canRewind: () => false,
   emitNewMessage: () => {},
   hudProxy: {
     client: {},
     releaseActor: actor => console.log("Release actor", actor),
   },
   onViewSourceInDebugger: () => {},
   onViewSourceInStyleEditor: () => {},
   onViewSourceInScratchpad: () => {},
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -168,16 +168,17 @@ support-files =
 skip-if = true # Bug 1437843
 [browser_console_consolejsm_output.js]
 [browser_console_context_menu_entries.js]
 skip-if = (os == "linux" && (debug || ccov)) # Bug 1440059
 [browser_console_dead_objects.js]
 [browser_console_devtools_loader_exception.js]
 [browser_console_error_source_click.js]
 [browser_console_filters.js]
+[browser_console_jsterm_await.js]
 [browser_console_nsiconsolemessage.js]
 [browser_console_open_or_focus.js]
 skip-if = (verify && debug && (os == 'mac' || os == 'linux'))
 [browser_console_restore.js]
 skip-if = verify
 [browser_console_webconsole_console_api_calls.js]
 [browser_console_webconsole_ctrlw_close_tab.js]
 [browser_console_webconsole_iframe_messages.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_console_jsterm_await.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This is a lightweight version of browser_jsterm_await.js to only ensure top-level await
+// support in the Browser Console.
+
+"use strict";
+
+const TEST_URI = "data:text/html;charset=utf-8,Top-level await Browser Console test";
+
+add_task(async function() {
+  // Enable await mapping.
+  await pushPref("devtools.debugger.features.map-await-expression", true);
+
+  // Run test with legacy JsTerm
+  await pushPref("devtools.webconsole.jsterm.codeMirror", false);
+  await performTests();
+  // And then run it with the CodeMirror-powered one.
+  await pushPref("devtools.webconsole.jsterm.codeMirror", true);
+  await performTests();
+});
+
+async function performTests() {
+  await addTab(TEST_URI);
+  const hud = await HUDService.toggleBrowserConsole();
+
+  const executeAndWaitForResultMessage = (input, expectedOutput) =>
+    executeAndWaitForMessage(hud, input, expectedOutput, ".result");
+
+  info("Evaluate a top-level await expression");
+  const simpleAwait = `await new Promise(r => setTimeout(() => r(["await1"]), 500))`;
+  await executeAndWaitForResultMessage(
+    simpleAwait,
+    `Array [ "await1" ]`,
+  );
+
+  // Check that the resulting promise of the async iife is not displayed.
+  const messages = hud.ui.outputNode.querySelectorAll(".message .message-body");
+  const messagesText = Array.from(messages).map(n => n.textContent).join(" - ");
+  is(messagesText.includes("Promise {"), false, "The output does not contain a Promise");
+  ok(messagesText.includes(simpleAwait) && messagesText.includes(`Array [ "await1" ]`),
+    "The output contains the the expected messages");
+
+  info("Close the Browser console");
+  await HUDService.toggleBrowserConsole();
+}
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -238,33 +238,50 @@ WebConsole.prototype = {
    *            - {String} expression: The mapped expression
    *            - {Object} mapped: An object containing the different mapping that could
    *                               be done and if they were applied on the input.
    *                               At the moment, contains `await`, `bindings` and
    *                               `originalExpression`.
    */
   getMappedExpression(expression) {
     const toolbox = gDevTools.getToolbox(this.target);
-    if (!toolbox) {
-      return null;
-    }
 
-    const panel = toolbox.getPanel("jsdebugger");
+    // We need to check if the debugger is open, since it may perform a variable name
+    // substitution for sourcemapped script (i.e. evaluated `myVar.trim()` might need to
+    // be transformed into `a.trim()`).
+    const panel = toolbox && toolbox.getPanel("jsdebugger");
     if (panel) {
       return panel.getMappedExpression(expression);
     }
 
-    if (toolbox.parserService && expression.includes("await ")) {
-      return toolbox.parserService.mapExpression(expression);
+    if (this.parserService && expression.includes("await ")) {
+      return this.parserService.mapExpression(expression);
     }
 
     return null;
   },
 
   /**
+   * A common access point for the client-side parser service that any panel can use.
+   */
+  get parserService() {
+    if (this._parserService) {
+      return this._parserService;
+    }
+
+    this._parserService =
+      require("devtools/client/debugger/new/src/workers/parser/index");
+
+    this._parserService.start(
+      "resource://devtools/client/debugger/new/dist/parser-worker.js",
+      this.browserWindow);
+    return this._parserService;
+  },
+
+  /**
    * Retrieves the current selection from the Inspector, if such a selection
    * exists. This is used to pass the ID of the selected actor to the Web
    * Console server for the $0 helper.
    *
    * @return object|null
    *         A Selection referring to the currently selected node in the
    *         Inspector.
    *         If the inspector was never opened, or no node was ever selected,
@@ -304,16 +321,21 @@ WebConsole.prototype = {
       if (!this._browserConsole) {
         try {
           await this.target.activeTab.focus();
         } catch (ex) {
           // Tab focus can fail if the tab or target is closed.
         }
       }
 
+      if (this._parserService) {
+        this._parserService.stop();
+        this._parserService = null;
+      }
+
       const id = Utils.supportsString(this.hudId);
       Services.obs.notifyObservers(id, "web-console-destroyed");
     })();
 
     return this._destroyer;
   },
 };
 
--- a/devtools/server/tests/mochitest/chrome.ini
+++ b/devtools/server/tests/mochitest/chrome.ini
@@ -2,16 +2,17 @@
 tags = devtools
 skip-if = os == 'android'
 support-files =
   animation-data.html
   doc_Debugger.Source.prototype.introductionType.xul
   Debugger.Source.prototype.element.js
   Debugger.Source.prototype.element-2.js
   Debugger.Source.prototype.element.html
+  framerate-helpers.js
   hello-actor.js
   iframe1_makeGlobalObjectReference.html
   iframe2_makeGlobalObjectReference.html
   inspector_css-properties.html
   inspector_display-type.html
   inspector_getImageData.html
   inspector_getOffsetParent.html
   inspector-delay-image-response.sjs
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/mochitest/framerate-helpers.js
@@ -0,0 +1,63 @@
+/* exported getTargetForSelectedTab, waitFor, plotFPS */
+"use strict";
+const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
+const {TargetFactory} = require("devtools/client/framework/target");
+const Services = require("Services");
+
+// Always log packets when running tests.
+Services.prefs.setBoolPref("devtools.debugger.log", true);
+SimpleTest.registerCleanupFunction(function() {
+  Services.prefs.clearUserPref("devtools.debugger.log");
+});
+
+SimpleTest.waitForExplicitFinish();
+
+/**
+ * Add a new test tab in the browser and load the given url.
+ * @return Promise a promise that resolves to the new target representing
+ *         the page currently opened.
+ */
+function getTargetForSelectedTab() {
+  // Get the target and get the necessary front
+  const {gBrowser} = Services.wm.getMostRecentWindow("navigator:browser");
+  return TargetFactory.forTab(gBrowser.selectedTab);
+}
+
+function waitFor(time) {
+  return new Promise(resolve => setTimeout(resolve, time));
+}
+
+function plotFPS(ticks, interval = 100, clamp = 60) {
+  const timeline = [];
+  const totalTicks = ticks.length;
+
+  // If the refresh driver didn't get a chance to tick before the
+  // recording was stopped, assume framerate was 0.
+  if (totalTicks == 0) {
+    timeline.push({ delta: 0, value: 0 });
+    timeline.push({ delta: interval, value: 0 });
+    return timeline;
+  }
+
+  let frameCount = 0;
+  let prevTime = ticks[0];
+
+  for (let i = 1; i < totalTicks; i++) {
+    const currTime = ticks[i];
+    frameCount++;
+
+    const elapsedTime = currTime - prevTime;
+    if (elapsedTime < interval) {
+      continue;
+    }
+
+    const framerate = Math.min(1000 / (elapsedTime / frameCount), clamp);
+    timeline.push({ delta: prevTime, value: framerate });
+    timeline.push({ delta: currTime, value: framerate });
+
+    frameCount = 0;
+    prevTime = currTime;
+  }
+
+  return timeline;
+}
--- a/devtools/server/tests/mochitest/inspector-helpers.js
+++ b/devtools/server/tests/mochitest/inspector-helpers.js
@@ -1,17 +1,18 @@
 /* exported attachURL, promiseDone, assertOwnershipTrees, checkMissing, checkAvailable,
    promiseOnce, isSrcChange, isUnretained, isNewRoot, assertSrcChange, assertUnload,
    assertFrameLoad, assertChildList, waitForMutation, addTest, addAsyncTest,
    runNextTest */
 "use strict";
 
 const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-const {DebuggerClient} = require("devtools/shared/client/debugger-client");
+const {TargetFactory} = require("devtools/client/framework/target");
 const {DebuggerServer} = require("devtools/server/main");
+const {BrowserTestUtils} = require("resource://testing-common/BrowserTestUtils.jsm");
 
 const Services = require("Services");
 const {DocumentWalker: _documentWalker} = require("devtools/server/actors/inspector/document-walker");
 
 // Always log packets when running tests.
 Services.prefs.setBoolPref("devtools.debugger.log", true);
 SimpleTest.registerCleanupFunction(function() {
   Services.prefs.clearUserPref("devtools.debugger.log");
@@ -29,64 +30,61 @@ var gAttachCleanups = [];
 
 SimpleTest.registerCleanupFunction(function() {
   for (const cleanup of gAttachCleanups) {
     cleanup();
   }
 });
 
 /**
+ * Add a new test tab in the browser and load the given url.
+ * @return Promise a promise that resolves to the new target representing
+ *         the page currently opened.
+ */
+
+async function getTargetForSelectedTab(gBrowser) {
+  const selectedTab = gBrowser.selectedTab;
+  await BrowserTestUtils.browserLoaded(selectedTab.linkedBrowser);
+  return TargetFactory.forTab(selectedTab);
+}
+
+/**
  * Open a tab, load the url, wait for it to signal its readiness,
  * find the tab with the debugger server, and call the callback.
  *
  * Returns a function which can be called to close the opened ta
  * and disconnect its debugger client.
  */
-function attachURL(url, callback) {
-  let win = window.open(url, "_blank");
-  let client = null;
+async function attachURL(url) {
+  // Get the current browser window
+  const gBrowser = Services.wm.getMostRecentWindow("navigator:browser").gBrowser;
 
-  const cleanup = () => {
-    if (client) {
-      client.close();
-      client = null;
+  // open the url in a new tab, save a reference to the new inner window global object
+  // and wait for it to load. The tests rely on this window object to send a "ready"
+  // event to its opener (the test page). This window reference is used within
+  // the test tab, to reference the webpage being tested against, which is in another
+  // tab.
+  const windowOpened = BrowserTestUtils.waitForNewTab(gBrowser, url);
+  const win = window.open(url, "_blank");
+  await windowOpened;
+
+  const target = await getTargetForSelectedTab(gBrowser);
+  await target.attach();
+
+  const cleanup = async function() {
+    if (target.client) {
+      await target.client.close();
     }
     if (win) {
       win.close();
-      win = null;
     }
   };
+
   gAttachCleanups.push(cleanup);
-
-  window.addEventListener("message", function loadListener(event) {
-    if (event.data === "ready") {
-      client = new DebuggerClient(DebuggerServer.connectPipe());
-      client.connect().then(([applicationType, traits]) => {
-        client.listTabs().then(response => {
-          for (const tab of response.tabs) {
-            if (tab.url === url) {
-              window.removeEventListener("message", loadListener);
-              // eslint-disable-next-line max-nested-callbacks
-              client.attachTarget(tab.actor).then(function() {
-                try {
-                  callback(null, client, tab, win.document);
-                } catch (ex) {
-                  Cu.reportError(ex);
-                  dump(ex);
-                }
-              });
-              break;
-            }
-          }
-        });
-      });
-    }
-  });
-
-  return cleanup;
+  return { target, doc: win.document };
 }
 
 function promiseOnce(target, event) {
   return new Promise(resolve => {
     target.on(event, (...args) => {
       if (args.length === 1) {
         resolve(args[0]);
       } else {
@@ -163,34 +161,34 @@ function assertOwnershipTrees(walker) {
   const clientTree = clientOwnershipTree(walker);
   is(JSON.stringify(clientTree, null, " "), JSON.stringify(serverTree, null, " "),
      "Server and client ownership trees should match.");
 
   return ownershipTreeSize(clientTree.root);
 }
 
 // Verify that an actorID is inaccessible both from the client library and the server.
-function checkMissing(client, actorID) {
+function checkMissing({client}, actorID) {
   return new Promise(resolve => {
     const front = client.getActor(actorID);
     ok(!front, "Front shouldn't be accessible from the client for actorID: " + actorID);
 
     client.request({
       to: actorID,
       type: "request",
     }, response => {
       is(response.error, "noSuchActor",
         "node list actor should no longer be contactable.");
       resolve(undefined);
     });
   });
 }
 
 // Verify that an actorID is accessible both from the client library and the server.
-function checkAvailable(client, actorID) {
+function checkAvailable({client}, actorID) {
   return new Promise(resolve => {
     const front = client.getActor(actorID);
     ok(front, "Front should be accessible from the client for actorID: " + actorID);
 
     client.request({
       to: actorID,
       type: "garbageAvailableTest",
     }, response => {
--- a/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
+++ b/devtools/server/tests/mochitest/test_animation_actor-lifetime.html
@@ -9,38 +9,32 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {AnimationsFront} = require("devtools/shared/fronts/animation");
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
   let animationsFront = null;
 
-  addTest(function setup() {
+  addTest(async function setup() {
     info("Setting up inspector and animation actors.");
 
     const url = document.getElementById("animationContent").href;
-    attachURL(url, function(err, client, tab, doc) {
-      const inspector = InspectorFront(client, tab);
 
-      animationsFront = new AnimationsFront(client, tab);
-
-      promiseDone(inspector.getWalker().then(walker => {
-        ok(walker, "getWalker() should return an actor.");
-        gWalker = walker;
-      }).then(runNextTest));
-    });
+    const { target } = await attachURL(url);
+    const inspector = target.getInspector();
+    animationsFront = target.getFront("animations");
+    gWalker = await inspector.getWalker();
+    ok(gWalker, "getWalker() should return an actor.");
+    runNextTest();
   });
 
   addAsyncTest(async function testActorLifetime() {
     info("Testing animated node actor");
     const animatedNodeActor = await gWalker.querySelector(gWalker.rootNode,
       ".animated");
     await animationsFront.getAnimationPlayersForNode(animatedNodeActor);
 
--- a/devtools/server/tests/mochitest/test_css-properties.html
+++ b/devtools/server/tests/mochitest/test_css-properties.html
@@ -10,71 +10,48 @@ Bug 1265798 - Replace inIDOMUtils.cssPro
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
   const { initCssProperties, getCssProperties } =
     require("devtools/shared/fronts/css-properties");
-  const { getFront } =
-    require("devtools/shared/protocol");
-
-  function promiseAttachUrl(url) {
-    return new Promise((resolve, reject) => {
-      attachURL(url, function(err, client, tab, doc) {
-        if (err) {
-          return reject(err);
-        }
-        return resolve({client, tab, doc});
-      });
-    });
-  }
 
   function toSortedString(array) {
     return JSON.stringify(array.sort());
   }
 
+  // Return some mocked values for a tab. Override hasActor with the
+  // options passed into the test. A second property is used
+  // during these tests: `win` for css-properties.js's getClientBrowserVersion.
+  async function getTabProperties(url, useActor) {
+    const { target, win } = await attachURL(url);
+    target.hasActor = () => useActor;
+    return { target, win };
+  }
+
   const runCssPropertiesTests = async function(url, useActor) {
     info(`Opening two tabs ${useActor ? "with" : "without"} CssPropertiesActor support.`);
 
-    const attachmentA = await promiseAttachUrl(url);
-    const attachmentB = await promiseAttachUrl(url);
+    // Open a new tab. The only property we are interested in is `target`.
+    const tabA = await getTabProperties(url, useActor);
+    const tabB = await getTabProperties(url, useActor);
 
-    const toolboxMockA = {
-      target: {
-        hasActor: () => useActor,
-        client: attachmentA.client,
-        form: attachmentA.tab,
-        getFront: typeName => getFront(attachmentA.client, typeName, attachmentA.tab)
-      },
-      // Fake the window for css-properties.js's getClientBrowserVersion to work
-      win: window
-    };
-    const toolboxMockB = {
-      target: {
-        hasActor: () => useActor,
-        client: attachmentB.client,
-        form: attachmentB.tab,
-        getFront: typeName => getFront(attachmentB.client, typeName, attachmentB.tab)
-      },
-      win: window
-    };
+    await initCssProperties(tabA);
+    await initCssProperties(tabB);
 
-    await initCssProperties(toolboxMockA);
-    await initCssProperties(toolboxMockB);
-
-    const cssProperties = getCssProperties(toolboxMockA);
-    const cssPropertiesA = getCssProperties(toolboxMockA);
-    const cssPropertiesB = getCssProperties(toolboxMockB);
+    const cssProperties = getCssProperties(tabA);
+    const cssPropertiesA = getCssProperties(tabA);
+    const cssPropertiesB = getCssProperties(tabB);
 
     is(cssProperties, cssPropertiesA,
-       "Multiple calls with the same toolbox returns the same object.");
+       "Multiple calls with the same target returns the same object.");
     isnot(cssProperties, cssPropertiesB,
-       "Multiple calls with the different toolboxes return different " +
+       "Multiple calls with the different target return different " +
        " objects.");
 
     ok(cssProperties.isKnown("border"),
       "The `border` shorthand property is known.");
     ok(cssProperties.isKnown("display"),
       "The `display` property is known.");
     ok(!cssProperties.isKnown("foobar"),
       "A fake property is not known.");
--- a/devtools/server/tests/mochitest/test_framerate_01.html
+++ b/devtools/server/tests/mochitest/test_framerate_01.html
@@ -2,133 +2,69 @@
 <html>
 <!--
 Bug 1007200 - Create a framerate actor
 -->
 <head>
   <meta charset="utf-8">
   <title>Framerate actor test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="framerate-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
-  const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const Services = require("Services");
-  const { DebuggerClient } = require("devtools/shared/client/debugger-client");
-  const { DebuggerServer } = require("devtools/server/main");
+window.onload = async function() {
+  const target = await getTargetForSelectedTab();
+  const front = target.getFront("framerate");
+  const TICK = 1000;
 
-  // Always log packets when running tests.
-  Services.prefs.setBoolPref("devtools.debugger.log", true);
-  SimpleTest.registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("devtools.debugger.log");
-  });
+  await waitFor(TICK);
+  await front.startRecording();
+  await waitFor(TICK);
+  const rawData = await front.stopRecording();
+  await onRecordingStopped(front, rawData);
+  await target.destroy();
+  SimpleTest.finish();
+};
 
-  SimpleTest.waitForExplicitFinish();
-
-  const { FramerateFront } = require("devtools/shared/fronts/framerate");
-
-  function plotFPS(ticks, interval = 100, clamp = 60) {
-    const timeline = [];
-    const totalTicks = ticks.length;
+// Local Helpers
+async function onRecordingStopped(front, rawData) {
+  ok(rawData, "There should be a recording available.");
 
-    // If the refresh driver didn't get a chance to tick before the
-    // recording was stopped, assume framerate was 0.
-    if (totalTicks == 0) {
-      timeline.push({ delta: 0, value: 0 });
-      timeline.push({ delta: interval, value: 0 });
-      return timeline;
-    }
+  const timeline = plotFPS(rawData);
+  ok(timeline.length >= 2,
+    "There should be at least one measurement available, with two entries.");
 
-    let frameCount = 0;
-    let prevTime = ticks[0];
-
-    for (let i = 1; i < totalTicks; i++) {
-      const currTime = ticks[i];
-      frameCount++;
+  let prevTimeStart = timeline[0].delta;
 
-      const elapsedTime = currTime - prevTime;
-      if (elapsedTime < interval) {
-        continue;
-      }
+  for (let i = 0; i < timeline.length; i += 2) {
+    const currTimeStart = timeline[i].delta;
+    const currTimeEnd = timeline[i + 1].delta;
+    info("Testing delta: " + currTimeStart + " vs. " + currTimeEnd);
 
-      const framerate = Math.min(1000 / (elapsedTime / frameCount), clamp);
-      timeline.push({ delta: prevTime, value: framerate });
-      timeline.push({ delta: currTime, value: framerate });
+    ok(currTimeStart < currTimeEnd,
+      "The start and end time deltas should be consecutive.");
+    is(currTimeStart, prevTimeStart,
+      "There should be two time deltas for each framerate value.");
 
-      frameCount = 0;
-      prevTime = currTime;
-    }
-
-    return timeline;
+    prevTimeStart = currTimeEnd;
   }
 
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  client.connect().then(function onConnect() {
-    client.listTabs().then(function onListTabs(response) {
-      const form = response.tabs[response.selected];
-      const front = FramerateFront(client, form);
-
-      window.setTimeout(() => {
-        /* eslint-disable max-nested-callbacks */
-        front.startRecording().then(() => {
-          window.setTimeout(() => {
-            front.stopRecording().then(rawData => {
-              onRecordingStopped(front, rawData);
-            });
-          }, 1000);
-        });
-        /* eslint-enable max-nested-callbacks */
-      }, 1000);
-    });
-  });
-
-  function onRecordingStopped(front, rawData) {
-    ok(rawData, "There should be a recording available.");
-
-    const timeline = plotFPS(rawData);
-    ok(timeline.length >= 2,
-      "There should be at least one measurement available, with two entries.");
-
-    let prevTimeStart = timeline[0].delta;
+  for (let i = 0; i < timeline.length; i += 2) {
+    const currFramerateStart = timeline[i].value;
+    const currFramerateEnd = timeline[i + 1].value;
+    info("Testing framerate: " + currFramerateStart);
 
-    for (let i = 0; i < timeline.length; i += 2) {
-      const currTimeStart = timeline[i].delta;
-      const currTimeEnd = timeline[i + 1].delta;
-      info("Testing delta: " + currTimeStart + " vs. " + currTimeEnd);
-
-      ok(currTimeStart < currTimeEnd,
-        "The start and end time deltas should be consecutive.");
-      is(currTimeStart, prevTimeStart,
-        "There should be two time deltas for each framerate value.");
-
-      prevTimeStart = currTimeEnd;
-    }
+    is(currFramerateStart, currFramerateEnd,
+      "The start and end framerate values should be equal.");
 
-    for (let i = 0; i < timeline.length; i += 2) {
-      const currFramerateStart = timeline[i].value;
-      const currFramerateEnd = timeline[i + 1].value;
-      info("Testing framerate: " + currFramerateStart);
-
-      is(currFramerateStart, currFramerateEnd,
-        "The start and end framerate values should be equal.");
-
-      is(typeof currFramerateStart, "number", "All values should be numbers.");
-      ok(currFramerateStart <= 60, "All values were correctly clamped.");
-    }
-
-    client.close().then(() => {
-      DebuggerServer.destroy();
-      SimpleTest.finish();
-    });
+    is(typeof currFramerateStart, "number", "All values should be numbers.");
+    ok(currFramerateStart <= 60, "All values were correctly clamped.");
   }
-};
+}
 </script>
 </pre>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_framerate_02.html
+++ b/devtools/server/tests/mochitest/test_framerate_02.html
@@ -2,108 +2,47 @@
 <html>
 <!--
 Bug 1007200 - Create a framerate actor
 -->
 <head>
   <meta charset="utf-8">
   <title>Framerate actor test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="framerate-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {DebuggerClient} = require("devtools/shared/client/debugger-client");
-  const {DebuggerServer} = require("devtools/server/main");
-  const Services = require("Services");
-
-  // Always log packets when running tests.
-  Services.prefs.setBoolPref("devtools.debugger.log", true);
-  SimpleTest.registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("devtools.debugger.log");
-  });
-
-  SimpleTest.waitForExplicitFinish();
-
-  const {FramerateFront} = require("devtools/shared/fronts/framerate");
-
-  function plotFPS(ticks, interval = 100, clamp = 60) {
-    const timeline = [];
-    const totalTicks = ticks.length;
+window.onload = async function() {
+  const target = await getTargetForSelectedTab();
+  const front = target.getFront("framerate");
 
-    // If the refresh driver didn't get a chance to tick before the
-    // recording was stopped, assume framerate was 0.
-    if (totalTicks == 0) {
-      timeline.push({ delta: 0, value: 0 });
-      timeline.push({ delta: interval, value: 0 });
-      return timeline;
-    }
-
-    let frameCount = 0;
-    let prevTime = ticks[0];
+  const rawData = await front.stopRecording();
+  ok(rawData, "There should be a recording available.");
+  is(rawData.length, 0, "...but it should be empty.");
 
-    for (let i = 1; i < totalTicks; i++) {
-      const currTime = ticks[i];
-      frameCount++;
-
-      const elapsedTime = currTime - prevTime;
-      if (elapsedTime < interval) {
-        continue;
-      }
-
-      const framerate = Math.min(1000 / (elapsedTime / frameCount), clamp);
-      timeline.push({ delta: prevTime, value: framerate });
-      timeline.push({ delta: currTime, value: framerate });
+  const timeline = plotFPS(rawData);
+  is(timeline.length, 2,
+    "There should be one measurement plotted, with two entries.");
 
-      frameCount = 0;
-      prevTime = currTime;
-    }
-
-    return timeline;
-  }
-
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
+  info("The framerate should be assumed to be 0 if the recording is empty.");
 
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  client.connect().then(function onConnect() {
-    client.listTabs().then(function onListTabs(response) {
-      const form = response.tabs[response.selected];
-      const front = FramerateFront(client, form);
-
-      front.stopRecording().then(rawData => {
-        ok(rawData, "There should be a recording available.");
-        is(rawData.length, 0, "...but it should be empty.");
+  is(timeline[0].delta, 0,
+    "The first time delta should be 0.");
+  is(timeline[0].value, 0,
+    "The first framerate value should be 0.");
 
-        const timeline = plotFPS(rawData);
-        is(timeline.length, 2,
-          "There should be one measurement plotted, with two entries.");
-
-        info("The framerate should be assumed to be 0 if the recording is empty.");
-
-        is(timeline[0].delta, 0,
-          "The first time delta should be 0.");
-        is(timeline[0].value, 0,
-          "The first framerate value should be 0.");
+  is(timeline[1].delta, 100,
+    "The last time delta should be 100 (the default interval value).");
+  is(timeline[1].value, 0,
+    "The last framerate value should be 0.");
 
-        is(timeline[1].delta, 100,
-          "The last time delta should be 100 (the default interval value).");
-        is(timeline[1].value, 0,
-          "The last framerate value should be 0.");
-
-        // eslint-disable-next-line max-nested-callbacks
-        client.close().then(() => {
-          DebuggerServer.destroy();
-          SimpleTest.finish();
-        });
-      });
-    });
-  });
+  await target.destroy();
+  SimpleTest.finish();
 };
 </script>
 </pre>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_framerate_03.html
+++ b/devtools/server/tests/mochitest/test_framerate_03.html
@@ -2,78 +2,50 @@
 <html>
 <!--
 Bug 1023018 - Tests whether or not the framerate actor can handle time ranges.
 -->
 <head>
   <meta charset="utf-8">
   <title>Framerate actor test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="framerate-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {DebuggerClient} = require("devtools/shared/client/debugger-client");
-  const {DebuggerServer} = require("devtools/server/main");
-  const Services = require("Services");
-
-  // Always log packets when running tests.
-  Services.prefs.setBoolPref("devtools.debugger.log", true);
-  SimpleTest.registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("devtools.debugger.log");
-  });
-
-  SimpleTest.waitForExplicitFinish();
+const START_TICK = 2000;
+const STOP_TICK = 3000;
+const TOTAL_TIME = 5000;
 
-  const {FramerateFront} = require("devtools/shared/fronts/framerate");
-  const START_TICK = 2000;
-  const STOP_TICK = 3000;
-  const TOTAL_TIME = 5000;
-
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  client.connect().then(function onConnect() {
-    client.listTabs().then(function onListTabs(response) {
-      const form = response.tabs[response.selected];
-      const front = FramerateFront(client, form);
+window.onload = async function() {
+  const target = await getTargetForSelectedTab();
+  const front = target.getFront("framerate");
 
-      front.startRecording().then(() => {
-        /* eslint-disable max-nested-callbacks */
-        window.setTimeout(() => {
-          front.stopRecording(START_TICK, STOP_TICK).then(rawData => {
-            onRecordingStopped(front, rawData);
-          });
-        }, TOTAL_TIME);
-        /* eslint-enable max-nested-callbacks */
-      });
-    });
-  });
-
-  function onRecordingStopped(front, rawData) {
-    ok(rawData, "There should be a recording available.");
+  await front.startRecording();
+  await waitFor(TOTAL_TIME);
+  const rawData = await front.stopRecording(START_TICK, STOP_TICK);
+  await onRecordingStopped(front, rawData);
+  await target.destroy();
+  SimpleTest.finish();
+};
 
-    ok(!rawData.find(e => e < START_TICK),
-      "There should be no tick before 2000ms.");
-    ok(!rawData.find(e => e > STOP_TICK),
-      "There should be no tick after 3000ms.");
+// Local Helper Functions
+async function onRecordingStopped(front, rawData) {
+  ok(rawData, "There should be a recording available.");
 
-    for (const tick of rawData) {
-      info("Testing tick: " + tick);
-      is(typeof tick, "number", "All values should be numbers.");
-    }
+  ok(!rawData.find(e => e < START_TICK),
+    "There should be no tick before 2000ms.");
+  ok(!rawData.find(e => e > STOP_TICK),
+    "There should be no tick after 3000ms.");
 
-    client.close().then(() => {
-      DebuggerServer.destroy();
-      SimpleTest.finish();
-    });
+  for (const tick of rawData) {
+    info("Testing tick: " + tick);
+    is(typeof tick, "number", "All values should be numbers.");
   }
-};
+}
 </script>
 </pre>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_framerate_04.html
+++ b/devtools/server/tests/mochitest/test_framerate_04.html
@@ -10,67 +10,57 @@ Bug 1023018 - Tests if the framerate act
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
+window.onload = async function() {
+  // inspector-helpers doesnt wait for explicit finish
   SimpleTest.waitForExplicitFinish();
-  const {FramerateFront} = require("devtools/shared/fronts/framerate");
-  const {TargetFactory} = require("devtools/client/framework/target");
-
-  const url = document.getElementById("testContent").href;
-  attachURL(url, onTab);
 
-  async function onTab(_, client, form, contentDoc) {
-    const contentWin = contentDoc.defaultView;
-    const chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
-    const selectedTab = chromeWin.gBrowser.selectedTab;
+  const TICK = 1000;
+  const url = document.getElementById("testContent").href;
+  const { target, doc } = await attachURL(url);
+  const contentWin = doc.defaultView;
+  const front = target.getFront("framerate");
 
-    const target = await TargetFactory.forTab(selectedTab);
-    await target.attach();
-    const front = FramerateFront(client, form);
+  await front.startRecording();
+  await waitFor(TICK);
+  const firstBatch = await front.getPendingTicks();
+  await waitFor(TICK);
+
+  const onWillNavigate = target.once("will-navigate");
+  contentWin.location.reload();
+  await onWillNavigate;
 
-    front.startRecording().then(() => {
-      window.setTimeout(() => {
-        front.getPendingTicks().then(firstBatch => {
-          /* eslint-disable max-nested-callbacks */
-          target.once("will-navigate", () => {
-            window.setTimeout(() => {
-              front.stopRecording().then(secondBatch => {
-                onRecordingStopped(client, firstBatch, secondBatch);
-              });
-            }, 1000);
-          });
-          /* eslint-enable max-nested-callbacks */
-          contentWin.location.reload();
-        });
-      }, 1000);
-    });
-  }
+  await waitFor(TICK);
+  const secondBatch = await front.stopRecording();
+  await onRecordingStopped(firstBatch, secondBatch);
+  target.destroy();
+  SimpleTest.finish();
+};
+
+// Local Helpers
+function waitFor(time) {
+  return new Promise(resolve => setTimeout(resolve, time));
+}
 
-  function onRecordingStopped(client, firstBatch, secondBatch) {
-    ok(firstBatch, "There should be a first batch recording available.");
-    ok(secondBatch, "There should be a second batch recording available.");
-
-    const diff = secondBatch.length - firstBatch.length;
-    info("Difference in ticks: " + diff);
-    ok(diff > 0, "More ticks should be recorded in the second batch.");
+function onRecordingStopped(firstBatch, secondBatch) {
+  ok(firstBatch, "There should be a first batch recording available.");
+  ok(secondBatch, "There should be a second batch recording available.");
 
-    ok(firstBatch.every((e) => secondBatch.includes(e)),
-      "All the ticks in the first batch should be in the second batch as well.");
-    ok(secondBatch.every((e, i, array) => i < array.length - 1 ? e < array[i + 1] : true),
-      "All the ticks in the final batch should be ascending in value.");
+  const diff = secondBatch.length - firstBatch.length;
+  info("Difference in ticks: " + diff);
+  ok(diff > 0, "More ticks should be recorded in the second batch.");
 
-    client.close().then(() => {
-      DebuggerServer.destroy();
-      SimpleTest.finish();
-    });
-  }
-};
+  ok(firstBatch.every((e) => secondBatch.includes(e)),
+    "All the ticks in the first batch should be in the second batch as well.");
+  ok(secondBatch.every((e, i, array) => i < array.length - 1 ? e < array[i + 1] : true),
+    "All the ticks in the final batch should be ascending in value.");
+}
 </script>
 </pre>
 <a id="testContent" target="_blank" href="inspector_getImageData.html">Test Document</a>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_framerate_05.html
+++ b/devtools/server/tests/mochitest/test_framerate_05.html
@@ -2,75 +2,46 @@
 <html>
 <!--
 Bug 1034648 - Tests whether a framerate recording can be cancelled.
 -->
 <head>
   <meta charset="utf-8">
   <title>Framerate actor test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="framerate-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {DebuggerClient} = require("devtools/shared/client/debugger-client");
-  const {DebuggerServer} = require("devtools/server/main");
-  const Services = require("Services");
-
-  // Always log packets when running tests.
-  Services.prefs.setBoolPref("devtools.debugger.log", true);
-  SimpleTest.registerCleanupFunction(function() {
-    Services.prefs.clearUserPref("devtools.debugger.log");
-  });
+window.onload = async function() {
+  const target = await getTargetForSelectedTab();
+  const front = target.getFront("framerate");
+  const TICK = 1000;
 
-  SimpleTest.waitForExplicitFinish();
-
-  const {FramerateFront} = require("devtools/shared/fronts/framerate");
+  await front.startRecording();
+  await waitFor(TICK);
 
-  DebuggerServer.init();
-  DebuggerServer.registerAllActors();
-
-  const client = new DebuggerClient(DebuggerServer.connectPipe());
-  client.connect().then(function onConnect() {
-    client.listTabs().then(function onListTabs(response) {
-      const form = response.tabs[response.selected];
-      const front = FramerateFront(client, form);
+  await front.cancelRecording();
+  await waitFor(TICK);
 
-      front.startRecording().then(() => {
-        /* eslint-disable max-nested-callbacks */
-        window.setTimeout(() => {
-          front.cancelRecording().then(() => {
-            window.setTimeout(() => {
-              front.getPendingTicks().then(rawTicks => {
-                ok(rawTicks,
-                  "The returned pending ticks should be empty (1).");
-                is(rawTicks.length, 0,
-                  "The returned pending ticks should be empty (2).");
+  const rawTicks = await front.getPendingTicks();
+  ok(rawTicks,
+    "The returned pending ticks should be empty (1).");
+  is(rawTicks.length, 0,
+    "The returned pending ticks should be empty (2).");
 
-                front.stopRecording().then(rawData => {
-                  ok(rawData,
-                    "The returned raw data should be an empty array (1).");
-                  is(rawData.length, 0,
-                    "The returned raw data should be an empty array (2).");
+  const newRawData = await front.stopRecording();
+  ok(newRawData,
+    "The returned raw data should be an empty array (1).");
+  is(newRawData.length, 0,
+    "The returned raw data should be an empty array (2).");
 
-                  client.close().then(() => {
-                    DebuggerServer.destroy();
-                    SimpleTest.finish();
-                  });
-                });
-              });
-            }, 1000);
-          });
-        }, 1000);
-        /* eslint-enable max-nested-callbacks */
-      });
-    });
-  });
+  await target.destroy();
+  SimpleTest.finish();
 };
 </script>
 </pre>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_framerate_06.html
+++ b/devtools/server/tests/mochitest/test_framerate_06.html
@@ -1,83 +1,87 @@
 <!DOCTYPE HTML>
 <html>
 <!--
-Bug 1171489 - Tests if the framerate actor does not record timestamps from multiple frames. 
+Bug 1171489 - Tests if the framerate actor does not record timestamps from multiple frames.
 -->
 <head>
   <meta charset="utf-8">
   <title>Framerate actor test</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
 </head>
 <body>
 <pre id="test">
 <script>
 "use strict";
 
-window.onload = function() {
+window.onload = async function() {
+  // inspector-helpers doesnt wait for explicit finish
   SimpleTest.waitForExplicitFinish();
-  const {FramerateFront} = require("devtools/shared/fronts/framerate");
 
+  const TICK = 1000;
   const url = document.getElementById("testContent").href;
-  attachURL(url, onTab);
+  const { target, doc } = await attachURL(url);
+  const contentWin = doc.defaultView;
+
+  const front = target.getFront("framerate");
+
+  await front.startRecording();
+  await waitFor(TICK);
+  const onWindowReady = waitForWindowReady();
+  contentWin.location.reload();
 
-  function onTab(_, client, form, contentDoc) {
-    const contentWin = contentDoc.defaultView;
+  // Wait for the iframe to be loaded again
+  await onWindowReady;
+  await waitFor(TICK);
+  const ticks = await front.stopRecording();
+  await onRecordingStopped(ticks);
 
-    const front = FramerateFront(client, form);
+  await target.destroy();
+  SimpleTest.finish();
+};
 
-    front.startRecording().then(() => {
-      window.setTimeout(() => {
-        // Wait for the iframe to be loaded again
-        window.addEventListener("message", function loaded(event) {
-          if (event.data === "ready") {
-            window.removeEventListener("message", loaded);
-            /* eslint-disable max-nested-callbacks */
-            window.setTimeout(() => {
-              front.stopRecording().then(ticks => {
-                onRecordingStopped(client, ticks);
-              });
-            }, 1000);
-            /* eslint-enable max-nested-callbacks */
-          }
-        });
-        contentWin.location.reload();
-      }, 1000);
+// Local Helpers
+function waitFor(time) {
+  return new Promise(resolve => setTimeout(resolve, time));
+}
+
+function waitForWindowReady() {
+  return new Promise(resolve => {
+    window.addEventListener("message", function loaded(event) {
+      if (event.data === "ready") {
+        window.removeEventListener("message", loaded);
+        resolve();
+      }
     });
+  });
+}
+
+function onRecordingStopped(ticks) {
+  const diffs = [];
+
+  info(`Got ${ticks.length} ticks.`);
+
+  for (let i = 1; i < ticks.length; i++) {
+    const prev = ticks[i - 1];
+    const curr = ticks[i];
+    diffs.push(curr - prev);
+    info(curr + " - " + (curr - prev));
   }
 
-  function onRecordingStopped(client, ticks) {
-    const diffs = [];
-
-    info(`Got ${ticks.length} ticks.`);
-
-    for (let i = 1; i < ticks.length; i++) {
-      const prev = ticks[i - 1];
-      const curr = ticks[i];
-      diffs.push(curr - prev);
-      info(curr + " - " + (curr - prev));
-    }
-
-    // 1000 / 60 => 16.666... so we shouldn't get more than diffs of 16.66.. but
-    // when we get ticks from other frames they're usually at diffs of < 1. Sometimes
-    // ticks can still be less than 16ms even on one frame (usually following a very slow
-    // frame), so use a low number (2) to be our threshold
-    const THRESHOLD = 2;
-    ok(ticks.length >= 20,
-       "we should have atleast 20 ticks over the course of two seconds.");
-    const belowThreshold = diffs.filter(v => v <= THRESHOLD);
-    ok(belowThreshold.length <= 10,
-       "we should have very few frames less than the threshold");
-
-    client.close().then(() => {
-      DebuggerServer.destroy();
-      SimpleTest.finish();
-    });
-  }
-};
+  // 1000 / 60 => 16.666... so we shouldn't get more than diffs of 16.66.. but
+  // when we get ticks from other frames they're usually at diffs of < 1. Sometimes
+  // ticks can still be less than 16ms even on one frame (usually following a very slow
+  // frame), so use a low number (2) to be our threshold
+  const THRESHOLD = 2;
+  ok(ticks.length >= 20,
+     "we should have atleast 20 ticks over the course of two seconds.");
+  const belowThreshold = diffs.filter(v => v <= THRESHOLD);
+  ok(belowThreshold.length <= 10,
+     "we should have very few frames less than the threshold");
+}
 </script>
 </pre>
 <a id="testContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
 </body>
 </html>
--- a/devtools/server/tests/mochitest/test_inspector-anonymous.html
+++ b/devtools/server/tests/mochitest/test_inspector-anonymous.html
@@ -9,45 +9,42 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {InspectorFront} =
-    require("devtools/shared/fronts/inspector");
   const {DocumentWalker: _documentWalker} =
     require("devtools/server/actors/inspector/document-walker");
 
   const nodeFilterConstants =
     require("devtools/shared/dom-node-filter-constants");
   const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
   SpecialPowers.pushPrefEnv({"set": [
     ["dom.webcomponents.shadowdom.enabled", true]
   ]});
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
   let gInspectee = null;
 
-  addTest(function setup() {
+  addTest(async function setup() {
     info("Setting up inspector and walker actors.");
 
     const url = document.getElementById("inspectorContent").href;
-    attachURL(url, function(err, client, tab, doc) {
-      gInspectee = doc;
-      const inspector = InspectorFront(client, tab);
-      promiseDone(inspector.getWalker().then(walker => {
-        ok(walker, "getWalker() should return an actor.");
-        gWalker = walker;
-      }).then(runNextTest));
-    });
+    const { target, doc } = await attachURL(url);
+    gInspectee = doc;
+    const inspector = target.getInspector();
+    const walker = await inspector.getWalker();
+    ok(walker, "getWalker() should return an actor.");
+    gWalker = walker;
+    runNextTest();
   });
 
   addAsyncTest(async function testXBLAnonymousInHTMLDocument() {
     info("Testing XBL anonymous in an HTML document.");
     const rawToolbarbutton = gInspectee.createElementNS(XUL_NS, "toolbarbutton");
     gInspectee.documentElement.appendChild(rawToolbarbutton);
 
     const toolbarbutton = await gWalker.querySelector(gWalker.rootNode, "toolbarbutton");
--- a/devtools/server/tests/mochitest/test_inspector-changeattrs.html
+++ b/devtools/server/tests/mochitest/test_inspector-changeattrs.html
@@ -16,27 +16,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(function testChangeAttrs() {
   const attrNode = gInspectee.querySelector("#a");
   let attrFront;
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(front => {
     attrFront = front;
     dump("attrFront is: " + attrFront + "\n");
--- a/devtools/server/tests/mochitest/test_inspector-changevalue.html
+++ b/devtools/server/tests/mochitest/test_inspector-changevalue.html
@@ -16,27 +16,25 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  const walker = await inspector.getWalker();
+  ok(walker, "getWalker() should return an actor.");
+  gWalker = walker;
+  runNextTest();
 });
 
 addTest(function testChangeValue() {
   const contentNode = gInspectee.querySelector("#a").firstChild;
   let nodeFront;
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(front => {
     // Get the text child
     return gWalker.children(front, { maxNodes: 1 });
--- a/devtools/server/tests/mochitest/test_inspector-dead-nodes.html
+++ b/devtools/server/tests/mochitest/test_inspector-dead-nodes.html
@@ -18,29 +18,20 @@ window.onload = function() {
   runNextTest();
 };
 
 let gWalker = null;
 let gDoc = null;
 
 addAsyncTest(async function() {
   const url = document.getElementById("inspectorContent").href;
-
-  const attachURLPromise = new Promise(resolve => {
-    attachURL(url, function(err, client, tab, doc) {
-      resolve({client, tab, doc});
-    });
-  });
-  const {client, tab, doc} = await attachURLPromise;
+  const { target, doc } = await attachURL(url);
   gDoc = doc;
-
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-  const inspector = InspectorFront(client, tab);
+  const inspector = target.getInspector();
   gWalker = await inspector.getWalker();
-
   runNextTest();
 });
 
 addAsyncTest(async function() {
   info("Getting a nodeFront, reloading the page, and calling " +
     "walker.children(nodeFront) before the load completes shouldn't fail");
 
   const nodeFront = await gWalker.querySelector(gWalker.rootNode, "body");
--- a/devtools/server/tests/mochitest/test_inspector-display-type.html
+++ b/devtools/server/tests/mochitest/test_inspector-display-type.html
@@ -15,26 +15,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 var gWalker;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  runNextTest();
 });
 
 addAsyncTest(async function testInlineBlockDisplayType() {
   info("Test getting the display type of an inline block element.");
   const node = await gWalker.querySelector(gWalker.rootNode, "#inline-block");
   const displayType = node.displayType;
   is(displayType, "inline-block", "The node has a display type of 'inline-block'.");
   runNextTest();
--- a/devtools/server/tests/mochitest/test_inspector-duplicate-node.html
+++ b/devtools/server/tests/mochitest/test_inspector-duplicate-node.html
@@ -15,26 +15,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(async function testDuplicateNode() {
   const className = ".node-to-duplicate";
   let matches = await gWalker.querySelectorAll(gWalker.rootNode, className);
   is(matches.length, 1, "There should initially be one node to duplicate.");
 
   const nodeFront = await gWalker.querySelector(gWalker.rootNode, className);
--- a/devtools/server/tests/mochitest/test_inspector-hide.html
+++ b/devtools/server/tests/mochitest/test_inspector-hide.html
@@ -16,27 +16,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gInspectee = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(function testRearrange() {
   let listFront = null;
   const listNode = gInspectee.querySelector("#longlist");
 
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#longlist").then(front => {
     listFront = front;
--- a/devtools/server/tests/mochitest/test_inspector-insert.html
+++ b/devtools/server/tests/mochitest/test_inspector-insert.html
@@ -18,27 +18,25 @@ const {DocumentWalker} = require("devtoo
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gInspectee = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspectorFront = InspectorFront(client, tab);
-    promiseDone(inspectorFront.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  const walker = await inspector.getWalker();
+  ok(walker, "getWalker() should return an actor.");
+  gWalker = walker;
+  runNextTest();
 });
 
 addAsyncTest(async function testRearrange() {
   const longlist = await gWalker.querySelector(gWalker.rootNode, "#longlist");
   let children = await gWalker.children(longlist);
   const nodeA = children.nodes[0];
   is(nodeA.id, "a", "Got the expected node.");
 
--- a/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
+++ b/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
@@ -18,27 +18,24 @@ window.onload = function() {
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
 let attrNode;
 let attrFront;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(setupAttrTest);
 addTest(testAddAttribute);
 addTest(testChangeAttribute);
 addTest(testRemoveAttribute);
 addTest(testQueuedMutations);
 addTest(setupFrameAttrTest);
--- a/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html
+++ b/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html
@@ -15,37 +15,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
-let gCleanupConnection = null;
 
-function setup(callback) {
+async function setup(callback) {
   const url = document.getElementById("inspectorContent").href;
-  gCleanupConnection = attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-    }).then(callback));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  callback();
 }
 
 function teardown() {
   gWalker = null;
   gInspectee = null;
-  if (gCleanupConnection) {
-    gCleanupConnection();
-    gCleanupConnection = null;
-  }
 }
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
 function setParent(nodeSelector, newParentSelector) {
   const node = gInspectee.querySelector(nodeSelector);
--- a/devtools/server/tests/mochitest/test_inspector-mutations-events.html
+++ b/devtools/server/tests/mochitest/test_inspector-mutations-events.html
@@ -8,43 +8,34 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1157469</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-
   SimpleTest.waitForExplicitFinish();
 
   let inspectee = null;
   let inspector = null;
   let walker = null;
   const eventListener1 = function() {};
   const eventListener2 = function() {};
   let eventNode1;
   let eventNode2;
   let eventFront1;
   let eventFront2;
 
   addAsyncTest(async function setup() {
     info("Setting up inspector and walker actors.");
     const url = document.getElementById("inspectorContent").href;
-
-    await new Promise(resolve => {
-      attachURL(url, function(err, client, tab, doc) {
-        inspectee = doc;
-        inspector = InspectorFront(client, tab);
-        resolve();
-      });
-    });
-
+    const { target, doc } = await attachURL(url);
+    inspectee = doc;
+    inspector = target.getInspector();
     walker = await inspector.getWalker();
     ok(walker, "getWalker() should return an actor.");
 
     runNextTest();
   });
 
   addAsyncTest(async function setupEventTest() {
     eventNode1 = inspectee.querySelector("#a");
--- a/devtools/server/tests/mochitest/test_inspector-mutations-frameload.html
+++ b/devtools/server/tests/mochitest/test_inspector-mutations-frameload.html
@@ -15,40 +15,31 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
-let gClient = null;
-let gCleanupConnection = null;
+let gTarget = null;
 
-function setup(callback) {
+async function setup(callback) {
   const url = document.getElementById("inspectorContent").href;
-  gCleanupConnection = attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      gClient = client;
-      gWalker = walker;
-    }).then(callback));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  gTarget = target;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  await callback();
 }
 
 function teardown() {
   gWalker = null;
-  gClient = null;
   gInspectee = null;
-  if (gCleanupConnection) {
-    gCleanupConnection();
-    gCleanupConnection = null;
-  }
 }
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
 function loadChildSelector(selector) {
   return gWalker.querySelector(gWalker.rootNode, "#childFrame").then(frame => {
@@ -84,17 +75,17 @@ addTest(function loadNewChild() {
       mutations = assertUnload(mutations);
       mutations = assertFrameLoad(mutations);
       mutations = assertChildList(mutations);
 
       is(mutations.length, 0, "Got the expected mutations.");
 
       assertOwnership();
 
-      return checkMissing(gClient, unloaded);
+      return checkMissing(gTarget, unloaded);
     }).then(() => {
       teardown();
     }).then(runNextTest));
   });
 });
 
 addTest(function loadNewChildTwice() {
   setup(() => {
@@ -147,17 +138,17 @@ addTest(function loadNewChildTwiceAndCar
       mutations = assertUnload(mutations);
       mutations = assertFrameLoad(mutations);
       mutations = assertChildList(mutations);
 
       is(mutations.length, 0, "Got the expected mutations.");
 
       assertOwnership();
 
-      return checkMissing(gClient, unloaded);
+      return checkMissing(gTarget, unloaded);
     }).then(() => {
       teardown();
     }).then(runNextTest));
   });
 });
 
 addTest(function testBack() {
   setup(() => {
@@ -180,17 +171,17 @@ addTest(function testBack() {
       mutations = assertSrcChange(mutations);
       mutations = assertUnload(mutations);
       mutations = assertFrameLoad(mutations);
       mutations = assertChildList(mutations);
       is(mutations.length, 0, "Got the expected mutations.");
 
       assertOwnership();
 
-      return checkMissing(gClient, unloaded);
+      return checkMissing(gTarget, unloaded);
     }).then(() => {
       teardown();
     }).then(runNextTest));
   });
 });
 
   </script>
 </head>
--- a/devtools/server/tests/mochitest/test_inspector-mutations-value.html
+++ b/devtools/server/tests/mochitest/test_inspector-mutations-value.html
@@ -30,27 +30,24 @@ let gInspectee = null;
 let gWalker = null;
 let valueNode;
 var valueFront;
 var longStringFront;
 var longString = "stringstringstringstringstringstringstringstringstringstringstring";
 var shortString = "str";
 var shortString2 = "str2";
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspectorFront = InspectorFront(client, tab);
-    promiseDone(inspectorFront.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(setupValueTest);
 addTest(testKeepLongValue);
 addTest(testSetShortValue);
 addTest(testKeepShortValue);
 addTest(testSetLongValue);
 addTest(setupFrameValueTest);
--- a/devtools/server/tests/mochitest/test_inspector-pick-color.html
+++ b/devtools/server/tests/mochitest/test_inspector-pick-color.html
@@ -11,36 +11,28 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1262439</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-
   SimpleTest.waitForExplicitFinish();
 
   let win = null;
   let inspector = null;
 
   addAsyncTest(async function() {
     info("Setting up inspector actor");
 
     const url = document.getElementById("inspectorContent").href;
-
-    await new Promise(resolve => {
-      attachURL(url, function(err, client, tab, doc) {
-        win = doc.defaultView;
-        inspector = InspectorFront(client, tab);
-        resolve();
-      });
-    });
-
+    const { target, doc } = await attachURL(url);
+    inspector = target.getInspector();
+    win = doc.defaultView;
     runNextTest();
   });
 
   addAsyncTest(async function() {
     info("Start picking a color from the page");
     await inspector.pickColorFromPage();
 
     info("Click in the page and make sure a color-picked event is received");
--- a/devtools/server/tests/mochitest/test_inspector-pseudoclass-lock.html
+++ b/devtools/server/tests/mochitest/test_inspector-pseudoclass-lock.html
@@ -19,37 +19,31 @@ window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 const InspectorUtils = require("InspectorUtils");
 
 let gInspectee = null;
 let gWalker = null;
-let gCleanupConnection = null;
 
-function setup(callback) {
+async function setup(callback) {
   const url = document.getElementById("inspectorContent").href;
-  gCleanupConnection = attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-    }).then(callback));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  const walker = await inspector.getWalker();
+  ok(walker, "getWalker() should return an actor.");
+  gWalker = walker;
+  runNextTest();
 }
 
 function teardown() {
   gWalker = null;
   gInspectee = null;
-  if (gCleanupConnection) {
-    gCleanupConnection();
-    gCleanupConnection = null;
-  }
 }
 
 function checkChange(change, expectation) {
   is(change.type, "pseudoClassLock", "Expect a pseudoclass lock change.");
   const target = change.target;
   if (expectation.id) {
     is(target.id, expectation.id, "Expect a change on node id " + expectation.id);
   }
--- a/devtools/server/tests/mochitest/test_inspector-release.html
+++ b/devtools/server/tests/mochitest/test_inspector-release.html
@@ -14,33 +14,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 "use strict";
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
-let gClient = null;
+let gTarget = null;
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gClient = client;
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gTarget = target;
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(function testReleaseSubtree() {
   let originalOwnershipSize = 0;
   let longlist = null;
   let firstChild = null;
   promiseDone(gWalker.querySelectorAll(gWalker.rootNode, "#longlist div").then(list => {
     // Make sure we have the 26 children of longlist in our ownership tree.
@@ -71,25 +68,25 @@ addTest(function testReleaseSubtree() {
     return gWalker.releaseNode(node);
   }).then(() => {
     // Our ownership size should now be 53 fewer
     // (we forgot about #longlist + 26 children + 26 singleTextChild nodes)
     const newOwnershipSize = assertOwnership();
     is(newOwnershipSize, originalOwnershipSize - 53,
       "Ownership tree should be lower");
     // Now verify that some nodes have gone away
-    return checkMissing(gClient, longlist);
+    return checkMissing(gTarget, longlist);
   }).then(() => {
-    return checkMissing(gClient, firstChild);
+    return checkMissing(gTarget, firstChild);
   }).then(runNextTest));
 });
 
 addTest(function cleanup() {
   gWalker = null;
-  gClient = null;
+  gTarget = null;
   runNextTest();
 });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
 <a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
 <p id="display"></p>
--- a/devtools/server/tests/mochitest/test_inspector-reload.html
+++ b/devtools/server/tests/mochitest/test_inspector-reload.html
@@ -16,31 +16,27 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getWalker();
-    }).then(walker => {
-      dump(walker.actorID + "\n");
-      ok(walker === gWalker, "getWalker() twice should return the same walker.");
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  const walker = await inspector.getWalker();
+  ok(walker, "getWalker() should return an actor.");
+  dump(walker.actorID + "\n");
+  gWalker = await inspector.getWalker();
+  ok(walker === gWalker, "getWalker() twice should return the same walker.");
+  runNextTest();
 });
 
 addTest(function testReload() {
   const oldRootID = gWalker.rootNode.actorID;
   // Load a node to populate the tree a bit.
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(front => {
     gInspectee.defaultView.location.reload();
     return waitForMutation(gWalker, isNewRoot);
--- a/devtools/server/tests/mochitest/test_inspector-remove.html
+++ b/devtools/server/tests/mochitest/test_inspector-remove.html
@@ -14,41 +14,38 @@ https://bugzilla.mozilla.org/show_bug.cg
 "use strict";
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
-let gClient = null;
+let gTarget = null;
 let gInspectee = null;
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
 function ignoreNode(node) {
   // Duplicate the walker logic to skip blank nodes...
   return node.nodeType === Node.TEXT_NODE &&
     !/[^\s]/.test(node.nodeValue);
 }
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gClient = client;
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  gTarget = target;
+  runNextTest();
 });
 
 addTest(function testRemoveSubtree() {
   let originalOwnershipSize = 0;
   let longlist = null;
   let longlistID = null;
 
   let nextSibling = gInspectee.querySelector("#longlist").nextSibling;
@@ -89,23 +86,23 @@ addTest(function testRemoveSubtree() {
   }).then(() => {
     // Our ownership size should now be 51 fewer (we forgot about #longlist + 26
     // children + 26 singleTextChild nodes, but learned about #longlist's
     // prev/next sibling)
     const newOwnershipSize = assertOwnership();
     is(newOwnershipSize, originalOwnershipSize - 51,
       "Ownership tree should be lower");
     // Now verify that some nodes have gone away
-    return checkMissing(gClient, longlistID);
+    return checkMissing(gTarget, longlistID);
   }).then(runNextTest));
 });
 
 addTest(function cleanup() {
   gWalker = null;
-  gClient = null;
+  gTarget = null;
   gInspectee = null;
   runNextTest();
 });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
 <a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
--- a/devtools/server/tests/mochitest/test_inspector-resize.html
+++ b/devtools/server/tests/mochitest/test_inspector-resize.html
@@ -9,38 +9,29 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 1222409</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-
   SimpleTest.waitForExplicitFinish();
 
   let win = null;
   let inspector = null;
 
   addAsyncTest(async function setup() {
     info("Setting up inspector and walker actors.");
 
     const url = document.getElementById("inspectorContent").href;
 
-    // eslint-disable-next-line new-cap
-    await new Promise(resolve => {
-      attachURL(url, function(err, client, tab, doc) {
-        win = doc.defaultView;
-        inspector = InspectorFront(client, tab);
-        resolve();
-      });
-    });
-
+    const { target, doc } = await attachURL(url);
+    inspector = target.getInspector();
+    win = doc.defaultView;
     runNextTest();
   });
 
   addAsyncTest(async function() {
     const walker = await inspector.getWalker();
 
     // We can't receive events from the walker if we haven't first executed a
     // method on the actor to initialize it.
--- a/devtools/server/tests/mochitest/test_inspector-resolve-url.html
+++ b/devtools/server/tests/mochitest/test_inspector-resolve-url.html
@@ -16,24 +16,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspector;
 let gDoc;
 
-addTest(function() {
+addTest(async function() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gDoc = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    gInspector = InspectorFront(client, tab);
-    runNextTest();
-  });
+  const { target, doc } = await attachURL(url);
+  gInspector = target.getInspector();
+  gDoc = doc;
+  runNextTest();
 });
 
 addTest(function() {
   info("Resolve a relative URL without providing a context node");
   gInspector.resolveRelativeURL("test.png?id=4#wow").then(url => {
     is(url, "chrome://mochitests/content/chrome/devtools/server/tests/" +
             "mochitest/test.png?id=4#wow");
     runNextTest();
--- a/devtools/server/tests/mochitest/test_inspector-retain.html
+++ b/devtools/server/tests/mochitest/test_inspector-retain.html
@@ -20,27 +20,23 @@ window.onload = function() {
 
 let gWalker = null;
 let gInspectee = null;
 
 function assertOwnership() {
   return assertOwnershipTrees(gWalker);
 }
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  gWalker = await inspector.getWalker();
+  runNextTest();
 });
 
 // Retain a node, and a second-order child (in another document, for kicks)
 // Release the parent of the top item, which should cause one retained orphan.
 
 // Then unretain the top node, which should retain the orphan.
 
 // Then change the source of the iframe, which should kill that orphan.
--- a/devtools/server/tests/mochitest/test_inspector-scroll-into-view.html
+++ b/devtools/server/tests/mochitest/test_inspector-scroll-into-view.html
@@ -16,27 +16,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(async function testScrollIntoView() {
   const id = "#scroll-into-view";
   let rect = gInspectee.querySelector(id).getBoundingClientRect();
   const nodeFront = await gWalker.querySelector(gWalker.rootNode, id);
   let inViewport = rect.x >= 0 &&
                    rect.y >= 0 &&
--- a/devtools/server/tests/mochitest/test_inspector-search-front.html
+++ b/devtools/server/tests/mochitest/test_inspector-search-front.html
@@ -8,42 +8,33 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 835896</title>
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
-  const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
-
   SimpleTest.waitForExplicitFinish();
 
   let walkerFront = null;
   let inspector = null;
 
   // WalkerFront specific tests.  These aren't to excercise search
   // edge cases so much as to test the state the Front maintains between
   // searches.
   // See also test_inspector-search.html
 
   addAsyncTest(async function setup() {
     info("Setting up inspector and walker actors.");
 
     const url = document.getElementById("inspectorContent").href;
 
-    // eslint-disable-next-line new-cap
-    await new Promise(resolve => {
-      attachURL(url, function(err, client, tab, doc) {
-        inspector = InspectorFront(client, tab);
-        resolve();
-      });
-    });
-
+    const { target } = await attachURL(url);
+    inspector = target.getInspector();
     walkerFront = await inspector.getWalker();
     ok(walkerFront, "getWalker() should return an actor.");
 
     runNextTest();
   });
 
   addAsyncTest(async function testWalkerFrontDefaults() {
     info("Testing search API using WalkerFront.");
--- a/devtools/server/tests/mochitest/test_inspector-search.html
+++ b/devtools/server/tests/mochitest/test_inspector-search.html
@@ -9,17 +9,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
 window.onload = function() {
   const {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
-  const {InspectorFront} = require("devtools/shared/fronts/inspector");
   const {WalkerSearch, WalkerIndex} =
     require("devtools/server/actors/utils/walker-search");
 
   SimpleTest.waitForExplicitFinish();
 
   let walkerActor = null;
   let walkerSearch = null;
   let inspectee = null;
@@ -29,24 +28,19 @@ window.onload = function() {
   // coming back as expected.
   // See also test_inspector-search-front.html.
 
   addAsyncTest(async function setup() {
     info("Setting up inspector and walker actors.");
 
     const url = document.getElementById("inspectorContent").href;
 
-    // eslint-disable-next-line new-cap
-    await new Promise(resolve => {
-      attachURL(url, function(err, client, tab, doc) {
-        inspectee = doc;
-        inspector = InspectorFront(client, tab);
-        resolve();
-      });
-    });
+    const { target, doc } = await attachURL(url);
+    inspectee = doc;
+    inspector = target.getInspector();
 
     const walkerFront = await inspector.getWalker();
     ok(walkerFront, "getWalker() should return an actor.");
 
     walkerActor = DebuggerServer.searchAllConnectionsForActor(walkerFront.actorID);
     ok(walkerActor,
       "Got a reference to the walker actor (" + walkerFront.actorID + ")");
 
--- a/devtools/server/tests/mochitest/test_inspector-template.html
+++ b/devtools/server/tests/mochitest/test_inspector-template.html
@@ -17,24 +17,18 @@ Display template tag content in inspecto
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
 
   let gWalker = null;
 
   addAsyncTest(async function setup() {
     const url = document.getElementById("inspectorContent").href;
 
-    const {client, tab} = await new Promise(resolve => {
-      attachURL(url, function(err, _client, _tab, doc) {
-        resolve({ client: _client, tab: _tab });
-      });
-    });
-
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
+    const { target } = await attachURL(url);
+    const inspector = target.getInspector();
     gWalker = await inspector.getWalker();
 
     runNextTest();
   });
 
   addAsyncTest(async function testWalker() {
     const nodeFront = await gWalker.querySelector(gWalker.rootNode, "template");
 
--- a/devtools/server/tests/mochitest/test_inspector-traversal.html
+++ b/devtools/server/tests/mochitest/test_inspector-traversal.html
@@ -14,35 +14,32 @@ https://bugzilla.mozilla.org/show_bug.cg
 "use strict";
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gInspectee = null;
-let gClient = null;
+let gTarget = null;
 let gWalker = null;
 const checkActorIDs = [];
 
 function assertOwnership() {
   assertOwnershipTrees(gWalker);
 }
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gClient = client;
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
+  gTarget = target;
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(function testWalkerRoot() {
   // Make sure that refetching the root document of the walker returns the same
   // actor as the getWalker returned.
   promiseDone(gWalker.document().then(root => {
     ok(root === gWalker.rootNode,
        "Re-fetching the document node should match the root document node.");
@@ -132,17 +129,17 @@ addTest(function testQuerySelectors() {
     checkActorIDs.push(nodes[0].actorID);
     // Save the node list ID so we can ensure it was destroyed.
     nodeListID = nodeList.actorID;
     assertOwnership();
     return nodeList.release();
   }).then(() => {
     ok(!nodeList.actorID, "Actor should have been destroyed.");
     assertOwnership();
-    return checkMissing(gClient, nodeListID);
+    return checkMissing(gTarget, nodeListID);
   }).then(runNextTest));
 });
 
 // Helper to check the response of requests that return hasFirst/hasLast/nodes
 // node lists (like `children` and `siblings`)
 function nodeArrayChecker(first, last, ids) {
   return function(response) {
     is(response.hasFirst, first,
@@ -308,25 +305,25 @@ addTest(function testShortValue() {
        "Full node value should match the string from the document.");
   }).then(runNextTest));
 });
 
 addTest(function testReleaseWalker() {
   checkActorIDs.push(gWalker.actorID);
 
   promiseDone(gWalker.release().then(() => {
-    const promises = Array.from(checkActorIDs, (id) => checkMissing(gClient, id));
+    const promises = Array.from(checkActorIDs, (id) => checkMissing(gTarget, id));
     return Promise.all(promises);
   }).then(runNextTest));
 });
 
 addTest(function cleanup() {
   gWalker = null;
   gInspectee = null;
-  gClient = null;
+  gTarget = null;
   runNextTest();
 });
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug </a>
 <a id="inspectorContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
 <p id="display"></p>
--- a/devtools/server/tests/mochitest/test_inspector_getImageData-wait-for-load.html
+++ b/devtools/server/tests/mochitest/test_inspector_getImageData-wait-for-load.html
@@ -36,34 +36,26 @@ function pushPref(preferenceName, value)
     SpecialPowers.pushPrefEnv(options, resolve);
   });
 }
 
 let gImg = null;
 let gNodeFront = null;
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-      // eslint-disable-next-line max-nested-callbacks
-      return walker.querySelector(gWalker.rootNode, "img.custom").then(img => {
-        gNodeFront = img;
-        gImg = doc.querySelector("img.custom");
-
-        ok(gNodeFront, "Got the image NodeFront.");
-        ok(gImg, "Got the image Node.");
-      });
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  gNodeFront = await gWalker.querySelector(gWalker.rootNode, "img.custom");
+  gImg = doc.querySelector("img.custom");
+  ok(gNodeFront, "Got the image NodeFront.");
+  ok(gImg, "Got the image Node.");
+  runNextTest();
 });
 
 addTest(async function testTimeout() {
   info("Testing that the method aborts if the image takes too long to load.");
 
   // imageToImageData() only times out when flags.testing is not set.
   await pushPref("devtools.testing", false);
 
--- a/devtools/server/tests/mochitest/test_inspector_getImageData.html
+++ b/devtools/server/tests/mochitest/test_inspector_getImageData.html
@@ -15,26 +15,22 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  runNextTest();
 });
 
 addTest(function testLargeImage() {
   // Select the image node from the test page
   gWalker.querySelector(gWalker.rootNode, ".big-horizontal").then(img => {
     ok(img, "Image node found in the test page");
     ok(img.getImageData, "Image node has the getImageData function");
 
--- a/devtools/server/tests/mochitest/test_inspector_getImageDataFromURL.html
+++ b/devtools/server/tests/mochitest/test_inspector_getImageDataFromURL.html
@@ -33,23 +33,21 @@ function pushPref(preferenceName, value)
   return new Promise(resolve => {
     const options = {"set": [[preferenceName, value]]};
     SpecialPowers.pushPrefEnv(options, resolve);
   });
 }
 
 let gInspector = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    gInspector = InspectorFront(client, tab);
-    runNextTest();
-  });
+  const { target } = await attachURL(url);
+  gInspector = target.getInspector();
+  runNextTest();
 });
 
 addTest(async function testTimeout() {
   info("Testing that the method aborts if the image takes too long to load.");
 
   // imageToImageData() only times out when flags.testing is not set.
   await pushPref("devtools.testing", false);
 
--- a/devtools/server/tests/mochitest/test_inspector_getNodeFromActor.html
+++ b/devtools/server/tests/mochitest/test_inspector_getNodeFromActor.html
@@ -15,26 +15,23 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker;
 
-addTest(function() {
+addTest(async function() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  runNextTest();
 });
 
 addTest(function() {
   info("Try to get a NodeFront from an invalid actorID");
   gWalker.getNodeFromActor("invalid", ["node"]).then(node => {
     ok(!node, "The node returned is null");
     runNextTest();
   });
--- a/devtools/server/tests/mochitest/test_inspector_getOffsetParent.html
+++ b/devtools/server/tests/mochitest/test_inspector_getOffsetParent.html
@@ -17,32 +17,24 @@ window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 var gWalker;
 var gHTMLNode;
 var gBodyNode;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-
-    promiseDone(inspector.getWalker().then(walker => {
-      gWalker = walker;
-      return gWalker.querySelector(gWalker.rootNode, "body");
-    }).then(node => {
-      gBodyNode = node;
-      return gWalker.querySelector(gWalker.rootNode, "html");
-    }).then(node => {
-      gHTMLNode = node;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  gBodyNode = await gWalker.querySelector(gWalker.rootNode, "body");
+  gHTMLNode = await gWalker.querySelector(gWalker.rootNode, "html");
+  runNextTest();
 });
 
 addTest(function() {
   info("Try to get the offset parent for a dead node (null)");
   gWalker.getOffsetParent(null).then(offsetParent => {
     ok(!offsetParent, "No offset parent found");
     runNextTest();
   });
--- a/devtools/server/tests/mochitest/test_styles-applied.html
+++ b/devtools/server/tests/mochitest/test_styles-applied.html
@@ -16,29 +16,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gStyles = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getPageStyle();
-    }).then(styles => {
-      gStyles = styles;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  gStyles = await inspector.getPageStyle();
+  runNextTest();
 });
 
 addTest(function inheritedUserStyles() {
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#test-node").then(node => {
     return gStyles.getApplied(node, { inherited: true, filter: "user" });
   }).then(applied => {
     ok(!applied[0].inherited, "Entry 0 should be uninherited");
     is(applied[0].rule.type, 100, "Entry 0 should be an element style");
--- a/devtools/server/tests/mochitest/test_styles-computed.html
+++ b/devtools/server/tests/mochitest/test_styles-computed.html
@@ -16,29 +16,24 @@ https://bugzilla.mozilla.org/show_bug.cg
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gStyles = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getPageStyle();
-    }).then(styles => {
-      gStyles = styles;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  gStyles = await inspector.getPageStyle();
+  runNextTest();
 });
 
 addTest(function testComputed() {
   promiseDone(
     gWalker.querySelector(gWalker.rootNode, "#computed-test-node").then(node => {
       return gStyles.getComputed(node, {});
     }).then(computed => {
       // Test a smattering of properties that include some system-defined
--- a/devtools/server/tests/mochitest/test_styles-layout.html
+++ b/devtools/server/tests/mochitest/test_styles-layout.html
@@ -12,29 +12,25 @@
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gStyles = null;
 
-addTest(function() {
+addTest(async function() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getPageStyle();
-    }).then(styles => {
-      gStyles = styles;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  const walker = await inspector.getWalker();
+  ok(walker, "getWalker() should return an actor.");
+  gWalker = walker;
+  gStyles = await inspector.getPageStyle();
+  runNextTest();
 });
 
 addTest(function() {
   ok(gStyles.getLayout, "The PageStyleActor has a getLayout method");
   runNextTest();
 });
 
 addAsyncTest(async function() {
--- a/devtools/server/tests/mochitest/test_styles-matched.html
+++ b/devtools/server/tests/mochitest/test_styles-matched.html
@@ -19,30 +19,25 @@ window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gStyles = null;
 let gInspectee = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    gInspectee = doc;
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getPageStyle();
-    }).then(styles => {
-      gStyles = styles;
-    }).then(runNextTest));
-  });
+  const { target, doc } = await attachURL(url);
+  gInspectee = doc;
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  gStyles = await inspector.getPageStyle();
+  runNextTest();
 });
 
 addTest(function testMatchedStyles() {
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#matched-test-node").then(node => {
     return gStyles.getMatchedSelectors(node, "font-size", {});
   }).then(matched => {
     is(matched[0].sourceText, "this.style", "First match comes from the element style");
     is(matched[0].selector, "@element.style", "Element style has a special selector");
--- a/devtools/server/tests/mochitest/test_styles-modify.html
+++ b/devtools/server/tests/mochitest/test_styles-modify.html
@@ -21,26 +21,20 @@ window.onload = function() {
 };
 
 var gWalker = null;
 var gStyles = null;
 var gInspectee = null;
 
 addAsyncTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  let inspector;
 
-  await new Promise(resolve => {
-    attachURL(url, function(err, client, tab, doc) {
-      gInspectee = doc;
-      const {InspectorFront} = require("devtools/shared/fronts/inspector");
-      inspector = InspectorFront(client, tab);
-      resolve();
-    });
-  });
+  const { target, doc } = await attachURL(url);
+  const inspector = target.getInspector();
+  gInspectee = doc;
 
   gWalker = await inspector.getWalker();
   gStyles = await inspector.getPageStyle();
 
   runNextTest();
 });
 
 addAsyncTest(async function modifyProperties() {
--- a/devtools/server/tests/mochitest/test_styles-svg.html
+++ b/devtools/server/tests/mochitest/test_styles-svg.html
@@ -17,29 +17,24 @@ Bug 921191 - allow inspection/editing of
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 let gWalker = null;
 let gStyles = null;
 
-addTest(function setup() {
+addTest(async function setup() {
   const url = document.getElementById("inspectorContent").href;
-  attachURL(url, function(err, client, tab, doc) {
-    const {InspectorFront} = require("devtools/shared/fronts/inspector");
-    const inspector = InspectorFront(client, tab);
-    promiseDone(inspector.getWalker().then(walker => {
-      ok(walker, "getWalker() should return an actor.");
-      gWalker = walker;
-      return inspector.getPageStyle();
-    }).then(styles => {
-      gStyles = styles;
-    }).then(runNextTest));
-  });
+  const { target } = await attachURL(url);
+  const inspector = target.getInspector();
+  gWalker = await inspector.getWalker();
+  ok(gWalker, "getWalker() should return an actor.");
+  gStyles = await inspector.getPageStyle();
+  runNextTest();
 });
 
 addTest(function inheritedUserStyles() {
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#svgcontent rect").then(node => {
     return gStyles.getApplied(node, { inherited: true, filter: "user" });
   }).then(applied => {
     is(applied.length, 2, "Should have 2 rules");
     is(applied[1].rule.cssText, "fill: rgb(1, 2, 3);", "cssText is right");
--- a/dom/interfaces/payments/nsIPaymentRequest.idl
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -25,17 +25,16 @@ interface nsIPaymentCurrencyAmount : nsI
 };
 
 [scriptable, builtinclass, uuid(4f78a59f-b5ff-4fb5-ab48-3b37d0101b02)]
 interface nsIPaymentItem : nsISupports
 {
   readonly attribute AString label;
   readonly attribute nsIPaymentCurrencyAmount amount;
   readonly attribute boolean pending;
-  readonly attribute AString type;
 };
 
 [scriptable, builtinclass, uuid(74259861-c318-40e8-b3d5-518e701bed80)]
 interface nsIPaymentDetailsModifier : nsISupports
 {
   readonly attribute AString supportedMethods;
   readonly attribute nsIPaymentItem total;
   readonly attribute nsIArray additionalDisplayItems;
--- a/dom/payments/PaymentRequestData.cpp
+++ b/dom/payments/PaymentRequestData.cpp
@@ -104,37 +104,35 @@ PaymentCurrencyAmount::GetValue(nsAStrin
 
 /* PaymentItem */
 
 NS_IMPL_ISUPPORTS(PaymentItem,
                   nsIPaymentItem)
 
 PaymentItem::PaymentItem(const nsAString& aLabel,
                          nsIPaymentCurrencyAmount* aAmount,
-                         const bool aPending,
-                         const nsAString& aType)
+                         const bool aPending)
   : mLabel(aLabel)
   , mAmount(aAmount)
   , mPending(aPending)
-  , mType(aType)
 {
 }
 
 nsresult
 PaymentItem::Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem)
 {
   NS_ENSURE_ARG_POINTER(aItem);
   nsCOMPtr<nsIPaymentCurrencyAmount> amount;
   nsresult rv = PaymentCurrencyAmount::Create(aIPCItem.amount(),
                                               getter_AddRefs(amount));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   nsCOMPtr<nsIPaymentItem> item =
-    new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending(), aIPCItem.type());
+    new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending());
   item.forget(aItem);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PaymentItem::GetLabel(nsAString& aLabel)
 {
   aLabel = mLabel;
@@ -154,23 +152,16 @@ PaymentItem::GetAmount(nsIPaymentCurrenc
 NS_IMETHODIMP
 PaymentItem::GetPending(bool* aPending)
 {
   NS_ENSURE_ARG_POINTER(aPending);
   *aPending = mPending;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-PaymentItem::GetType(nsAString& aType)
-{
-  aType = mType;
-  return NS_OK;
-}
-
 /* PaymentDetailsModifier */
 
 NS_IMPL_ISUPPORTS(PaymentDetailsModifier,
                   nsIPaymentDetailsModifier)
 
 PaymentDetailsModifier::PaymentDetailsModifier(const nsAString& aSupportedMethods,
                                                nsIPaymentItem* aTotal,
                                                nsIArray* aAdditionalDisplayItems,
--- a/dom/payments/PaymentRequestData.h
+++ b/dom/payments/PaymentRequestData.h
@@ -60,25 +60,23 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTITEM
 
   static nsresult Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem);
 
 private:
   PaymentItem(const nsAString& aLabel,
               nsIPaymentCurrencyAmount* aAmount,
-              const bool aPending,
-              const nsAString& aType);
+              const bool aPending);
 
   ~PaymentItem() = default;
 
   nsString mLabel;
   nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
   bool mPending;
-  nsString mType;
 };
 
 class PaymentDetailsModifier final : public nsIPaymentDetailsModifier
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPAYMENTDETAILSMODIFIER
 
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -46,28 +46,19 @@ ConvertCurrencyAmount(const PaymentCurre
                       IPCPaymentCurrencyAmount& aIPCCurrencyAmount)
 {
   aIPCCurrencyAmount = IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
 }
 
 void
 ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem)
 {
-  uint8_t typeIndex = UINT8_MAX;
-  if (aItem.mType.WasPassed()) {
-    typeIndex = static_cast<uint8_t>(aItem.mType.Value());
-  }
-  nsString type;
-  if (typeIndex < ArrayLength(PaymentItemTypeValues::strings)) {
-    type.AssignASCII(
-      PaymentItemTypeValues::strings[typeIndex].value);
-  }
   IPCPaymentCurrencyAmount amount;
   ConvertCurrencyAmount(aItem.mAmount, amount);
-  aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending, type);
+  aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
 }
 
 nsresult
 ConvertModifier(JSContext* aCx,
                 const PaymentDetailsModifier& aModifier,
                 IPCPaymentDetailsModifier& aIPCModifier)
 {
   NS_ENSURE_ARG_POINTER(aCx);
--- a/dom/payments/ipc/PPaymentRequest.ipdl
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -22,17 +22,16 @@ struct IPCPaymentCurrencyAmount
   nsString value;
 };
 
 struct IPCPaymentItem
 {
   nsString label;
   IPCPaymentCurrencyAmount amount;
   bool pending;
-  nsString type;
 };
 
 struct IPCPaymentDetailsModifier
 {
   nsString supportedMethods;
   IPCPaymentItem total;
   IPCPaymentItem[] additionalDisplayItems;
   nsString data;
--- a/dom/payments/test/ConstructorChromeScript.js
+++ b/dom/payments/test/ConstructorChromeScript.js
@@ -136,58 +136,39 @@ function checkComplexRequest(payRequest)
   if (details.totalItem.amount.value != "100.00") {
     emitTestFail("total item's value should be '100.00'.");
   }
 
   const displayItems = details.displayItems;
   if (!details.displayItems) {
     emitTestFail("details.displayItems should not be undefined.");
   }
-  if (displayItems.length != 3) {
-    emitTestFail("displayItems' length should be 3.")
+  if (displayItems.length != 2) {
+    emitTestFail("displayItems' length should be 2.")
   }
   let item = displayItems.queryElementAt(0, Ci.nsIPaymentItem);
   if (item.label != "First item") {
     emitTestFail("1st display item's label should be 'First item'.");
   }
   if (item.amount.currency != "USD") {
     emitTestFail("1st display item's currency should be 'USD'.");
   }
   if (item.amount.value != "60.00") {
     emitTestFail("1st display item's value should be '60.00'.");
   }
-  if (item.type != "") {
-    emitTestFail("1st display item's type should be ''.");
-  }
   item = displayItems.queryElementAt(1, Ci.nsIPaymentItem);
   if (item.label != "Second item") {
     emitTestFail("2nd display item's label should be 'Second item'.");
   }
   if (item.amount.currency != "USD") {
     emitTestFail("2nd display item's currency should be 'USD'.");
   }
   if (item.amount.value != "40.00") {
     emitTestFail("2nd display item's value should be '40.00'.");
   }
-  if (item.type != "") {
-    emitTestFail("2nd display item's type should be ''.");
-  }
-  item = displayItems.queryElementAt(2, Ci.nsIPaymentItem);
-  if (item.label != "Tax") {
-    emitTestFail("3rd display item's label should be 'Tax'.");
-  }
-  if (item.amount.currency != "USD") {
-    emitTestFail("3rd display item's currency should be 'USD'.");
-  }
-  if (item.amount.value != "5.00") {
-    emitTestFail("3rd display item's value should be '5.00'.");
-  }
-  if (item.type != "tax") {
-    emitTestFail("3rd display item's type should be 'tax'.");
-  }
 
   const modifiers = details.modifiers;
   if (!modifiers) {
     emitTestFail("details.displayItems should not be undefined.");
   }
   if (modifiers.length != 1) {
     emitTestFail("modifiers' length should be 1.");
   }
--- a/dom/payments/test/test_constructor.html
+++ b/dom/payments/test/test_constructor.html
@@ -70,24 +70,16 @@ https://bugzilla.mozilla.org/show_bug.cg
         }
       },
       {
         label: "Second item",
         amount: {
           currency: "USD",
           value: "40.00"
         }
-      },
-      {
-        label: "Tax",
-        amount: {
-          currency: "USD",
-          value: "5.00"
-        },
-        type: "tax"
       }
     ],
     modifiers: [
       {
         supportedMethods: "basic-card",
         total: {
           label: "Discounted Total",
           amount: {
--- a/dom/plugins/ipc/FunctionBrokerIPCUtils.h
+++ b/dom/plugins/ipc/FunctionBrokerIPCUtils.h
@@ -43,17 +43,19 @@ enum FunctionHookId
   , ID_HttpEndRequestA
   , ID_InternetQueryOptionA
   , ID_InternetErrorDlg
   , ID_AcquireCredentialsHandleA
   , ID_QueryCredentialsAttributesA
   , ID_FreeCredentialsHandle
   , ID_PrintDlgW
   , ID_CreateMutexW
+#if defined(MOZ_SANDBOX)
   , ID_GetFileAttributesW
+#endif // defined(MOZ_SANDBOX)
   , ID_FunctionHookCount
 #else // defined(XP_WIN)
     ID_FunctionHookCount
 #endif // defined(XP_WIN)
 };
 
 // Max number of bytes to show when logging a blob of raw memory
 static const uint32_t MAX_BLOB_CHARS_TO_LOG = 12;
--- a/dom/webidl/PaymentRequest.webidl
+++ b/dom/webidl/PaymentRequest.webidl
@@ -15,25 +15,20 @@ dictionary PaymentMethodData {
            object              data;
 };
 
 dictionary PaymentCurrencyAmount {
   required DOMString currency;
   required DOMString value;
 };
 
-enum PaymentItemType {
-  "tax"
-};
-
 dictionary PaymentItem {
   required DOMString             label;
   required PaymentCurrencyAmount amount;
            boolean               pending = false;
-           PaymentItemType       type;
 };
 
 dictionary PaymentShippingOption {
   required DOMString             id;
   required DOMString             label;
   required PaymentCurrencyAmount amount;
            boolean               selected = false;
 };
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -22,18 +22,16 @@
 #define GLAPI
 #endif
 
 namespace mozilla {
 namespace gl {
 
 struct GLContextSymbols final
 {
-    GLContextSymbols() = delete; // Initialize with {}.
-
     void (GLAPIENTRY * fActiveTexture)(GLenum);
     void (GLAPIENTRY * fAttachShader)(GLuint, GLuint);
     void (GLAPIENTRY * fBeginQuery)(GLenum, GLuint);
     void (GLAPIENTRY * fBindAttribLocation)(GLuint, GLuint, const GLchar*);
     void (GLAPIENTRY * fBindBuffer)(GLenum, GLuint);
     void (GLAPIENTRY * fBindTexture)(GLenum, GLuint);
     void (GLAPIENTRY * fBindVertexArray)(GLuint);
     void (GLAPIENTRY * fBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat);
--- a/js/src/builtin/Boolean-inl.h
+++ b/js/src/builtin/Boolean-inl.h
@@ -15,16 +15,16 @@
 
 namespace js {
 
 inline bool
 EmulatesUndefined(JSObject* obj)
 {
     // This may be called off the main thread. It's OK not to expose the object
     // here as it doesn't escape.
-    AutoUnsafeCallWithABI unsafe;
+    AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
     JSObject* actual = MOZ_LIKELY(!obj->is<WrapperObject>()) ? obj : UncheckedUnwrapWithoutExpose(obj);
     return actual->getClass()->emulatesUndefined();
 }
 
 } /* namespace js */
 
 #endif /* builtin_Boolean_inl_h */
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -14,34 +14,34 @@
 #include "js/Value.h"
 #include "vm/JSContext.h"
 
 namespace js {
 
 inline double
 NumberDiv(double a, double b)
 {
-    AutoUnsafeCallWithABI unsafe;
+    AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
     if (b == 0) {
         if (a == 0 || mozilla::IsNaN(a)) {
             return JS::GenericNaN();
         }
         if (mozilla::IsNegative(a) != mozilla::IsNegative(b)) {
             return mozilla::NegativeInfinity<double>();
         }
         return mozilla::PositiveInfinity<double>();
     }
 
     return a / b;
 }
 
 inline double
 NumberMod(double a, double b)
 {
-    AutoUnsafeCallWithABI unsafe;
+    AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
     if (b == 0) {
         return JS::GenericNaN();
     }
     return fmod(a, b);
 }
 
 } // namespace js
 
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -538,17 +538,17 @@ js::minmax_impl(JSContext* cx, bool max,
     }
 
     return true;
 }
 
 double
 js::powi(double x, int32_t y)
 {
-    AutoUnsafeCallWithABI unsafe;
+    AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
     uint32_t n = Abs(y);
     double m = x;
     double p = 1;
     while (true) {
         if ((n & 1) != 0) p *= m;
         n >>= 1;
         if (n == 0) {
             if (y < 0) {
--- a/js/xpconnect/tests/components/js/xpctest.manifest
+++ b/js/xpconnect/tests/components/js/xpctest.manifest
@@ -19,10 +19,8 @@ contract @mozilla.org/js/xpc/test/js/Int
 component {90ec5c9e-f6da-406b-9a38-14d00f59db76} xpctest_interfaces.js
 contract @mozilla.org/js/xpc/test/js/TestInterfaceAll;1 {90ec5c9e-f6da-406b-9a38-14d00f59db76}
 
 component {38dd78aa-467f-4fad-8dcf-4383a743e235} xpctest_returncode_child.js
 contract @mozilla.org/js/xpc/test/js/ReturnCodeChild;1 {38dd78aa-467f-4fad-8dcf-4383a743e235}
 
 component {e86573c4-a384-441a-8c92-7b99e8575b28} xpctest_utils.js
 contract @mozilla.org/js/xpc/test/js/TestUtils;1 {e86573c4-a384-441a-8c92-7b99e8575b28}
-
-interfaces xpctest.xpt
--- a/js/xpconnect/tests/components/native/moz.build
+++ b/js/xpconnect/tests/components/native/moz.build
@@ -3,20 +3,16 @@
 # 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/.
 
 EXPORTS += [
     'xpctest_private.h',
 ]
 
-EXTRA_COMPONENTS += [
-    'xpctest.manifest',
-]
-
 UNIFIED_SOURCES += [
     'xpctest_attributes.cpp',
     'xpctest_module.cpp',
     'xpctest_params.cpp',
     'xpctest_returncode.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
deleted file mode 100644
--- a/js/xpconnect/tests/components/native/xpctest.manifest
+++ /dev/null
@@ -1,1 +0,0 @@
-interfaces xpctest.xpt
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5308,28 +5308,54 @@ nsLayoutUtils::IntrinsicForAxis(Physical
   AutoMaybeDisableFontInflation an(aFrame);
 
   // We want the size this frame will contribute to the parent's inline-size,
   // so we work in the parent's writing mode; but if aFrame is orthogonal to
   // its parent, we'll need to look at its BSize instead of min/pref-ISize.
   const nsStylePosition* stylePos = aFrame->StylePosition();
   StyleBoxSizing boxSizing = stylePos->mBoxSizing;
 
-  const nsStyleCoord& styleMinISize =
+  nsStyleCoord styleMinISize =
     horizontalAxis ? stylePos->mMinWidth : stylePos->mMinHeight;
-  const nsStyleCoord& styleISize =
+  nsStyleCoord styleISize =
     (aFlags & MIN_INTRINSIC_ISIZE) ? styleMinISize :
     (horizontalAxis ? stylePos->mWidth : stylePos->mHeight);
   MOZ_ASSERT(!(aFlags & MIN_INTRINSIC_ISIZE) ||
              styleISize.GetUnit() == eStyleUnit_Auto ||
              styleISize.GetUnit() == eStyleUnit_Enumerated,
              "should only use MIN_INTRINSIC_ISIZE for intrinsic values");
-  const nsStyleCoord& styleMaxISize =
+  nsStyleCoord styleMaxISize =
     horizontalAxis ? stylePos->mMaxWidth : stylePos->mMaxHeight;
 
+  PhysicalAxis ourInlineAxis =
+    aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
+  const bool isInlineAxis = aAxis == ourInlineAxis;
+
+  auto resetIfKeywords = [](nsStyleCoord& aSize,
+                            nsStyleCoord& aMinSize,
+                            nsStyleCoord& aMaxSize) {
+    if (aSize.GetUnit() == eStyleUnit_Enumerated) {
+      aSize.SetAutoValue();
+    }
+    if (aMinSize.GetUnit() == eStyleUnit_Enumerated) {
+      aMinSize.SetAutoValue();
+    }
+    if (aMaxSize.GetUnit() == eStyleUnit_Enumerated) {
+      aMaxSize.SetNoneValue();
+    }
+  };
+  // According to the spec, max-content and min-content should behave as the
+  // property's initial values in block axis.
+  // It also make senses to use the initial values for -moz-fit-content and
+  // -moz-available for intrinsic size in block axis. Therefore, we reset them
+  // if needed.
+  if (!isInlineAxis) {
+    resetIfKeywords(styleISize, styleMinISize, styleMaxISize);
+  }
+
   // We build up two values starting with the content box, and then
   // adding padding, border and margin.  The result is normally
   // |result|.  Then, when we handle 'width', 'min-width', and
   // 'max-width', we use the results we've been building in |min| as a
   // minimum, overriding 'min-width'.  This ensures two things:
   //   * that we don't let a value of 'box-sizing' specifying a width
   //     smaller than the padding/border inside the box-sizing box give
   //     a content width less than zero
@@ -5349,27 +5375,25 @@ nsLayoutUtils::IntrinsicForAxis(Physical
     // flex items' min-sizes are intentionally ignored until the flex
     // container explicitly considers them during space distribution.
     minISize = 0;
     haveFixedMinISize = true;
   } else {
     haveFixedMinISize = GetAbsoluteCoord(styleMinISize, minISize);
   }
 
-  PhysicalAxis ourInlineAxis =
-    aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
-  const bool isInlineAxis = aAxis == ourInlineAxis;
   // If we have a specified width (or a specified 'min-width' greater
   // than the specified 'max-width', which works out to the same thing),
   // don't even bother getting the frame's intrinsic width, because in
   // this case GetAbsoluteCoord(styleISize, w) will always succeed, so
   // we'll never need the intrinsic dimensions.
   if (styleISize.GetUnit() == eStyleUnit_Enumerated &&
       (styleISize.GetIntValue() == NS_STYLE_WIDTH_MAX_CONTENT ||
        styleISize.GetIntValue() == NS_STYLE_WIDTH_MIN_CONTENT)) {
+    MOZ_ASSERT(isInlineAxis);
     // -moz-fit-content and -moz-available enumerated widths compute intrinsic
     // widths just like auto.
     // For -moz-max-content and -moz-min-content, we handle them like
     // specified widths, but ignore box-sizing.
     boxSizing = StyleBoxSizing::Content;
   } else if (!styleISize.ConvertsToLength() &&
              !(haveFixedMinISize && haveFixedMaxISize && maxISize <= minISize)) {
 #ifdef DEBUG_INTRINSIC_WIDTH
@@ -5411,23 +5435,32 @@ nsLayoutUtils::IntrinsicForAxis(Physical
 #endif
 
     // Handle elements with an intrinsic ratio (or size) and a specified
     // height, min-height, or max-height.
     // NOTE: We treat "min-height:auto" as "0" for the purpose of this code,
     // since that's what it means in all cases except for on flex items -- and
     // even there, we're supposed to ignore it (i.e. treat it as 0) until the
     // flex container explicitly considers it.
-    const nsStyleCoord& styleBSize =
+    nsStyleCoord styleBSize =
       horizontalAxis ? stylePos->mHeight : stylePos->mWidth;
-    const nsStyleCoord& styleMinBSize =
+    nsStyleCoord styleMinBSize =
       horizontalAxis ? stylePos->mMinHeight : stylePos->mMinWidth;
-    const nsStyleCoord& styleMaxBSize =
+    nsStyleCoord styleMaxBSize =
       horizontalAxis ? stylePos->mMaxHeight : stylePos->mMaxWidth;
 
+    // According to the spec, max-content and min-content should behave as the
+    // property's initial values in block axis.
+    // It also make senses to use the initial values for -moz-fit-content and
+    // -moz-available for intrinsic size in block axis. Therefore, we reset them
+    // if needed.
+    if (isInlineAxis) {
+      resetIfKeywords(styleBSize, styleMinBSize, styleMaxBSize);
+    }
+
     if (styleBSize.GetUnit() != eStyleUnit_Auto ||
         !(styleMinBSize.GetUnit() == eStyleUnit_Auto ||
           (styleMinBSize.GetUnit() == eStyleUnit_Coord &&
            styleMinBSize.GetCoordValue() == 0)) ||
         styleMaxBSize.GetUnit() != eStyleUnit_None) {
 
       nsSize ratio(aFrame->GetIntrinsicRatio());
       nscoord ratioISize = (horizontalAxis ? ratio.width  : ratio.height);
@@ -5561,46 +5594,68 @@ nsLayoutUtils::MinSizeContributionForAxi
   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
   printf_stderr(" %s min-isize for %s WM:\n",
                 aType == MIN_ISIZE ? "min" : "pref",
                 aWM.IsVertical() ? "vertical" : "horizontal");
 #endif
 
   // Note: this method is only meant for grid/flex items.
   const nsStylePosition* const stylePos = aFrame->StylePosition();
-  const nsStyleCoord* style = aAxis == eAxisHorizontal ? &stylePos->mMinWidth
-                                                       : &stylePos->mMinHeight;
+  nsStyleCoord size = aAxis == eAxisHorizontal ? stylePos->mMinWidth
+                                               : stylePos->mMinHeight;
+  nsStyleCoord maxSize = aAxis == eAxisHorizontal ? stylePos->mMaxWidth
+                                                  : stylePos->mMaxHeight;
+  auto childWM = aFrame->GetWritingMode();
+  PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline);
+  // According to the spec, max-content and min-content should behave as the
+  // property's initial values in block axis.
+  // It also make senses to use the initial values for -moz-fit-content and
+  // -moz-available for intrinsic size in block axis. Therefore, we reset them
+  // if needed.
+  if (aAxis != ourInlineAxis) {
+    if (size.GetUnit() == eStyleUnit_Enumerated) {
+      size.SetAutoValue();
+    }
+    if (maxSize.GetUnit() == eStyleUnit_Enumerated) {
+      maxSize.SetNoneValue();
+    }
+  }
+
   nscoord minSize;
   nscoord* fixedMinSize = nullptr;
-  auto minSizeUnit = style->GetUnit();
+  auto minSizeUnit = size.GetUnit();
   if (minSizeUnit == eStyleUnit_Auto) {
     if (aFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE) {
-      style = aAxis == eAxisHorizontal ? &stylePos->mWidth
-                                       : &stylePos->mHeight;
-      if (GetAbsoluteCoord(*style, minSize)) {
+      size = aAxis == eAxisHorizontal ? stylePos->mWidth
+                                      : stylePos->mHeight;
+      // This is same as above: keywords should behaves as property's initial
+      // values in block axis.
+      if (aAxis != ourInlineAxis && size.GetUnit() == eStyleUnit_Enumerated) {
+        size.SetAutoValue();
+      }
+
+      if (GetAbsoluteCoord(size, minSize)) {
         // We have a definite width/height.  This is the "specified size" in:
         // https://drafts.csswg.org/css-grid/#min-size-auto
         fixedMinSize = &minSize;
-      } else if (::IsReplacedBoxResolvedAgainstZero(aFrame, *style,
-                     aAxis == eAxisHorizontal ? stylePos->mMaxWidth
-                                              : stylePos->mMaxHeight)) {
+      } else if (::IsReplacedBoxResolvedAgainstZero(aFrame, size, maxSize)) {
         // XXX bug 1463700: this doesn't handle calc() according to spec
         minSize = 0;
         fixedMinSize = &minSize;
       }
       // fall through - the caller will have to deal with "transferred size"
     } else {
       // min-[width|height]:auto with overflow != visible computes to zero.
       minSize = 0;
       fixedMinSize = &minSize;
     }
-  } else if (GetAbsoluteCoord(*style, minSize)) {
+  } else if (GetAbsoluteCoord(size, minSize)) {
     fixedMinSize = &minSize;
   } else if (minSizeUnit != eStyleUnit_Enumerated) {
-    MOZ_ASSERT(style->HasPercent());
+    MOZ_ASSERT(size.HasPercent());
     minSize = 0;
     fixedMinSize = &minSize;
   }
 
   if (!fixedMinSize) {
     // Let the caller deal with the "content size" cases.
 #ifdef DEBUG_INTRINSIC_WIDTH
     nsFrame::IndentBy(stderr, gNoiseIndent);
@@ -5612,33 +5667,29 @@ nsLayoutUtils::MinSizeContributionForAxi
   }
 
   // If aFrame is a container for font size inflation, then shrink
   // wrapping inside of it should not apply font size inflation.
   AutoMaybeDisableFontInflation an(aFrame);
 
   // The padding/margin percentage basis is the inline-size in the parent's
   // writing-mode.
-  auto childWM = aFrame->GetWritingMode();
   nscoord pmPercentageBasis =
     aFrame->GetParent()->GetWritingMode().IsOrthogonalTo(childWM) ?
       aPercentageBasis.BSize(childWM) :
       aPercentageBasis.ISize(childWM);
-  PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline);
   nsIFrame::IntrinsicISizeOffsetData offsets =
     ourInlineAxis == aAxis ? aFrame->IntrinsicISizeOffsets(pmPercentageBasis)
                            : aFrame->IntrinsicBSizeOffsets(pmPercentageBasis);
   nscoord result = 0;
   nscoord min = 0;
-  const nsStyleCoord& maxISize =
-    aAxis == eAxisHorizontal ? stylePos->mMaxWidth : stylePos->mMaxHeight;
   result = AddIntrinsicSizeOffset(aRC, aFrame, offsets, aType,
                                   stylePos->mBoxSizing,
-                                  result, min, *style, fixedMinSize,
-                                  *style, nullptr, maxISize, aFlags, aAxis);
+                                  result, min, size, fixedMinSize,
+                                  size, nullptr, maxSize, aFlags, aAxis);
 
 #ifdef DEBUG_INTRINSIC_WIDTH
   nsFrame::IndentBy(stderr, gNoiseIndent);
   static_cast<nsFrame*>(aFrame)->ListTag(stderr);
   printf_stderr(" %s min-isize is %d twips.\n",
          aType == MIN_ISIZE ? "min" : "pref", result);
 #endif
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1519,22 +1519,16 @@ public:
                "caller must deal with %% of unconstrained block-size");
     MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
 
     nscoord result = aCoord.ComputeCoordPercentCalc(aContainingBlockBSize);
     // Clamp calc(), and the subtraction for box-sizing.
     return std::max(0, result - aContentEdgeToBoxSizingBoxEdge);
   }
 
-  // XXX to be removed
-  static bool IsAutoHeight(const nsStyleCoord &aCoord, nscoord aCBHeight)
-  {
-    return IsAutoBSize(aCoord, aCBHeight);
-  }
-
   static bool IsAutoBSize(const nsStyleCoord &aCoord, nscoord aCBBSize)
   {
     nsStyleUnit unit = aCoord.GetUnit();
     return unit == eStyleUnit_Auto ||  // only for 'height'
            unit == eStyleUnit_None ||  // only for 'max-height'
            // The enumerated values were originally aimed at inline-size
            // (or width, as it was before logicalization). For now, let them
            // return true here, so that we don't call ComputeBSizeValue with
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -437,18 +437,17 @@ ReflowInput::Init(nsPresContext*     aPr
         parent->StyleDisplay()->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN)) {
     mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
   } else if (type == LayoutFrameType::SVGForeignObject) {
     // An SVG foreignObject frame is inherently constrained block-size.
     mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
   } else {
     const nsStyleCoord& bSizeCoord = mStylePosition->BSize(mWritingMode);
     const nsStyleCoord& maxBSizeCoord = mStylePosition->MaxBSize(mWritingMode);
-    if ((bSizeCoord.GetUnit() != eStyleUnit_Auto ||
-         maxBSizeCoord.GetUnit() != eStyleUnit_None) &&
+    if ((!bSizeCoord.IsAutoOrEnum() || !maxBSizeCoord.IsAutoOrEnum()) &&
          // Don't set NS_FRAME_IN_CONSTRAINED_BSIZE on body or html elements.
          (mFrame->GetContent() &&
         !(mFrame->GetContent()->IsAnyOfHTMLElements(nsGkAtoms::body,
                                                    nsGkAtoms::html)))) {
 
       // If our block-size was specified as a percentage, then this could
       // actually resolve to 'auto', based on:
       // http://www.w3.org/TR/CSS21/visudet.html#the-height-property
@@ -1563,18 +1562,17 @@ ReflowInput::CalculateHypotheticalPositi
     // values.
     nscoord insideBoxSizing, outsideBoxSizing;
     CalculateBorderPaddingMargin(eLogicalAxisBlock,
                                  blockContentSize.BSize(wm),
                                  &insideBoxSizing, &outsideBoxSizing);
 
     nscoord boxBSize;
     nsStyleCoord styleBSize = mStylePosition->BSize(wm);
-    bool isAutoBSize = styleBSize.GetUnit() == eStyleUnit_Auto;
-    if (isAutoBSize) {
+    if (styleBSize.IsAutoOrEnum()) {
       if (NS_FRAME_IS_REPLACED(mFrameType) && knowIntrinsicSize) {
         // It's a replaced element with an 'auto' block size so the box
         // block size is its intrinsic size plus any border/padding/margin
         boxBSize = LogicalSize(wm, intrinsicSize).BSize(wm) +
                    outsideBoxSizing + insideBoxSizing;
       } else {
         // XXX Bug 1191801
         // Figure out how to get the correct boxBSize here (need to reflow the
@@ -1884,17 +1882,17 @@ ReflowInput::InitAbsoluteConstraints(nsP
         // above, where the spec says to ignore
         // 'margin-left'/'margin-right'.
         // Ignore the specified value for 'right'.
         offsets.IEnd(cbwm) += availMarginSpace;
       }
     }
   }
 
-  bool bSizeIsAuto = eStyleUnit_Auto == mStylePosition->BSize(cbwm).GetUnit();
+  bool bSizeIsAuto = mStylePosition->BSize(cbwm).IsAutoOrEnum();
   if (bStartIsAuto) {
     // solve for block-start
     if (bSizeIsAuto) {
       offsets.BStart(cbwm) = NS_AUTOOFFSET;
     } else {
       offsets.BStart(cbwm) = cbSize.BSize(cbwm) - margin.BStartEnd(cbwm) -
         borderPadding.BStartEnd(cbwm) - computedSize.BSize(cbwm) -
         offsets.BEnd(cbwm);
@@ -2278,17 +2276,19 @@ ReflowInput::InitConstraints(nsPresConte
     // For calculating positioning offsets, margins, borders and
     // padding, we use the writing mode of the containing block
     WritingMode cbwm = cbri->GetWritingMode();
     InitOffsets(cbwm, cbSize.ConvertTo(cbwm, wm).ISize(cbwm),
                 aFrameType, mFlags, aBorder, aPadding, mStyleDisplay);
 
     // For calculating the size of this box, we use its own writing mode
     const nsStyleCoord &blockSize = mStylePosition->BSize(wm);
-    nsStyleUnit blockSizeUnit = blockSize.GetUnit();
+    nsStyleUnit blockSizeUnit = blockSize.IsAutoOrEnum()
+                                ? eStyleUnit_Auto
+                                : blockSize.GetUnit();
 
     // Check for a percentage based block size and a containing block
     // block size that depends on the content block size
     // XXX twiddling blockSizeUnit doesn't help anymore
     // FIXME Shouldn't we fix that?
     if (blockSize.HasPercent()) {
       if (NS_AUTOHEIGHT == cbSize.BSize(wm)) {
         // this if clause enables %-blockSize on replaced inline frames,
@@ -3016,17 +3016,17 @@ SizeComputationInput::ComputePadding(Wri
                               stylePadding->mPadding.GetBEnd(aWM)));
 
     SetComputedLogicalPadding(aWM, p);
   }
   return isCBDependent;
 }
 
 void
-ReflowInput::ComputeMinMaxValues(const LogicalSize&aCBSize)
+ReflowInput::ComputeMinMaxValues(const LogicalSize& aCBSize)
 {
   WritingMode wm = GetWritingMode();
 
   const nsStyleCoord& minISize = mStylePosition->MinISize(wm);
   const nsStyleCoord& maxISize = mStylePosition->MaxISize(wm);
   const nsStyleCoord& minBSize = mStylePosition->MinBSize(wm);
   const nsStyleCoord& maxBSize = mStylePosition->MaxBSize(wm);
 
@@ -3052,59 +3052,47 @@ ReflowInput::ComputeMinMaxValues(const L
 
   // If the computed value of 'min-width' is greater than the value of
   // 'max-width', 'max-width' is set to the value of 'min-width'
   if (ComputedMinISize() > ComputedMaxISize()) {
     ComputedMaxISize() = ComputedMinISize();
   }
 
   // Check for percentage based values and a containing block height that
-  // depends on the content height. Treat them like 'auto'
+  // depends on the content height. Treat them like the initial value.
   // Likewise, check for calc() with percentages on internal table elements;
-  // that's treated as 'auto' too.
+  // that's treated as the initial value too.
   // Likewise, if we're a child of a flex container who's measuring our
-  // intrinsic height, then we want to disregard our min-height.
+  // intrinsic height, then we want to disregard our min-height/max-height.
+  const nscoord& bPercentageBasis = aCBSize.BSize(wm);
+  auto BSizeBehavesAsInitialValue = [&](const nsStyleCoord& aBSize) {
+    return nsLayoutUtils::IsAutoBSize(aBSize, bPercentageBasis) ||
+             (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
+              aBSize.IsCalcUnit() && aBSize.CalcHasPercent()) ||
+             mFlags.mIsFlexContainerMeasuringBSize;
+  };
 
   // NOTE: min-height:auto resolves to 0, except on a flex item. (But
   // even there, it's supposed to be ignored (i.e. treated as 0) until
   // the flex container explicitly resolves & considers it.)
-  if (eStyleUnit_Auto == minBSize.GetUnit() ||
-      (NS_AUTOHEIGHT == aCBSize.BSize(wm) &&
-       minBSize.HasPercent()) ||
-      (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
-       minBSize.IsCalcUnit() && minBSize.CalcHasPercent()) ||
-      mFlags.mIsFlexContainerMeasuringBSize) {
+  if (BSizeBehavesAsInitialValue(minBSize)) {
     ComputedMinBSize() = 0;
   } else {
-    ComputedMinBSize() = ComputeBSizeValue(aCBSize.BSize(wm),
+    ComputedMinBSize() = ComputeBSizeValue(bPercentageBasis,
                                            mStylePosition->mBoxSizing,
                                            minBSize);
   }
-  nsStyleUnit maxBSizeUnit = maxBSize.GetUnit();
-  if (eStyleUnit_None == maxBSizeUnit) {
+
+  if (BSizeBehavesAsInitialValue(maxBSize)) {
     // Specified value of 'none'
     ComputedMaxBSize() = NS_UNCONSTRAINEDSIZE;  // no limit
   } else {
-    // Check for percentage based values and a containing block height that
-    // depends on the content height. Treat them like 'none'
-    // Likewise, check for calc() with percentages on internal table elements;
-    // that's treated as 'auto' too.
-    // Likewise, if we're a child of a flex container who's measuring our
-    // intrinsic height, then we want to disregard our max-height.
-    if ((NS_AUTOHEIGHT == aCBSize.BSize(wm) &&
-         maxBSize.HasPercent()) ||
-        (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
-         maxBSize.IsCalcUnit() && maxBSize.CalcHasPercent()) ||
-        mFlags.mIsFlexContainerMeasuringBSize) {
-      ComputedMaxBSize() = NS_UNCONSTRAINEDSIZE;
-    } else {
-      ComputedMaxBSize() = ComputeBSizeValue(aCBSize.BSize(wm),
-                                             mStylePosition->mBoxSizing,
-                                             maxBSize);
-    }
+    ComputedMaxBSize() = ComputeBSizeValue(bPercentageBasis,
+                                           mStylePosition->mBoxSizing,
+                                           maxBSize);
   }
 
   // If the computed value of 'min-height' is greater than the value of
   // 'max-height', 'max-height' is set to the value of 'min-height'
   if (ComputedMinBSize() > ComputedMaxBSize()) {
     ComputedMaxBSize() = ComputedMinBSize();
   }
 }
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -5703,17 +5703,17 @@ nsFrame::ComputeSize(gfxContext*        
   // in the initial ComputeAutoSize() call.)
   if (!(aFlags & nsIFrame::eUseAutoBSize)) {
     if (!nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM))) {
       result.BSize(aWM) =
         nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
                                          boxSizingAdjust.BSize(aWM),
                                          *blockStyleCoord);
     } else if (MOZ_UNLIKELY(isGridItem) &&
-               blockStyleCoord->GetUnit() == eStyleUnit_Auto &&
+               blockStyleCoord->IsAutoOrEnum() &&
                !IS_TRUE_OVERFLOW_CONTAINER(this)) {
       auto cbSize = aCBSize.BSize(aWM);
       if (cbSize != NS_AUTOHEIGHT) {
         // 'auto' block-size for grid-level box - fill the CB for 'stretch' /
         // 'normal' and clamp it to the CB if requested:
         bool stretch = false;
         if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
           auto blockAxisAlignment =
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -607,31 +607,45 @@ struct nsGridContainerFrame::GridItemInf
   // Return true if we should apply Automatic Minimum Size to this item.
   // https://drafts.csswg.org/css-grid/#min-size-auto
   // @note the caller should also check that the item spans at least one track
   // that has a min track sizing function that is 'auto' before applying it.
   bool ShouldApplyAutoMinSize(WritingMode aContainerWM,
                               LogicalAxis aContainerAxis,
                               nscoord aPercentageBasis) const
   {
+    const bool isInlineAxis = aContainerAxis == eLogicalAxisInline;
     const auto* pos = mFrame->IsTableWrapperFrame() ?
       mFrame->PrincipalChildList().FirstChild()->StylePosition() :
       mFrame->StylePosition();
-    const auto& size = aContainerAxis == eLogicalAxisInline ?
+    const auto& size = isInlineAxis ?
       pos->ISize(aContainerWM) : pos->BSize(aContainerWM);
+    // max-content and min-content should behave as initial value in block axis.
+    // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
+    // for block size dimension on sizing properties (e.g. height), so we
+    // treat it as `auto`.
+    bool isAuto = size.GetUnit() == eStyleUnit_Auto ||
+      (isInlineAxis == aContainerWM.IsOrthogonalTo(mFrame->GetWritingMode()) &&
+       size.GetUnit() == eStyleUnit_Enumerated);
     // NOTE: if we have a definite size then our automatic minimum size
     // can't affect our size.  Excluding these simplifies applying
     // the clamping in the right cases later.
-    if (size.GetUnit() != eStyleUnit_Auto &&
-        !::IsPercentOfIndefiniteSize(size, aPercentageBasis)) {
+    if (!isAuto && !::IsPercentOfIndefiniteSize(size, aPercentageBasis)) {
       return false;
     }
-    const auto& minSize = aContainerAxis == eLogicalAxisInline ?
+    const auto& minSize = isInlineAxis ?
       pos->MinISize(aContainerWM) : pos->MinBSize(aContainerWM);
-    return minSize.GetUnit() == eStyleUnit_Auto &&
+    // max-content and min-content should behave as initial value in block axis.
+    // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
+    // for block size dimension on sizing properties (e.g. height), so we
+    // treat it as `auto`.
+    isAuto = minSize.GetUnit() == eStyleUnit_Auto ||
+      (isInlineAxis == aContainerWM.IsOrthogonalTo(mFrame->GetWritingMode()) &&
+       minSize.GetUnit() == eStyleUnit_Enumerated);
+    return isAuto &&
            mFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE;
   }
 
 #ifdef DEBUG
   void Dump() const;
 #endif
 
   static bool IsStartRowLessThan(const GridItemInfo* a, const GridItemInfo* b)
@@ -3763,18 +3777,28 @@ MinSize(const GridItemInfo&    aGridItem
         CachedIntrinsicSizes*  aCache)
 {
   if (aCache->mMinSize.isSome()) {
     return aCache->mMinSize.value();
   }
   nsIFrame* child = aGridItem.mFrame;
   PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
   const nsStylePosition* stylePos = child->StylePosition();
-  const nsStyleCoord& sizeStyle =
+  nsStyleCoord sizeStyle =
     axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
+
+  auto ourInlineAxis = child->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
+  // max-content and min-content should behave as initial value in block axis.
+  // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
+  // for block size dimension on sizing properties (e.g. height), so we
+  // treat it as `auto`.
+  if (axis != ourInlineAxis && sizeStyle.GetUnit() == eStyleUnit_Enumerated) {
+    sizeStyle.SetAutoValue();
+  }
+
   if (sizeStyle.GetUnit() != eStyleUnit_Auto && !sizeStyle.HasPercent()) {
     nscoord s =
       MinContentContribution(aGridItem, aState, aRC, aCBWM, aAxis, aCache);
     aCache->mMinSize.emplace(s);
     return s;
   }
 
   if (aCache->mPercentageBasis.isNothing()) {
@@ -3793,17 +3817,23 @@ MinSize(const GridItemInfo&    aGridItem
              aGridItem.mBaselineOffset[aAxis] == nscoord(0),
              "baseline offset should be zero when not baseline-aligned");
   nscoord sz = aGridItem.mBaselineOffset[aAxis] +
     nsLayoutUtils::MinSizeContributionForAxis(axis, aRC, child,
                                               nsLayoutUtils::MIN_ISIZE,
                                               *aCache->mPercentageBasis);
   const nsStyleCoord& style = axis == eAxisHorizontal ? stylePos->mMinWidth
                                                       : stylePos->mMinHeight;
-  auto unit = style.GetUnit();
+  // max-content and min-content should behave as initial value in block axis.
+  // FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
+  // for block size dimension on sizing properties (e.g. height), so we
+  // treat it as `auto`.
+  auto unit = axis != ourInlineAxis && style.GetUnit() == eStyleUnit_Enumerated
+    ? eStyleUnit_Auto
+    : style.GetUnit();
   if (unit == eStyleUnit_Enumerated ||
       (unit == eStyleUnit_Auto &&
        child->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)) {
     // Now calculate the "content size" part and return whichever is smaller.
     MOZ_ASSERT(unit != eStyleUnit_Enumerated || sz == NS_UNCONSTRAINEDSIZE);
     sz = std::min(sz, ContentContribution(aGridItem, aState, aRC, aCBWM, aAxis,
                                           aCache->mPercentageBasis,
                                           nsLayoutUtils::MIN_ISIZE,
@@ -5124,17 +5154,17 @@ nsGridContainerFrame::ReflowInFlowChild(
   }
 
   // If the child is stretching in its block axis, and we might be fragmenting
   // it in that axis, then setup a frame property to tell
   // nsBlockFrame::ComputeFinalSize the size.
   if (isConstrainedBSize && !wm.IsOrthogonalTo(childWM)) {
     bool stretch = false;
     if (!childRI.mStyleMargin->HasBlockAxisAuto(childWM) &&
-        childRI.mStylePosition->BSize(childWM).GetUnit() == eStyleUnit_Auto) {
+        childRI.mStylePosition->BSize(childWM).IsAutoOrEnum()) {
       auto blockAxisAlignment =
         childRI.mStylePosition->UsedAlignSelf(Style());
       if (blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
           blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
         stretch = true;
       }
     }
     if (stretch) {
--- a/layout/style/nsStyleCoord.h
+++ b/layout/style/nsStyleCoord.h
@@ -144,16 +144,26 @@ public:
   bool           operator==(const nsStyleCoord& aOther) const;
   bool           operator!=(const nsStyleCoord& aOther) const;
 
   nsStyleUnit GetUnit() const {
     NS_ASSERTION(mUnit != eStyleUnit_Null, "reading uninitialized value");
     return mUnit;
   }
 
+  // This is especially useful to check if it is the property's initial value
+  // or keyword for sizing properties.
+  bool IsAutoOrEnum() const {
+    // The initial value of width/height and min-width/min-height is `auto`.
+    // The initial value of max-width/max-height is `none`.
+    return mUnit == eStyleUnit_Auto ||
+           mUnit == eStyleUnit_None ||
+           mUnit == eStyleUnit_Enumerated;
+  }
+
   bool IsAngleValue() const {
     return eStyleUnit_Degree == mUnit;
   }
 
   static bool IsCalcUnit(nsStyleUnit aUnit) {
     return aUnit == eStyleUnit_Calc;
   }
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -3726,24 +3726,21 @@ var gCSSProperties = {
                     "710", "1000" ],
     invalid_values: [ "0", "1001", "calc(10%)" ]
   },
   "height": {
     domProp: "height",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     /* FIXME: test zero, and test calc clamping */
-    initial_values: [ " auto",
-      // these four keywords compute to the initial value when the
-      // writing mode is horizontal, and that's the context we're testing in
-      "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
-    ],
+    initial_values: [ " auto" ],
     /* computed value tests for height test more with display:block */
     prerequisites: { "display": "block" },
     other_values: [ "15px", "3em", "15%",
+      "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
       "calc(2px)",
       "calc(50%)",
       "calc(3*25px)",
       "calc(25px*3)",
       "calc(3*25px + 50%)",
     ],
     invalid_values: [ "none" ],
     quirks_values: { "5": "5px" },
@@ -3984,22 +3981,19 @@ var gCSSProperties = {
     invalid_values: [ ],
     quirks_values: { "5": "5px" },
   },
   "max-height": {
     domProp: "maxHeight",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     prerequisites: { "display": "block" },
-    initial_values: [ "none",
-      // these four keywords compute to the initial value when the
-      // writing mode is horizontal, and that's the context we're testing in
+    initial_values: [ "none" ],
+    other_values: [ "30px", "50%", "0",
       "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
-    ],
-    other_values: [ "30px", "50%", "0",
       "calc(2px)",
       "calc(-2px)",
       "calc(0px)",
       "calc(50%)",
       "calc(3*25px)",
       "calc(25px*3)",
       "calc(3*25px + 50%)",
     ],
@@ -4028,22 +4022,19 @@ var gCSSProperties = {
     invalid_values: [ "auto" ],
     quirks_values: { "5": "5px" },
   },
   "min-height": {
     domProp: "minHeight",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     prerequisites: { "display": "block" },
-    initial_values: [ "auto", "0", "calc(0em)", "calc(-2px)",
-      // these four keywords compute to the initial value when the
-      // writing mode is horizontal, and that's the context we're testing in
+    initial_values: [ "auto", "0", "calc(0em)", "calc(-2px)" ],
+    other_values: [ "30px", "50%",
       "-moz-max-content", "-moz-min-content", "-moz-fit-content", "-moz-available",
-    ],
-    other_values: [ "30px", "50%",
       "calc(-1%)",
       "calc(2px)",
       "calc(50%)",
       "calc(3*25px)",
       "calc(25px*3)",
       "calc(3*25px + 50%)",
     ],
     invalid_values: ["none"],
--- a/layout/style/test/test_box_size_keywords.html
+++ b/layout/style/test/test_box_size_keywords.html
@@ -1,21 +1,19 @@
 <!DOCTYPE HTML>
 <html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=1122253
--->
 <head>
-  <title>Test for Bug 1122253</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <title>Test for keywords on box sizing properties</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script src="property_database.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1122253">Mozilla Bug 1122253</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1496558">Mozilla Bug 1496558</a>
 
 <style>
 #outer {
   position: absolute;
   width: 200px;
   height: 200px;
 }
 #horizontal, #vertical {
@@ -44,17 +42,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id=outer>
   <div id=horizontal><span class=small></span><span class=big></span><span class=big></span><span class=big></span></div>
   <div id=vertical><span class=small></span><span class=big></span><span class=big></span><span class=big></span></div>
 </div>
 
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
-/** Test for Bug 1122253 **/
+/** Test for Bug 1122253 and Bug 1496558 **/
 
 // Test that the -moz-available, -moz-min-content, -moz-max-content, and
 // -moz-fit-content keywords are usable only on width, when the writing
 // mode is horizontal, or height, when the writing mode is vertical,
 // and that they are always available on inline-size and never on
 // block-size.  When used on the wrong properties, they should be
 // equivalent to unset.
 //
@@ -112,52 +110,52 @@ var gTests = [
   { orientation: "vertical", prerequisites: "width: 30px; ", property: "width", specified_value: "-moz-available", computed_value: "20px", },
   { orientation: "vertical", prerequisites: "width: 30px; ", property: "width", specified_value: "-moz-min-content", computed_value: "20px", },
   { orientation: "vertical", prerequisites: "width: 30px; ", property: "width", specified_value: "-moz-max-content", computed_value: "20px", },
   { orientation: "vertical", prerequisites: "width: 30px; ", property: "width", specified_value: "-moz-fit-content", computed_value: "20px", },
   { orientation: "vertical", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
-  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-available", computed_value: "0px", },
-  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-min-content", computed_value: "0px", },
-  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-max-content", computed_value: "0px", },
-  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-fit-content", computed_value: "0px", },
+  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-available", computed_value: "-moz-available", },
+  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-min-content", computed_value: "-moz-min-content", },
+  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-max-content", computed_value: "-moz-max-content", },
+  { orientation: "vertical", prerequisites: "min-width: 30px; ", property: "min-width", specified_value: "-moz-fit-content", computed_value: "-moz-fit-content", },
   { orientation: "vertical", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
-  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-available", computed_value: "none", },
-  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-min-content", computed_value: "none", },
-  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-max-content", computed_value: "none", },
-  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-fit-content", computed_value: "none", },
+  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-available", computed_value: "-moz-available", },
+  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-min-content", computed_value: "-moz-min-content", },
+  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-max-content", computed_value: "-moz-max-content", },
+  { orientation: "vertical", prerequisites: "max-width: 30px; ", property: "max-width", specified_value: "-moz-fit-content", computed_value: "-moz-fit-content", },
   { orientation: "vertical", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "vertical", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "height: 30px; ", property: "height", specified_value: "-moz-available", computed_value: "20px", },
   { orientation: "horizontal", prerequisites: "height: 30px; ", property: "height", specified_value: "-moz-min-content", computed_value: "20px", },
   { orientation: "horizontal", prerequisites: "height: 30px; ", property: "height", specified_value: "-moz-max-content", computed_value: "20px", },
   { orientation: "horizontal", prerequisites: "height: 30px; ", property: "height", specified_value: "-moz-fit-content", computed_value: "20px", },
   { orientation: "horizontal", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "block-size: 30px; ", property: "block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
-  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-available", computed_value: "0px", },
-  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-min-content", computed_value: "0px", },
-  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-max-content", computed_value: "0px", },
-  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-fit-content", computed_value: "0px", },
+  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-available", computed_value: "-moz-available", },
+  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-min-content", computed_value: "-moz-min-content", },
+  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-max-content", computed_value: "-moz-max-content", },
+  { orientation: "horizontal", prerequisites: "min-height: 30px; ", property: "min-height", specified_value: "-moz-fit-content", computed_value: "-moz-fit-content", },
   { orientation: "horizontal", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "min-block-size: 30px; ", property: "min-block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
-  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-available", computed_value: "none", },
-  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-min-content", computed_value: "none", },
-  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-max-content", computed_value: "none", },
-  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-fit-content", computed_value: "none", },
+  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-available", computed_value: "-moz-available", },
+  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-min-content", computed_value: "-moz-min-content", },
+  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-max-content", computed_value: "-moz-max-content", },
+  { orientation: "horizontal", prerequisites: "max-height: 30px; ", property: "max-height", specified_value: "-moz-fit-content", computed_value: "-moz-fit-content", },
   { orientation: "horizontal", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-available", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-min-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-max-content", computed_value: "30px", },
   { orientation: "horizontal", prerequisites: "max-block-size: 30px; ", property: "max-block-size", specified_value: "-moz-fit-content", computed_value: "30px", },
 ];
 
 gTests.forEach(function(t) {
   var e = document.getElementById(t.orientation);
--- a/layout/style/test/test_value_computation.html
+++ b/layout/style/test/test_value_computation.html
@@ -91,16 +91,20 @@ function xfail_value(property, value, is
 
   return false;
 }
 
 var gSwapInitialWhenHaveFrame = {
   // When there's a frame, '-moz-available' works out to the same as
   // 'auto' given the prerequisites of only 'display: block'.
   "width": [ "-moz-available" ],
+  // When there's a frame, these keywords works out to the same as the initial
+  // value, i.e. `auto`, given the prerequisites of only 'display: block'.
+  "height": [ "-moz-max-content", "-moz-min-content", "-moz-fit-content",
+              "-moz-available" ],
 };
 
 function swap_when_frame(property, value) {
   return (property in gSwapInitialWhenHaveFrame) &&
          gSwapInitialWhenHaveFrame[property].includes(value);
 }
 
 var gDisplayTree = document.getElementById("display");
--- a/media/mtransport/SrtpFlow.cpp
+++ b/media/mtransport/SrtpFlow.cpp
@@ -48,17 +48,17 @@ RefPtr<SrtpFlow> SrtpFlow::Create(int ci
 
   if (!key) {
     MOZ_MTLOG(ML_ERROR, "Null SRTP key specified");
     return nullptr;
   }
 
   if ((key_len > SRTP_MAX_KEY_LENGTH) ||
       (key_len < SRTP_MIN_KEY_LENGTH)) {
-    MOZ_MTLOG(ML_ERROR, "Invalid SRTP key length");
+    MOZ_ASSERT(false, "Invalid SRTP key length");
     return nullptr;
   }
 
   srtp_policy_t policy;
   memset(&policy, 0, sizeof(srtp_policy_t));
 
   // Note that we set the same cipher suite for RTP and RTCP
   // since any flow can only have one cipher suite with DTLS-SRTP
--- a/media/mtransport/SrtpFlow.h
+++ b/media/mtransport/SrtpFlow.h
@@ -10,23 +10,27 @@
 #include "mozilla/RefPtr.h"
 #include "nsISupportsImpl.h"
 #include "srtp.h"
 
 namespace mozilla {
 
 #define SRTP_ICM_MASTER_KEY_LENGTH 16
 #define SRTP_ICM_MASTER_SALT_LENGTH 14
-#define SRTP_ICM_MAX_MASTER_LEGNTH (SRTP_ICM_MASTER_KEY_LENGTH + SRTP_ICM_MASTER_SALT_LENGTH)
-#define SRTP_GCM_MASTER_KEY_LENGTH 32
+#define SRTP_ICM_MAX_MASTER_LENGTH (SRTP_ICM_MASTER_KEY_LENGTH + SRTP_ICM_MASTER_SALT_LENGTH)
+
+#define SRTP_GCM_MASTER_KEY_MIN_LENGTH 16
+#define SRTP_GCM_MASTER_KEY_MAX_LENGTH 32
 #define SRTP_GCM_MASTER_SALT_LENGTH 12
-#define SRTP_GCM_MAX_MASTER_LEGNTH (SRTP_GCM_MASTER_KEY_LENGTH + SRTP_GCM_MASTER_SALT_LENGTH)
 
-#define SRTP_MIN_KEY_LENGTH SRTP_ICM_MAX_MASTER_LEGNTH 
-#define SRTP_MAX_KEY_LENGTH SRTP_GCM_MAX_MASTER_LEGNTH 
+#define SRTP_GCM_MIN_MASTER_LENGTH (SRTP_GCM_MASTER_KEY_MIN_LENGTH + SRTP_GCM_MASTER_SALT_LENGTH)
+#define SRTP_GCM_MAX_MASTER_LENGTH (SRTP_GCM_MASTER_KEY_MAX_LENGTH + SRTP_GCM_MASTER_SALT_LENGTH)
+
+#define SRTP_MIN_KEY_LENGTH SRTP_GCM_MIN_MASTER_LENGTH 
+#define SRTP_MAX_KEY_LENGTH SRTP_GCM_MAX_MASTER_LENGTH 
 
 // SRTCP requires an auth tag *plus* a 4-byte index-plus-'E'-bit value (see
 // RFC 3711)
 #define SRTP_MAX_EXPANSION (SRTP_MAX_TRAILER_LEN+4)
 
 
 class SrtpFlow {
   ~SrtpFlow();
--- a/media/mtransport/test/transport_unittests.cpp
+++ b/media/mtransport/test/transport_unittests.cpp
@@ -530,23 +530,17 @@ class TransportTestPeer : public sigslot
 
       ASSERT_TRUE(NS_SUCCEEDED(res));
 
       mask <<= 1;
     }
   }
 
   void SetupSrtp() {
-    // this mimics the setup we do elsewhere
-    std::vector<uint16_t> srtp_ciphers;
-    srtp_ciphers.push_back(kDtlsSrtpAeadAes256Gcm);
-    srtp_ciphers.push_back(kDtlsSrtpAeadAes128Gcm);
-    srtp_ciphers.push_back(kDtlsSrtpAes128CmHmacSha1_80);
-    srtp_ciphers.push_back(kDtlsSrtpAes128CmHmacSha1_32);
-
+    std::vector<uint16_t> srtp_ciphers = TransportLayerDtls::GetDefaultSrtpCiphers();
     SetSrtpCiphers(srtp_ciphers);
  }
 
   void SetSrtpCiphers(std::vector<uint16_t>& srtp_ciphers) {
     ASSERT_TRUE(NS_SUCCEEDED(dtls_->SetSrtpCiphers(srtp_ciphers)));
   }
 
   void ConnectSocket_s(TransportTestPeer *peer) {
@@ -975,17 +969,16 @@ class TransportTest : public MtransportT
   }
 
   PRFileDesc *fds_[2];
   TransportTestPeer *p1_;
   TransportTestPeer *p2_;
   nsCOMPtr<nsIEventTarget> target_;
 };
 
-
 TEST_F(TransportTest, TestNoDtlsVerificationSettings) {
   ConnectSocketExpectFail();
 }
 
 static void DisableChaCha(TransportTestPeer* peer) {
   // On ARM, ChaCha20Poly1305 might be preferred; disable it for the tests that
   // want to check the cipher suite.  It doesn't matter which peer disables the
   // suite, disabling on either side has the same effect.
@@ -1010,18 +1003,18 @@ TEST_F(TransportTest, TestConnect) {
 TEST_F(TransportTest, TestConnectSrtp) {
   SetupSrtp();
   SetDtlsPeer();
   DisableChaCha(p2_);
   ConnectSocket();
 
   ASSERT_EQ(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, p1_->cipherSuite());
 
-  // SRTP is on
-  ASSERT_EQ(kDtlsSrtpAeadAes256Gcm, p1_->srtpCipher());
+  // SRTP is on with default value
+  ASSERT_EQ(kDtlsSrtpAeadAes128Gcm, p1_->srtpCipher());
 }
 
 
 TEST_F(TransportTest, TestConnectDestroyFlowsMainThread) {
   SetDtlsPeer();
   ConnectSocket();
   DestroyPeerFlows();
 }
@@ -1403,30 +1396,39 @@ TEST_F(TransportTest, OnlyClientSendsSrt
   SetDtlsPeer();
   // This means that the server won't semd the extension as well.  The server
   // (p1) thinks that everything is OK.  The client (p2) notices the problem
   // after connecting and aborts.
   ConnectSocketExpectState(TransportLayer::TS_CLOSED,
                            TransportLayer::TS_ERROR);
 }
 
-TEST_F(TransportTest, TestSrtpFallback) {
-  std::vector<uint16_t> setA;
-  setA.push_back(kDtlsSrtpAeadAes256Gcm);
-  setA.push_back(kDtlsSrtpAes128CmHmacSha1_80);
+class TransportSrtpParameterTest : public TransportTest,
+                                   public ::testing::WithParamInterface<uint16_t> {
+};
+
+INSTANTIATE_TEST_CASE_P(SrtpParamInit,
+                        TransportSrtpParameterTest,
+                        ::testing::ValuesIn(TransportLayerDtls::GetDefaultSrtpCiphers()));
+
+TEST_P(TransportSrtpParameterTest, TestSrtpCiphersMismatchCombinations) {
+  uint16_t cipher = GetParam();
+  std::cerr << "Checking cipher: " << cipher << std::endl;
+
+  p1_->SetupSrtp();
+
   std::vector<uint16_t> setB;
-  setB.push_back(kDtlsSrtpAes128CmHmacSha1_80);
+  setB.push_back(cipher);
 
-  p1_->SetSrtpCiphers(setA);
   p2_->SetSrtpCiphers(setB);
   SetDtlsPeer();
   ConnectSocket();
 
-  ASSERT_EQ(kDtlsSrtpAes128CmHmacSha1_80, p1_->srtpCipher());
-  ASSERT_EQ(kDtlsSrtpAes128CmHmacSha1_80, p1_->srtpCipher());
+  ASSERT_EQ(cipher, p1_->srtpCipher());
+  ASSERT_EQ(cipher, p2_->srtpCipher());
 }
 
 // NSS doesn't support DHE suites on the server end.
 // This checks to see if we barf when that's the only option available.
 TEST_F(TransportTest, TestDheOnlyFails) {
   SetDtlsPeer();
 
   // p2_ is the client
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -804,16 +804,29 @@ nsresult TransportLayerDtls::GetCipherSu
   if (rv != SECSuccess) {
     MOZ_MTLOG(ML_NOTICE, LAYER_INFO << "GetCipherSuite can't get channel info");
     return NS_ERROR_FAILURE;
   }
   *cipherSuite = info.cipherSuite;
   return NS_OK;
 }
 
+std::vector<uint16_t> TransportLayerDtls::GetDefaultSrtpCiphers() {
+  std::vector<uint16_t> ciphers;
+
+  ciphers.push_back(kDtlsSrtpAeadAes128Gcm);
+  // Since we don't support DTLS 1.3 or SHA384 ciphers (see bug 1312976)
+  // we don't really enough entropy to prefer this over 128 bit
+  ciphers.push_back(kDtlsSrtpAeadAes256Gcm);
+  ciphers.push_back(kDtlsSrtpAes128CmHmacSha1_80);
+  ciphers.push_back(kDtlsSrtpAes128CmHmacSha1_32);
+
+  return ciphers;
+}
+
 void TransportLayerDtls::StateChange(TransportLayer *layer, State state) {
   if (state <= state_) {
     MOZ_MTLOG(ML_ERROR, "Lower layer state is going backwards from ours");
     TL_SET_STATE(TS_ERROR);
     return;
   }
 
   switch (state) {
--- a/media/mtransport/transportlayerdtls.h
+++ b/media/mtransport/transportlayerdtls.h
@@ -82,16 +82,17 @@ class TransportLayerDtls final : public 
   nsresult SetVerificationDigest(const std::string digest_algorithm,
                                  const unsigned char *digest_value,
                                  size_t digest_len);
 
   nsresult GetCipherSuite(uint16_t* cipherSuite) const;
 
   nsresult SetSrtpCiphers(const std::vector<uint16_t>& ciphers);
   nsresult GetSrtpCipher(uint16_t *cipher) const;
+  static std::vector<uint16_t> GetDefaultSrtpCiphers();
 
   nsresult ExportKeyingMaterial(const std::string& label,
                                 bool use_context,
                                 const std::string& context,
                                 unsigned char *out,
                                 unsigned int outlen);
 
   // Transport layer overrides.
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -733,21 +733,17 @@ PeerConnectionMedia::UpdateTransportFlow
     rv = dtls->SetVerificationDigest(ss.str(), &fingerprint.fingerprint[0],
                                      fingerprint.fingerprint.size());
     if (NS_FAILED(rv)) {
       CSFLogError(LOGTAG, "Could not set fingerprint");
       return rv;
     }
   }
 
-  std::vector<uint16_t> srtpCiphers;
-  srtpCiphers.push_back(kDtlsSrtpAeadAes256Gcm);
-  srtpCiphers.push_back(kDtlsSrtpAeadAes128Gcm);
-  srtpCiphers.push_back(kDtlsSrtpAes128CmHmacSha1_80);
-  srtpCiphers.push_back(kDtlsSrtpAes128CmHmacSha1_32);
+  std::vector<uint16_t> srtpCiphers = TransportLayerDtls::GetDefaultSrtpCiphers();
 
   rv = dtls->SetSrtpCiphers(srtpCiphers);
   if (NS_FAILED(rv)) {
     CSFLogError(LOGTAG, "Couldn't set SRTP ciphers");
     return rv;
   }
 
   // Always permits negotiation of the confidential mode.
--- a/mobile/android/app/src/main/res/layout/datetime_picker.xml
+++ b/mobile/android/app/src/main/res/layout/datetime_picker.xml
@@ -117,16 +117,34 @@
             android:layout_width="60dip"
             android:layout_height="wrap_content"
             android:layout_marginLeft="1dip"
             android:layout_marginRight="1dip"
             android:focusable="true"
             android:focusableInTouchMode="true"
             />
 
+        <TextView android:id="@+id/seccolon"
+            android:text="@string/colon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="1dip"
+            android:layout_marginRight="1dip"/>
+
+        <!-- Second -->
+        <android.widget.NumberPicker
+            android:id="@+id/second"
+            android:layout_width="60dip"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="1dip"
+            android:layout_marginRight="1dip"
+            android:focusable="true"
+            android:focusableInTouchMode="true"
+            />
+
         <!-- AMPM -->
         <android.widget.NumberPicker
             android:id="@+id/ampm"
             android:layout_width="60dip"
             android:layout_height="wrap_content"
             android:layout_marginLeft="1dip"
             android:layout_marginRight="1dip"
             android:focusable="true"
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -1033,16 +1033,18 @@ public class BrowserApp extends GeckoApp
 
         for (BrowserAppDelegate delegate : delegates) {
             delegate.onResume(this);
         }
     }
 
     @Override
     public void onPause() {
+        dismissTabHistoryFragment();
+
         super.onPause();
         if (mIsAbortingAppLaunch) {
             return;
         }
 
         if (mHasResumed) {
             // Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
             getAppEventDispatcher().registerUiThreadListener(this, "Prompt:ShowTop");
@@ -3113,20 +3115,17 @@ public class BrowserApp extends GeckoApp
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu aMenu) {
         if (aMenu == null)
             return false;
 
         // Hide the tab history panel when hardware menu button is pressed.
-        TabHistoryFragment frag = (TabHistoryFragment) getSupportFragmentManager().findFragmentByTag(TAB_HISTORY_FRAGMENT_TAG);
-        if (frag != null) {
-            frag.dismiss();
-        }
+        dismissTabHistoryFragment();
 
         if (!GeckoThread.isRunning()) {
             aMenu.findItem(R.id.settings).setEnabled(false);
             aMenu.findItem(R.id.help).setEnabled(false);
         }
 
         Tab tab = Tabs.getInstance().getSelectedTab();
         // Unlike other menu items, the bookmark star is not tinted. See {@link ThemedImageButton#setTintedDrawable}.
@@ -4135,9 +4134,16 @@ public class BrowserApp extends GeckoApp
     }
 
     @Override
     public void onFinishedOnboarding(final boolean showBrowserHint) {
         if (showBrowserHint && !Tabs.hasHomepage(this)) {
             enterEditingMode();
         }
     }
+
+    private void dismissTabHistoryFragment() {
+        TabHistoryFragment frag = (TabHistoryFragment) getSupportFragmentManager().findFragmentByTag(TAB_HISTORY_FRAGMENT_TAG);
+        if (frag != null) {
+            frag.dismiss();
+        }
+    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/PromptInput.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/PromptInput.java
@@ -41,16 +41,17 @@ import android.widget.TimePicker;
 
 public abstract class PromptInput {
     protected final String mLabel;
     protected final String mType;
     protected final String mId;
     protected String mValue;
     protected final String mMinValue;
     protected final String mMaxValue;
+    protected final boolean mSecondEnabled;
     protected OnChangeListener mListener;
     protected View mView;
     public static final String LOGTAG = "GeckoPromptInput";
 
     public interface OnChangeListener {
         void onChange(PromptInput input);
     }
 
@@ -172,17 +173,16 @@ public abstract class PromptInput {
     }
 
     public static class DateTimeInput extends PromptInput {
         public static final String[] INPUT_TYPES = new String[] {
             "date",
             "week",
             "time",
             "datetime-local",
-            "datetime",
             "month"
         };
 
         public DateTimeInput(GeckoBundle obj) {
             super(obj);
         }
 
         // Will use platform's DatePicker and TimePicker to let users input date and time using the fancy widgets.
@@ -213,57 +213,92 @@ public abstract class PromptInput {
                     input.setCalendarViewShown(false);
                 }
 
                 mView = (View)input;
             } else if (mType.equals("week")) {
                 DateTimePicker input = new DateTimePicker(context, "yyyy-'W'ww", mValue,
                                                           DateTimePicker.PickersState.WEEK, mMinValue, mMaxValue);
                 mView = (View)input;
+            } else if (mType.equals("time") && mSecondEnabled) {
+                // When seconds are requested, use DateTimePicker since FocusableDatePicker does not support seconds.
+                DateTimePicker input = new DateTimePicker(context, "HH:mm:ss",
+                                                          formatDateTimeSeconds(mValue),
+                                                          DateTimePicker.PickersState.TIME,
+                                                          formatDateTimeSeconds(mMinValue),
+                                                          formatDateTimeSeconds(mMaxValue));
+                mView = (View)input;
             } else if (mType.equals("time")) {
                 // FocusableDatePicker allow us to have priority in responding to scroll events.
                 TimePicker input = new FocusableTimePicker(context);
                 input.setIs24HourView(DateFormat.is24HourFormat(context));
 
                 GregorianCalendar calendar = new GregorianCalendar();
                 if (!TextUtils.isEmpty(mValue)) {
                     try {
                         calendar.setTime(new SimpleDateFormat("HH:mm").parse(mValue));
                     } catch (Exception e) { }
                 }
                 input.setCurrentHour(calendar.get(GregorianCalendar.HOUR_OF_DAY));
                 input.setCurrentMinute(calendar.get(GregorianCalendar.MINUTE));
                 mView = (View)input;
-            } else if (mType.equals("datetime-local") || mType.equals("datetime")) {
-                DateTimePicker input = new DateTimePicker(context, "yyyy-MM-dd HH:mm", mValue.replace("T", " ").replace("Z", ""),
-                                                          DateTimePicker.PickersState.DATETIME,
-                                                          mMinValue.replace("T", " ").replace("Z", ""), mMaxValue.replace("T", " ").replace("Z", ""));
+            } else if (mType.equals("datetime-local")) {
+                DateTimePicker input = new DateTimePicker(context, "yyyy-MM-dd'T'HH:mm:ss",
+                                                          formatDateTimeSeconds(mValue),
+                                                          mSecondEnabled ? DateTimePicker.PickersState.DATETIME_WITH_SECOND : DateTimePicker.PickersState.DATETIME,
+                                                          formatDateTimeSeconds(mMinValue),
+                                                          formatDateTimeSeconds(mMaxValue));
                 mView = (View)input;
             } else if (mType.equals("month")) {
                 DateTimePicker input = new DateTimePicker(context, "yyyy-MM", mValue,
                                                           DateTimePicker.PickersState.MONTH, mMinValue, mMaxValue);
                 mView = (View)input;
             }
 
             // Make sure the widgets will not be chopped on smaller screens (Bug 1412517)
             LinearLayout.LayoutParams parentParams = new LinearLayout.LayoutParams(
                     ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
             parentParams.gravity = Gravity.CENTER;
             mView.setLayoutParams(parentParams);
 
             return mView;
         }
 
+        private static String formatDateTimeSeconds(String dateString) {
+            // Reformat the datetime value so that it can be parsed by
+            // SimpleDateFormat ending with "HH:mm:ss".
+
+            int i = dateString.indexOf(":"); // Separator in "HH:mm".
+            if (i == -1) {
+                // Unparseable input.
+                return dateString;
+            }
+
+            i = dateString.indexOf(":", i + 1); // Separator in "mm:ss".
+            if (i == -1) {
+                // Append seconds.
+                return dateString + ":00";
+            }
+
+            return dateString;
+        }
+
         private static String formatDateString(String dateFormat, Calendar calendar) {
             return new SimpleDateFormat(dateFormat).format(calendar.getTime());
         }
 
         @Override
         public Object getValue() {
             if (mType.equals("time")) {
+                if (mSecondEnabled) {
+                    DateTimePicker dp = (DateTimePicker) mView;
+                    GregorianCalendar calendar = new GregorianCalendar();
+                    calendar.setTimeInMillis(dp.getTimeInMillis());
+                    return formatDateString("HH:mm:ss", calendar);
+                }
                 TimePicker tp = (TimePicker)mView;
                 GregorianCalendar calendar =
                     new GregorianCalendar(0, 0, 0, tp.getCurrentHour(), tp.getCurrentMinute());
                 return formatDateString("HH:mm", calendar);
             } else if (mType.equals("date")) {
                 DatePicker dp = (DatePicker) mView;
                 GregorianCalendar calendar =
                         new GregorianCalendar(dp.getYear(), dp.getMonth(), dp.getDayOfMonth());
@@ -271,21 +306,20 @@ public abstract class PromptInput {
             }
             else {
                 DateTimePicker dp = (DateTimePicker) mView;
                 GregorianCalendar calendar = new GregorianCalendar();
                 calendar.setTimeInMillis(dp.getTimeInMillis());
                 if (mType.equals("week")) {
                     return formatDateString("yyyy-'W'ww", calendar);
                 } else if (mType.equals("datetime-local")) {
+                    if (mSecondEnabled) {
+                        return formatDateString("yyyy-MM-dd'T'HH:mm:ss", calendar);
+                    }
                     return formatDateString("yyyy-MM-dd'T'HH:mm", calendar);
-                } else if (mType.equals("datetime")) {
-                    calendar.set(GregorianCalendar.ZONE_OFFSET, 0);
-                    calendar.setTimeInMillis(dp.getTimeInMillis());
-                    return formatDateString("yyyy-MM-dd'T'HH:mm'Z'", calendar);
                 } else if (mType.equals("month")) {
                     return formatDateString("yyyy-MM", calendar);
                 }
             }
             return super.getValue();
         }
     }
 
@@ -370,16 +404,19 @@ public abstract class PromptInput {
     public PromptInput(GeckoBundle obj) {
         mLabel = obj.getString("label", "");
         mType = obj.getString("type", "");
         String id = obj.getString("id", "");
         mId = TextUtils.isEmpty(id) ? mType : id;
         mValue = obj.getString("value", "");
         mMaxValue = obj.getString("max", "");
         mMinValue = obj.getString("min", "");
+
+        long timeStepInMs = obj.getLong("step", 0);
+        mSecondEnabled = (timeStepInMs % 60000) != 0;
     }
 
     public void saveCurrentInput(@NonNull final GeckoBundle userInput) {
         if (userInput.containsKey(mId)) {
             mValue = (String) userInput.get(mId);
         }
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/TabHistoryFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabHistoryFragment.java
@@ -100,59 +100,61 @@ public class TabHistoryFragment extends 
         // Since the fragment view fills the entire screen, any clicks outside of the history
         // ListView will end up here.
         dismiss();
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        dismiss();
+        onDismiss();
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
-        dismiss();
 
         GeckoApplication.watchReference(getActivity(), this);
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
         if (backStackId >= 0) {
             outState.putInt(BACK_STACK_ID, backStackId);
         }
     }
 
     // Function to add this fragment to activity state with containerViewId as parent.
     // This similar in functionality to DialogFragment.show() except that containerId is provided here.
     public void show(final int containerViewId, final FragmentTransaction transaction, final String tag) {
         dismissed = false;
-        transaction.add(containerViewId, this, tag);
+        transaction.replace(containerViewId, this, tag);
         transaction.addToBackStack(tag);
         // Populating the tab history requires a gecko call (which can be slow) - therefore the app
         // state by the time we try to show this fragment is unknown, and we could be in the
         // middle of shutting down:
         backStackId = transaction.commitAllowingStateLoss();
     }
 
     // Pop the fragment from backstack if it exists.
     public void dismiss() {
+        if (backStackId >= 0) {
+            getFragmentManager().popBackStackImmediate(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+            backStackId = -1;
+        }
+        onDismiss();
+    }
+
+    private void onDismiss() {
         if (dismissed) {
             return;
         }
 
         dismissed = true;
 
-        if (backStackId >= 0) {
-            getChildFragmentManager().popBackStackImmediate(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);
-            backStackId = -1;
-        }
-
         if (parent != null) {
             parent.setVisibility(View.GONE);
         }
     }
 
     private static class TabHistoryAdapter extends ArrayAdapter<TabHistoryPage> {
         private final List<TabHistoryPage> pages;
         private final Context context;
--- a/mobile/android/base/java/org/mozilla/gecko/widget/DateTimePicker.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/DateTimePicker.java
@@ -52,16 +52,17 @@ public class DateTimePicker extends Fram
     private static final char DATE_FORMAT_YEAR = 'y';
 
     boolean mYearEnabled = true;
     boolean mMonthEnabled = true;
     boolean mWeekEnabled;
     boolean mDayEnabled = true;
     boolean mHourEnabled = true;
     boolean mMinuteEnabled = true;
+    boolean mSecondEnabled = true;
     boolean mIs12HourMode;
     private boolean mCalendarEnabled;
 
     // Size of the screen in inches;
     private final int mScreenWidth;
     private final int mScreenHeight;
     private final OnValueChangeListener mOnChangeListener;
     private final LinearLayout mPickers;
@@ -69,37 +70,39 @@ public class DateTimePicker extends Fram
     private final LinearLayout mTimeSpinners;
 
     final NumberPicker mDaySpinner;
     final NumberPicker mMonthSpinner;
     final NumberPicker mWeekSpinner;
     final NumberPicker mYearSpinner;
     final NumberPicker mHourSpinner;
     final NumberPicker mMinuteSpinner;
+    final NumberPicker mSecondSpinner;
     final NumberPicker mAMPMSpinner;
     private final CalendarView mCalendar;
     private final EditText mDaySpinnerInput;
     private final EditText mMonthSpinnerInput;
     private final EditText mWeekSpinnerInput;
     private final EditText mYearSpinnerInput;
     private final EditText mHourSpinnerInput;
     private final EditText mMinuteSpinnerInput;
+    private final EditText mSecondSpinnerInput;
     private final EditText mAMPMSpinnerInput;
     private Locale mCurrentLocale;
     private String[] mShortMonths;
     private String[] mShortAMPMs;
     private int mNumberOfMonths;
 
     Calendar mTempDate;
     Calendar mCurrentDate;
     private Calendar mMinDate;
     private Calendar mMaxDate;
     private final PickersState mState;
 
-    public static enum PickersState { DATE, MONTH, WEEK, TIME, DATETIME };
+    public static enum PickersState { DATE, MONTH, WEEK, TIME, DATETIME, DATETIME_WITH_SECOND };
 
     public class OnValueChangeListener implements NumberPicker.OnValueChangeListener {
         @Override
         public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
             updateInputState();
             mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
             if (DEBUG) {
                 Log.d(LOGTAG, "SDK version > 10, using new behavior");
@@ -131,16 +134,18 @@ public class DateTimePicker extends Fram
             } else if (picker == mHourSpinner && mHourEnabled) {
                 if (mIs12HourMode) {
                     setTempDate(Calendar.HOUR, oldVal, newVal, 1, 12);
                 } else {
                     setTempDate(Calendar.HOUR_OF_DAY, oldVal, newVal, 0, 23);
                 }
             } else if (picker == mMinuteSpinner && mMinuteEnabled) {
                 setTempDate(Calendar.MINUTE, oldVal, newVal, 0, 59);
+            } else if (picker == mSecondSpinner && mSecondEnabled) {
+                setTempDate(Calendar.SECOND, oldVal, newVal, 0, 59);
             } else if (picker == mAMPMSpinner && mHourEnabled) {
                 mTempDate.set(Calendar.AM_PM, newVal);
             } else {
                 throw new IllegalArgumentException();
             }
             setDate(mTempDate);
             if (mDayEnabled) {
                 mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
@@ -179,21 +184,32 @@ public class DateTimePicker extends Fram
             return mFmt.toString();
         }
     };
 
     private void displayPickers() {
         setWeekShown(false);
         set12HourShown(mIs12HourMode);
         if (mState == PickersState.DATETIME) {
+            setSecondShown(false);
+            return;
+        }
+        if (mState == PickersState.DATETIME_WITH_SECOND) {
+            return;
+        }
+        if (mState == PickersState.TIME) {
+            setYearShown(false);
+            setMonthShown(false);
+            setDayShown(false);
             return;
         }
 
         setHourShown(false);
         setMinuteShown(false);
+        setSecondShown(false);
         if (mState == PickersState.WEEK) {
             setDayShown(false);
             setMonthShown(false);
             setWeekShown(true);
         } else if (mState == PickersState.MONTH) {
             setDayShown(false);
         }
     }
@@ -278,17 +294,17 @@ public class DateTimePicker extends Fram
         // a sensible default date here.
         if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) {
             mTempDate.setTimeInMillis(mMinDate.getTimeInMillis());
         }
 
         // If we're displaying a date, the screen is wide enough
         // (and if we're using an SDK where the calendar view exists)
         // then display a calendar.
-        if (mState == PickersState.DATE || mState == PickersState.DATETIME) {
+        if (mState == PickersState.DATE || mState == PickersState.DATETIME || mState == PickersState.DATETIME_WITH_SECOND) {
             mCalendar = new CalendarView(context);
             mCalendar.setVisibility(GONE);
 
             // Modify the time of mMaxDate and mMinDate to the end of the date and the beginning of the date. (Bug 1339884)
             mMaxDate.set(Calendar.HOUR, 23);
             mMaxDate.set(Calendar.MINUTE, 59);
             mMaxDate.set(Calendar.SECOND, 59);
             mMaxDate.set(Calendar.MILLISECOND, 999);
@@ -323,17 +339,17 @@ public class DateTimePicker extends Fram
             }
 
             mPickers.addView(mCalendar, LayoutParams.MATCH_PARENT, height);
 
         } else {
             // If the screen is more wide than high, we are displaying day and
             // time spinners, and if there is no calendar displayed, we should
             // display the fields in one row.
-            if (mScreenWidth > mScreenHeight && mState == PickersState.DATETIME) {
+            if (mScreenWidth > mScreenHeight && (mState == PickersState.DATETIME || mState == PickersState.DATETIME_WITH_SECOND)) {
                 mPickers.setOrientation(LinearLayout.HORIZONTAL);
             }
             mCalendar = null;
         }
 
         // Initialize all spinners.
         mDaySpinner = setupSpinner(R.id.day, 1,
                                    mTempDate.get(Calendar.DAY_OF_MONTH));
@@ -370,16 +386,20 @@ public class DateTimePicker extends Fram
 
         mHourSpinner.setFormatter(TWO_DIGIT_FORMATTER);
         mHourSpinnerInput = (EditText) mHourSpinner.getChildAt(1);
 
         mMinuteSpinner = setupSpinner(R.id.minute, 0, 59);
         mMinuteSpinner.setFormatter(TWO_DIGIT_FORMATTER);
         mMinuteSpinnerInput = (EditText) mMinuteSpinner.getChildAt(1);
 
+        mSecondSpinner = setupSpinner(R.id.second, 0, 59);
+        mSecondSpinner.setFormatter(TWO_DIGIT_FORMATTER);
+        mSecondSpinnerInput = (EditText) mSecondSpinner.getChildAt(1);
+
         // The order in which the spinners are displayed are locale-dependent
         reorderDateSpinners();
 
         // Set the date to the initial date. Since this date can come from the user,
         // it can fire an exception (out-of-bound date)
         try {
           updateDate(mTempDate);
         } catch (Exception ex) {
@@ -448,16 +468,19 @@ public class DateTimePicker extends Fram
             mDaySpinnerInput.clearFocus();
             inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
         } else if (mHourEnabled && inputMethodManager.isActive(mHourSpinnerInput)) {
             mHourSpinnerInput.clearFocus();
             inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
         } else if (mMinuteEnabled && inputMethodManager.isActive(mMinuteSpinnerInput)) {
             mMinuteSpinnerInput.clearFocus();
             inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
+        } else if (mSecondEnabled && inputMethodManager.isActive(mSecondSpinnerInput)) {
+            mSecondSpinnerInput.clearFocus();
+            inputMethodManager.hideSoftInputFromWindow(getWindowToken(), 0);
         }
     }
 
     void updateSpinners() {
         if (mDayEnabled) {
             if (mCurrentDate.equals(mMinDate)) {
                 mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
                 mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
@@ -509,30 +532,33 @@ public class DateTimePicker extends Fram
                 mAMPMSpinner.setDisplayedValues(mShortAMPMs);
             } else {
                 mHourSpinner.setValue(mCurrentDate.get(Calendar.HOUR_OF_DAY));
             }
         }
         if (mMinuteEnabled) {
             mMinuteSpinner.setValue(mCurrentDate.get(Calendar.MINUTE));
         }
+        if (mSecondEnabled) {
+            mSecondSpinner.setValue(mCurrentDate.get(Calendar.SECOND));
+        }
     }
 
     void updateCalendar() {
         if (mCalendarEnabled) {
             mCalendar.setDate(mCurrentDate.getTimeInMillis(), false, false);
         }
     }
 
     void notifyDateChanged() {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
     }
 
     public void toggleCalendar(boolean shown) {
-        if ((mState != PickersState.DATE && mState != PickersState.DATETIME)) {
+        if (mState != PickersState.DATE && mState != PickersState.DATETIME && mState != PickersState.DATETIME_WITH_SECOND && mState != PickersState.TIME) {
             return;
         }
 
         if (shown) {
             mCalendarEnabled = true;
             mCalendar.setVisibility(VISIBLE);
             setYearShown(false);
             setWeekShown(false);
@@ -619,16 +645,28 @@ public class DateTimePicker extends Fram
             mMinuteEnabled = true;
         } else {
             mMinuteSpinner.setVisibility(GONE);
             mTimeSpinners.findViewById(R.id.mincolon).setVisibility(GONE);
             mMinuteEnabled = false;
         }
     }
 
+    private void setSecondShown(boolean shown) {
+        if (shown) {
+            mSecondSpinner.setVisibility(VISIBLE);
+            mTimeSpinners.findViewById(R.id.seccolon).setVisibility(VISIBLE);
+            mSecondEnabled = true;
+        } else {
+            mSecondSpinner.setVisibility(GONE);
+            mTimeSpinners.findViewById(R.id.seccolon).setVisibility(GONE);
+            mSecondEnabled = false;
+        }
+    }
+
     private void setCurrentLocale(Locale locale) {
         if (locale.equals(mCurrentLocale)) {
             return;
         }
 
         mCurrentLocale = locale;
         mIs12HourMode = !DateFormat.is24HourFormat(getContext());
         mTempDate = getCalendarForLocale(mTempDate, locale);
--- a/mobile/android/components/BrowserCLH.js
+++ b/mobile/android/components/BrowserCLH.js
@@ -213,22 +213,21 @@ BrowserCLH.prototype = {
     aWindow.addEventListener("DOMAutoComplete", event => {
       if (shouldIgnoreLoginManagerEvent(event)) {
         return;
       }
       this.LoginManagerContent.onUsernameInput(event);
     }, options);
 
     aWindow.addEventListener("blur", event => {
-      if (shouldIgnoreLoginManagerEvent(event)) {
+      if (ChromeUtils.getClassName(event.target) !== "HTMLInputElement" ||
+          shouldIgnoreLoginManagerEvent(event)) {
         return;
       }
-      if (ChromeUtils.getClassName(event.target) === "HTMLInputElement") {
-        this.LoginManagerContent.onUsernameInput(event);
-      }
+      this.LoginManagerContent.onUsernameInput(event);
     }, options);
 
     aWindow.addEventListener("pageshow", event => {
       // XXXbz what about non-HTML documents??
       if (ChromeUtils.getClassName(event.target) == "HTMLDocument") {
         this.LoginManagerContent.onPageShow(event, event.target.defaultView.top);
       }
     }, options);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/SessionAccessibility.java
@@ -333,21 +333,27 @@ public class SessionAccessibility {
                             collectionItemBundle.getInt("columnIndex"),
                             collectionItemBundle.getInt("columnSpan"), false);
                     node.setCollectionItemInfo(collectionItemInfo);
                 }
 
                 // Set CollectionInfo
                 GeckoBundle collectionBundle = nodeInfo.getBundle("collectionInfo");
                 if (collectionBundle != null) {
-                    final CollectionInfo collectionInfo = CollectionInfo.obtain(
-                            collectionBundle.getInt("rowCount"),
-                            collectionBundle.getInt("columnCount"),
-                            collectionBundle.getBoolean("isHierarchical", false),
-                            collectionBundle.getInt("selectionMode", 0));
+                    // selectionMode is only supported in SDK >= 21.
+                    final CollectionInfo collectionInfo = Build.VERSION.SDK_INT >= 21
+                            ? CollectionInfo.obtain(
+                                collectionBundle.getInt("rowCount"),
+                                collectionBundle.getInt("columnCount"),
+                                collectionBundle.getBoolean("isHierarchical", false),
+                                collectionBundle.getInt("selectionMode", 0))
+                            : CollectionInfo.obtain(
+                                collectionBundle.getInt("rowCount"),
+                                collectionBundle.getInt("columnCount"),
+                                collectionBundle.getBoolean("isHierarchical", false));
                     node.setCollectionInfo(collectionInfo);
                 }
 
                 // Set inputType
                 switch (nodeInfo.getString("inputType", "").toLowerCase()) {
                     case "email":
                         node.setInputType(InputType.TYPE_CLASS_TEXT |
                                 InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS);
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -339,17 +339,16 @@ contextmenu.paste=Paste
 
 contextmenu.call=Call
 
 # Select UI
 selectHelper.closeMultipleSelectDialog=Done
 
 #Input widgets UI
 inputWidgetHelper.date=Pick a date
-inputWidgetHelper.datetime=Pick a date and a time
 inputWidgetHelper.datetime-local=Pick a date and a time
 inputWidgetHelper.time=Pick a time
 inputWidgetHelper.week=Pick a week
 inputWidgetHelper.month=Pick a month
 inputWidgetHelper.cancel=Cancel
 inputWidgetHelper.set=Set
 inputWidgetHelper.clear=Clear
 
--- a/mobile/android/modules/InputWidgetHelper.jsm
+++ b/mobile/android/modules/InputWidgetHelper.jsm
@@ -34,28 +34,29 @@ var InputWidgetHelper = {
       return;
 
     this._uiBusy = true;
     this.show(aTarget);
     this._uiBusy = false;
   },
 
   show: function(aElement) {
-    let type = aElement.getAttribute("type");
+    let type = aElement.type;
     new Prompt({
       window: aElement.ownerGlobal,
-      title: this.strings().GetStringFromName("inputWidgetHelper." + aElement.getAttribute("type")),
+      title: this.strings().GetStringFromName("inputWidgetHelper." + type),
       buttons: [
         this.strings().GetStringFromName("inputWidgetHelper.set"),
         this.strings().GetStringFromName("inputWidgetHelper.clear"),
         this.strings().GetStringFromName("inputWidgetHelper.cancel")
       ],
     }).addDatePicker({
       value: aElement.value,
       type: type,
+      step: this._getInputTimeStep(aElement),
       min: aElement.min,
       max: aElement.max,
     }).show(data => {
       let changed = false;
       if (data.button == -1) {
         // This type is not supported with this android version.
         return;
       }
@@ -79,18 +80,18 @@ var InputWidgetHelper = {
     });
   },
 
   hasInputWidget: function(aElement) {
     let win = aElement.ownerGlobal;
     if (!(aElement instanceof win.HTMLInputElement))
       return false;
 
-    let type = aElement.getAttribute("type");
-    if (type == "date" || type == "datetime" || type == "datetime-local" ||
+    let type = aElement.type;
+    if (type == "date" || type == "datetime-local" ||
         type == "week" || type == "month" || type == "time") {
       return true;
     }
 
     return false;
   },
 
   fireOnChange: function(aElement) {
@@ -105,10 +106,25 @@ var InputWidgetHelper = {
     let currentElement = aElement;
     while (currentElement) {
       if (currentElement.disabled)
         return true;
 
       currentElement = currentElement.parentElement;
     }
     return false;
+  },
+
+  // The step in milliseconds.
+  _getInputTimeStep: function(aElement) {
+    try {
+      // Delegate the implementation to HTMLInputElement::GetStep.
+      let tmpInput = aElement.ownerDocument.createElement("input");
+      tmpInput.type = aElement.type;
+      tmpInput.step = aElement.step;
+      // May throw if the type is unsupported.
+      tmpInput.stepUp();
+      return tmpInput.valueAsNumber || 0; // Prefer 0 over NaN.
+    } catch (e) {
+      return 0;
+    }
   }
 };
--- a/mobile/android/modules/Prompt.jsm
+++ b/mobile/android/modules/Prompt.jsm
@@ -125,16 +125,17 @@ Prompt.prototype = {
     });
   },
 
   addDatePicker: function(aOptions) {
     return this._addInput({
       type: aOptions.type || "date",
       value: aOptions.value,
       id: aOptions.id,
+      step: aOptions.step,
       max: aOptions.max,
       min: aOptions.min
     });
   },
 
   addColorPicker: function(aOptions) {
     return this._addInput({
       type: "color",
--- a/mobile/android/tests/browser/chrome/test_session_scroll_position.html
+++ b/mobile/android/tests/browser/chrome/test_session_scroll_position.html
@@ -38,23 +38,20 @@ https://bugzilla.mozilla.org/show_bug.cg
   // Test nested scrolling with frames.
   const URL_FRAMESET = BASE + "browser_scrollPositions_sample_frameset.html";
   // Reader mode URL
   const URL_reader = "about:reader?url=http%3A%2F%2Fexample.org%2Fchrome%2Fmobile%2Fandroid%2Ftests%2Fbrowser%2Fchrome%2Fbasic_article_mobile.html";
 
   // Randomized set of scroll positions and zoom factors we will use in this test.
   const SCROLL_X = Math.round(100 * (1 + Math.random()));
   const SCROLL_Y = Math.round(200 * (1 + Math.random()));
-  const SCROLL_STR = SCROLL_X + "," + SCROLL_Y;
-  const SCROLL_STR_Y_ONLY = 0 + "," + SCROLL_Y;
   const ZOOM = 1 + 0.5 * Math.random();
 
   const SCROLL2_X = Math.round(300 * (1 + Math.random()));
   const SCROLL2_Y = Math.round(400 * (1 + Math.random()));
-  const SCROLL2_STR = SCROLL2_X + "," + SCROLL2_Y;
   const ZOOM2 = 1.5 + 0.5 * Math.random();
 
   function getFrame(browser, data) {
     let frame = browser.contentWindow;
     if (data.hasOwnProperty("frame")) {
       frame = browser.contentWindow.frames[data.frame];
     }
     return frame;
@@ -85,16 +82,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     if (data.hasOwnProperty("y")) {
       is(actualY.value, y, "scrollY set correctly");
     }
     if (data.hasOwnProperty("zoom")) {
       ok(fuzzyEquals(actualZoom.value, zoom), "zoom set correctly");
     }
   }
 
+  function getScrollString(data) {
+    let {x, y} = data;
+    x = x || 0;
+    y = y || 0;
+    return x + "," + y;
+  }
+
   // Track the tabs where the tests are happening.
   let tabScroll;
 
   function cleanupTabs() {
     if (tabScroll) {
       BrowserApp.closeTab(tabScroll);
       tabScroll = null;
     }
@@ -127,17 +131,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         BrowserApp.closeTab(tabScroll);
         yield promiseTabEvent(browser, "SSTabCloseProcessed");
       });
     }
 
     await createAndRemoveReaderTab();
     let state = ss.getClosedTabs(chromeWin);
     let [{scrolldata}] = state;
-    is(scrolldata.scroll, SCROLL_STR_Y_ONLY, "stored scroll position is correct");
+    is(scrolldata.scroll, getScrollString(testData), "stored scroll position is correct");
 
     // Restore the closed tab.
     let closedTabData = ss.getClosedTabs(chromeWin)[0];
     let browser = ss.undoCloseTab(chromeWin, closedTabData);
     await promiseBrowserEvent(browser, "AboutReaderContentReady");
 
     // Check the scroll position.
     checkScroll(browser, testData);
@@ -177,17 +181,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         BrowserApp.closeTab(tabScroll);
         yield promiseTabEvent(browser, "SSTabCloseProcessed");
       });
     }
 
     await createAndRemoveTab();
     let state = ss.getClosedTabs(chromeWin);
     let [{scrolldata}] = state;
-    is(scrolldata.scroll, SCROLL2_STR, "stored scroll position is correct");
+    is(scrolldata.scroll, getScrollString(testData2), "stored scroll position is correct");
     ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM2), "stored zoom level is correct");
 
     // Restore the closed tab.
     let closedTabData = ss.getClosedTabs(chromeWin)[0];
     let browser = ss.undoCloseTab(chromeWin, closedTabData);
     let pageshow = promiseBrowserEvent(browser, "pageshow");
     let scroll = promiseBrowserEvent(browser, "scroll");
     await pageshow;
@@ -232,17 +236,17 @@ https://bugzilla.mozilla.org/show_bug.cg
         BrowserApp.closeTab(tabScroll);
         yield promiseTabEvent(browser, "SSTabCloseProcessed");
       });
     }
 
     await createAndRemoveTab();
     let state = ss.getClosedTabs(chromeWin);
     let [{scrolldata}] = state;
-    is(scrolldata.scroll, SCROLL_STR, "stored scroll position is correct");
+    is(scrolldata.scroll, getScrollString(testData), "stored scroll position is correct");
     ok(fuzzyEquals(scrolldata.zoom.resolution, ZOOM), "stored zoom level is correct");
 
     // Pretend the zoom level was originally saved on a rotated device.
     let closedTabData = ss.getClosedTabs(chromeWin)[0];
     let displayWidth = scrolldata.zoom.displaySize.width;
     let displayHeight = scrolldata.zoom.displaySize.height;
     closedTabData.scrolldata.zoom.displaySize.width = displayHeight;
     closedTabData.scrolldata.zoom.displaySize.height = displayWidth;
@@ -255,17 +259,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     testData.zoom = ZOOM * displayWidth / displayHeight;
     checkScroll(browser, testData);
 
     // Remove the tab.
     BrowserApp.closeTab(BrowserApp.getTabForBrowser(browser));
   });
 
   add_task(async function test_sessionStoreScrollPositionForFrames() {
-    let testDataParent = {x: 0, y: SCROLL_Y, zoom: 2.0};
+    let testDataParent = {x: 0, y: Math.round(SCROLL_Y / 2), zoom: 2.0};
     let testData1 = {x: SCROLL_X, y: SCROLL_Y, frame: 0};
     let testData2 = {x: SCROLL2_X, y: SCROLL2_Y, frame: 1};
     // Creates a tab, sets a scroll position and zoom level and closes the tab.
     function createAndRemoveTab() {
       return Task.spawn(function* () {
         // Create a new tab.
         tabScroll = BrowserApp.addTab(URL_FRAMESET);
         let browser = tabScroll.browser;
@@ -290,19 +294,19 @@ https://bugzilla.mozilla.org/show_bug.cg
         BrowserApp.closeTab(tabScroll);
         yield promiseTabEvent(browser, "SSTabCloseProcessed");
       });
     }
 
     await createAndRemoveTab();
     let state = ss.getClosedTabs(chromeWin);
     let [{scrolldata}] = state;
-    is(scrolldata.scroll, SCROLL_STR_Y_ONLY, "stored scroll position for frameset is correct");
-    is(scrolldata.children[0].scroll, SCROLL_STR, "stored scroll position for frame 1 is correct");
-    is(scrolldata.children[1].scroll, SCROLL2_STR, "stored scroll position for frame 2 is correct");
+    is(scrolldata.scroll, getScrollString(testDataParent), "stored scroll position for frameset is correct");
+    is(scrolldata.children[0].scroll, getScrollString(testData1), "stored scroll position for frame 1 is correct");
+    is(scrolldata.children[1].scroll, getScrollString(testData2), "stored scroll position for frame 2 is correct");
 
     // Restore the closed tab.
     let closedTabData = ss.getClosedTabs(chromeWin)[0];
     let browser = ss.undoCloseTab(chromeWin, closedTabData);
     let pageshow = promiseBrowserEvent(browser, "pageshow");
     // We can't add event listeners for the frames until we're sure that they've actually loaded.
     let load = promiseBrowserEvent(browser, "load");
     await load;
--- a/security/manager/ssl/OSKeyStore.cpp
+++ b/security/manager/ssl/OSKeyStore.cpp
@@ -230,17 +230,17 @@ OSKeyStore::GetIsNSSKeyStore(bool* aNSSK
   NS_ENSURE_STATE(mKs);
   *aNSSKeyStore = mKs->IsNSSKeyStore();
   return NS_OK;
 }
 
 // Async interfaces that return promises because the key store implementation
 // might block, e.g. asking for a password.
 
-static nsresult
+nsresult
 GetPromise(JSContext* aCx, /* out */ RefPtr<Promise>& aPromise)
 {
   nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx);
   if (NS_WARN_IF(!globalObject)) {
     return NS_ERROR_UNEXPECTED;
   }
   ErrorResult result;
   aPromise = Promise::Create(globalObject, result);
--- a/security/manager/ssl/OSKeyStore.h
+++ b/security/manager/ssl/OSKeyStore.h
@@ -63,16 +63,18 @@ private:
   const size_t mKeyByteLength = 16;
   const size_t mIVLength = 12;
 };
 
 #define NS_OSKEYSTORE_CONTRACTID "@mozilla.org/security/oskeystore;1"
 #define NS_OSKEYSTORE_CID \
   { 0x57972956, 0x5718, 0x42d2, { 0x80, 0x70, 0xb3, 0xfc, 0x72, 0x21, 0x2e, 0xaf } }
 
+nsresult GetPromise(JSContext* aCx, /* out */ RefPtr<mozilla::dom::Promise>& aPromise);
+
 class OSKeyStore : public nsIOSKeyStore
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOSKEYSTORE
 
   OSKeyStore();
   nsresult GenerateSecret(const nsACString& aLabel,
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/OSReauthenticator.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+
+#include "OSReauthenticator.h"
+
+#include "OSKeyStore.h"
+
+NS_IMPL_ISUPPORTS(OSReauthenticator, nsIOSReauthenticator)
+
+using namespace mozilla;
+using dom::Promise;
+
+static nsresult
+ReauthenticateUser(const nsACString& prompt, /* out */ bool& reauthenticated)
+{
+  reauthenticated = false;
+  return NS_OK;
+}
+
+static void
+BackgroundReauthenticateUser(RefPtr<Promise>& aPromise,
+                             const nsACString& aPrompt)
+{
+  nsAutoCString recovery;
+  bool reauthenticated;
+  nsresult rv = ReauthenticateUser(aPrompt, reauthenticated);
+  nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction(
+    "BackgroundReauthenticateUserResolve",
+    [rv, reauthenticated, aPromise = std::move(aPromise)]() {
+      if (NS_FAILED(rv)) {
+        aPromise->MaybeReject(rv);
+      } else {
+        aPromise->MaybeResolve(reauthenticated);
+      }
+    }));
+  NS_DispatchToMainThread(runnable.forget());
+}
+
+NS_IMETHODIMP
+OSReauthenticator::AsyncReauthenticateUser(const nsACString& aPrompt,
+                                           JSContext* aCx,
+                                           Promise** promiseOut)
+{
+  NS_ENSURE_ARG_POINTER(aCx);
+
+  RefPtr<Promise> promiseHandle;
+  nsresult rv = GetPromise(aCx, promiseHandle);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIRunnable> runnable(
+    NS_NewRunnableFunction("BackgroundReauthenticateUser",
+      [promiseHandle, aPrompt = nsAutoCString(aPrompt)]() mutable {
+        BackgroundReauthenticateUser(promiseHandle, aPrompt);
+      }
+    )
+  );
+
+  nsCOMPtr<nsIThread> thread;
+  rv = NS_NewNamedThread(NS_LITERAL_CSTRING("ReauthenticateUserThread"),
+                         getter_AddRefs(thread), runnable);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  promiseHandle.forget(promiseOut);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/OSReauthenticator.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+
+#ifndef OSReauthenticator_h
+#define OSReauthenticator_h
+
+#include "nsIOSReauthenticator.h"
+
+#define NS_OSREAUTHENTICATOR_CONTRACTID "@mozilla.org/security/osreauthenticator;1"
+#define NS_OSREAUTHENTICATOR_CID \
+  { 0x4fe082ae, 0x6ff0, 0x4b41, { 0xb2, 0x4f, 0xea, 0xa6, 0x64, 0xf6, 0xe4, 0x6a } }
+
+class OSReauthenticator : public nsIOSReauthenticator
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOSREAUTHENTICATOR
+
+private:
+  virtual ~OSReauthenticator() = default;
+};
+
+#endif // OSReauthenticator_h
--- a/security/manager/ssl/moz.build
+++ b/security/manager/ssl/moz.build
@@ -21,16 +21,17 @@ XPIDL_SOURCES += [
     'nsIGenKeypairInfoDlg.idl',
     'nsIKeygenThread.idl',
     'nsIKeyModule.idl',
     'nsILocalCertService.idl',
     'nsINSSComponent.idl',
     'nsINSSErrorsService.idl',
     'nsINSSVersion.idl',
     'nsIOSKeyStore.idl',
+    'nsIOSReauthenticator.idl',
     'nsIPK11Token.idl',
     'nsIPK11TokenDB.idl',
     'nsIPKCS11Module.idl',
     'nsIPKCS11ModuleDB.idl',
     'nsIPKCS11Slot.idl',
     'nsIProtectedAuthThread.idl',
     'nsISecretDecoderRing.idl',
     'nsISecurityUITelemetry.idl',
@@ -121,16 +122,17 @@ UNIFIED_SOURCES += [
     'nsSecureBrowserUIImpl.cpp',
     'nsSecurityHeaderParser.cpp',
     'NSSErrorsService.cpp',
     'nsSiteSecurityService.cpp',
     'NSSKeyStore.cpp',
     'nsSSLSocketProvider.cpp',
     'nsTLSSocketProvider.cpp',
     'OSKeyStore.cpp',
+    'OSReauthenticator.cpp',
     'PKCS11ModuleDB.cpp',
     'PSMContentListener.cpp',
     'PSMRunnable.cpp',
     'PublicKeyPinningService.cpp',
     'RootCertificateTelemetryUtils.cpp',
     'SecretDecoderRing.cpp',
     'SharedSSLState.cpp',
     'SSLServerCertVerification.cpp',
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/nsIOSReauthenticator.idl
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(4fe082ae-6ff0-4b41-b24f-eaa664f6e46a)]
+interface nsIOSReauthenticator: nsISupports {
+  /**
+   * This interface provides an abstract way to request that the user
+   * reauthenticate themselves to the operating system. It may be useful in
+   * conjunction with nsIOSKeyStore, whereby consumers of these APIs may
+   * consider some secrets too sensitive to access without first
+   * reauthenticating the user.
+   *
+   * Usage:
+   *
+   * // obtain the singleton nsIOSReauthenticator instance
+   * const reauthenticator = Cc["@mozilla.org/security/osreauthenticator;1"]
+   *                           .getService(Ci.nsIOSReauthenticator);
+   * if (await reauthenticator.asyncReauthenticate()) {
+   *   // do something only authenticated users are allowed to do...
+   * } else {
+   *   // show a "sorry, this isn't allowed" error
+   * }
+   */
+
+  /**
+   * Asynchronously cause the operating system to request that the user
+   * reauthenticate. This is typically in the form of a dialog box asking the
+   * user for their login password. The actual behaviour of this depends on the
+   * OS.
+   *
+   * @param prompt A short string that may be incorporated in the dialog
+   * @return Promise resolving to true if the user successfully authenticated
+   *         and false otherwise.
+   */
+  [implicit_jscontext, must_use]
+  Promise asyncReauthenticateUser(in ACString prompt);
+};
--- a/security/manager/ssl/nsNSSCertTrust.cpp
+++ b/security/manager/ssl/nsNSSCertTrust.cpp
@@ -1,14 +1,16 @@
 /* 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/. */
 
 #include "nsNSSCertTrust.h"
 
+#include "certdb.h"
+
 void
 nsNSSCertTrust::AddCATrust(bool ssl, bool email)
 {
   if (ssl) {
     addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CA);
     addTrust(&mTrust.sslFlags, CERTDB_TRUSTED_CLIENT_CA);
   }
   if (email) {
--- a/security/manager/ssl/nsNSSCertTrust.h
+++ b/security/manager/ssl/nsNSSCertTrust.h
@@ -1,16 +1,15 @@
 /* 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/. */
 
 #ifndef nsNSSCertTrust_h
 #define nsNSSCertTrust_h
 
-#include "certdb.h"
 #include "certt.h"
 
 /*
  * Class for maintaining trust flags for an NSS certificate.
  */
 class nsNSSCertTrust
 {
 public:
--- a/security/manager/ssl/nsNSSModule.cpp
+++ b/security/manager/ssl/nsNSSModule.cpp
@@ -29,16 +29,17 @@
 #include "nsPKCS11Slot.h"
 #include "nsRandomGenerator.h"
 #include "nsSSLSocketProvider.h"
 #include "nsSecureBrowserUIImpl.h"
 #include "nsSiteSecurityService.h"
 #include "nsTLSSocketProvider.h"
 #include "nsXULAppAPI.h"
 #include "OSKeyStore.h"
+#include "OSReauthenticator.h"
 
 #ifdef MOZ_XUL
 #include "nsCertTree.h"
 #endif
 
 namespace mozilla { namespace psm {
 
 // Many of the implementations in this module call NSS functions and as a result
@@ -155,16 +156,17 @@ NS_DEFINE_NAMED_CID(NS_CERTOVERRIDE_CID)
 NS_DEFINE_NAMED_CID(NS_RANDOMGENERATOR_CID);
 NS_DEFINE_NAMED_CID(TRANSPORTSECURITYINFO_CID);
 NS_DEFINE_NAMED_CID(NS_NSSERRORSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_NSSVERSION_CID);
 NS_DEFINE_NAMED_CID(NS_SECURE_BROWSER_UI_CID);
 NS_DEFINE_NAMED_CID(NS_SITE_SECURITY_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_CERT_BLOCKLIST_CID);
 NS_DEFINE_NAMED_CID(NS_OSKEYSTORE_CID);
+NS_DEFINE_NAMED_CID(NS_OSREAUTHENTICATOR_CID);
 
 // Components that require main thread initialization could cause a deadlock
 // in necko code (bug 1418752). To prevent it we initialize all such components
 // on main thread in advance in net_EnsurePSMInit(). Update that function when
 // new component with ThreadRestriction::MainThreadOnly is added.
 static const mozilla::Module::CIDEntry kNSSCIDs[] = {
   { &kNS_NSSCOMPONENT_CID, false, nullptr, nsNSSComponentConstructor },
   { &kNS_SSLSOCKETPROVIDER_CID, false, nullptr,
@@ -216,16 +218,20 @@ static const mozilla::Module::CIDEntry k
   { &kNS_CERT_BLOCKLIST_CID, false, nullptr,
     Constructor<CertBlocklist, &CertBlocklist::Init,
                 ProcessRestriction::ParentProcessOnly,
                 ThreadRestriction::MainThreadOnly> },
   { &kNS_OSKEYSTORE_CID, false, nullptr, Constructor<OSKeyStore,
                 nullptr,
                 ProcessRestriction::ParentProcessOnly,
                 ThreadRestriction::MainThreadOnly> },
+  { &kNS_OSREAUTHENTICATOR_CID, false, nullptr, Constructor<OSReauthenticator,
+                nullptr,
+                ProcessRestriction::ParentProcessOnly,
+                ThreadRestriction::MainThreadOnly> },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kNSSContracts[] = {
   { PSM_COMPONENT_CONTRACTID, &kNS_NSSCOMPONENT_CID },
   { NS_NSS_ERRORS_SERVICE_CONTRACTID, &kNS_NSSERRORSSERVICE_CID },
   { NS_NSSVERSION_CONTRACTID, &kNS_NSSVERSION_CID },
   { NS_SSLSOCKETPROVIDER_CONTRACTID, &kNS_SSLSOCKETPROVIDER_CID },
@@ -248,16 +254,17 @@ static const mozilla::Module::ContractID
   { NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &kNS_KEYMODULEOBJECTFACTORY_CID },
   { NS_CONTENTSIGNATUREVERIFIER_CONTRACTID, &kNS_CONTENTSIGNATUREVERIFIER_CID },
   { NS_CERTOVERRIDE_CONTRACTID, &kNS_CERTOVERRIDE_CID },
   { NS_RANDOMGENERATOR_CONTRACTID, &kNS_RANDOMGENERATOR_CID },
   { NS_SECURE_BROWSER_UI_CONTRACTID, &kNS_SECURE_BROWSER_UI_CID },
   { NS_SSSERVICE_CONTRACTID, &kNS_SITE_SECURITY_SERVICE_CID },
   { NS_CERTBLOCKLIST_CONTRACTID, &kNS_CERT_BLOCKLIST_CID },
   { NS_OSKEYSTORE_CONTRACTID, &kNS_OSKEYSTORE_CID},
+  { NS_OSREAUTHENTICATOR_CONTRACTID, &kNS_OSREAUTHENTICATOR_CID},
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kNSSCategories[] = {
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-ca-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-server-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-user-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
   { NS_CONTENT_LISTENER_CATEGORYMANAGER_ENTRY, "application/x-x509-email-cert", "@mozilla.org/uriloader/psm-external-content-listener;1" },
new file mode 100644
--- /dev/null
+++ b/security/manager/ssl/tests/unit/test_osreauthenticator.js
@@ -0,0 +1,16 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/publicdomain/zero/1.0/
+"use strict";
+
+// Tests nsIOSReauthenticator.asyncReauthenticateUser().
+// Currently this always resolves to false on all platforms. As this gets implemented on various
+// platforms, running this rest will result in a prompt from the OS. Consequently, we won't be able
+// to run this in automation, but it will help in testing locally.
+add_task(async function test_asyncReauthenticateUser() {
+  const reauthenticator = Cc["@mozilla.org/security/osreauthenticator;1"]
+                            .getService(Ci.nsIOSReauthenticator);
+  ok(reauthenticator, "nsIOSReauthenticator should be available");
+  ok(!await reauthenticator.asyncReauthenticateUser("this is the prompt string"),
+     "nsIOSReauthenticator.asyncReauthenticateUser always resolves to false for now");
+});
--- a/security/manager/ssl/tests/unit/xpcshell.ini
+++ b/security/manager/ssl/tests/unit/xpcshell.ini
@@ -136,16 +136,17 @@ run-sequentially = hardcoded ports
 run-sequentially = hardcoded ports
 [test_ocsp_stapling_with_intermediate.js]
 run-sequentially = hardcoded ports
 [test_ocsp_timeout.js]
 run-sequentially = hardcoded ports
 [test_ocsp_url.js]
 run-sequentially = hardcoded ports
 [test_oskeystore.js]
+[test_osreauthenticator.js]
 [test_password_prompt.js]
 [test_pinning.js]
 run-sequentially = hardcoded ports
 # This test can take longer than 300 seconds on B2G emulator debug builds, so
 # give it enough time to finish. See bug 1081128.
 requesttimeoutfactor = 2
 [test_pinning_dynamic.js]
 [test_pinning_header_parsing.js]
--- a/services/fxaccounts/FxAccountsComponents.manifest
+++ b/services/fxaccounts/FxAccountsComponents.manifest
@@ -1,4 +1,4 @@
 # FxAccountsPush.js
 component {1b7db999-2ecd-4abf-bb95-a726896798ca} FxAccountsPush.js process=main
-contract @mozilla.org/fxaccounts/push;1 {1b7db999-2ecd-4abf-bb95-a726896798ca}
+contract @mozilla.org/fxaccounts/push;1 {1b7db999-2ecd-4abf-bb95-a726896798ca} process=main
 category push chrome://fxa-device-update @mozilla.org/fxaccounts/push;1
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -14,24 +14,25 @@ use gecko_bindings::structs::{self, Coun
 use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
 use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
 use media_queries::Device;
 use nsstring::{nsACString, nsCStr};
 use std::cmp::max;
 use values::{Auto, Either, None_, Normal};
 use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
-use values::computed::{MaxLength, MozLength, Percentage};
+use values::computed::{MaxLength as ComputedMaxLength, MozLength as ComputedMozLength, Percentage};
 use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber};
 use values::computed::FlexBasis as ComputedFlexBasis;
 use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
 use values::generics::{CounterStyleOrNone, NonNegative};
 use values::generics::basic_shape::ShapeRadius;
 use values::generics::box_::Perspective;
 use values::generics::flex::FlexBasis;
+use values::generics::length::{MaxLength, MozLength};
 use values::generics::gecko::ScrollSnapPoint;
 use values::generics::grid::{TrackBreadth, TrackKeyword};
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
 pub trait GeckoStyleCoordConvertible: Sized {
     /// Convert this to a `nsStyleCoord`.
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T);
     /// Given a `nsStyleCoord`, try to get a value of this type..
@@ -69,17 +70,17 @@ impl GeckoStyleCoordConvertible for Comp
             FlexBasis::Content => coord.set_value(CoordDataValue::Enumerated(
                 structs::NS_STYLE_FLEX_BASIS_CONTENT,
             )),
             FlexBasis::Width(ref w) => w.to_gecko_style_coord(coord),
         }
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
-        if let Some(width) = MozLength::from_gecko_style_coord(coord) {
+        if let Some(width) = ComputedMozLength::from_gecko_style_coord(coord) {
             return Some(FlexBasis::Width(width));
         }
 
         if let CoordDataValue::Enumerated(structs::NS_STYLE_FLEX_BASIS_CONTENT) = coord.as_value() {
             return Some(FlexBasis::Content);
         }
 
         None
@@ -401,34 +402,34 @@ impl GeckoStyleCoordConvertible for Extr
             CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => {
                 Some(ExtremumLength::MozAvailable)
             },
             _ => None,
         }
     }
 }
 
-impl GeckoStyleCoordConvertible for MozLength {
+impl GeckoStyleCoordConvertible for ComputedMozLength {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         match *self {
             MozLength::LengthOrPercentageOrAuto(ref lopoa) => lopoa.to_gecko_style_coord(coord),
             MozLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
         }
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         LengthOrPercentageOrAuto::from_gecko_style_coord(coord)
             .map(MozLength::LengthOrPercentageOrAuto)
             .or_else(|| {
                 ExtremumLength::from_gecko_style_coord(coord).map(MozLength::ExtremumLength)
             })
     }
 }
 
-impl GeckoStyleCoordConvertible for MaxLength {
+impl GeckoStyleCoordConvertible for ComputedMaxLength {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         match *self {
             MaxLength::LengthOrPercentageOrNone(ref lopon) => lopon.to_gecko_style_coord(coord),
             MaxLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord),
         }
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -30,17 +30,17 @@ use super::ComputedValues;
 use values::CSSFloat;
 use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::animated::color::Color as AnimatedColor;
 use values::animated::effects::Filter as AnimatedFilter;
 #[cfg(feature = "gecko")] use values::computed::TransitionProperty;
 use values::computed::{Angle, CalcLengthOrPercentage};
 use values::computed::{ClipRect, Context};
 use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
-use values::computed::{LengthOrPercentageOrNone, MaxLength};
+use values::computed::LengthOrPercentageOrNone;
 use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
 use values::computed::length::NonNegativeLengthOrPercentage;
 use values::computed::ToComputedValue;
 use values::computed::transform::{DirectionVector, Matrix, Matrix3D};
 use values::computed::transform::TransformOperation as ComputedTransformOperation;
 use values::computed::transform::Transform as ComputedTransform;
 use values::computed::transform::Rotate as ComputedRotate;
 use values::computed::transform::Translate as ComputedTranslate;
@@ -883,21 +883,16 @@ impl ToAnimatedZero for LengthOrPercenta
             LengthOrPercentageOrNone::Calc(_) => {
                 Ok(LengthOrPercentageOrNone::Length(Length::new(0.)))
             },
             LengthOrPercentageOrNone::None => Err(()),
         }
     }
 }
 
-impl ToAnimatedZero for MaxLength {
-    #[inline]
-    fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
-}
-
 impl ToAnimatedZero for FontWeight {
     #[inline]
     fn to_animated_zero(&self) -> Result<Self, ()> {
         Ok(FontWeight::normal())
     }
 }
 
 /// <https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def>
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -287,28 +287,29 @@ impl ToAnimatedValue for ComputedMaxLeng
     #[inline]
     fn to_animated_value(self) -> Self {
         self
     }
 
     #[inline]
     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
         use values::computed::{Length, LengthOrPercentageOrNone, Percentage};
+        use values::generics::length::MaxLength as GenericMaxLength;
         match animated {
-            ComputedMaxLength::LengthOrPercentageOrNone(lopn) => {
+            GenericMaxLength::LengthOrPercentageOrNone(lopn) => {
                 let result = match lopn {
                     LengthOrPercentageOrNone::Length(px) => {
                         LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.)))
                     },
                     LengthOrPercentageOrNone::Percentage(percentage) => {
                         LengthOrPercentageOrNone::Percentage(Percentage(percentage.0.max(0.)))
                     },
                     _ => lopn,
                 };
-                ComputedMaxLength::LengthOrPercentageOrNone(result)
+                GenericMaxLength::LengthOrPercentageOrNone(result)
             },
             _ => animated,
         }
     }
 }
 
 impl ToAnimatedValue for ComputedMozLength {
     type AnimatedValue = Self;
@@ -316,28 +317,29 @@ impl ToAnimatedValue for ComputedMozLeng
     #[inline]
     fn to_animated_value(self) -> Self {
         self
     }
 
     #[inline]
     fn from_animated_value(animated: Self::AnimatedValue) -> Self {
         use values::computed::{Length, LengthOrPercentageOrAuto, Percentage};
+        use values::generics::length::MozLength as GenericMozLength;
         match animated {
-            ComputedMozLength::LengthOrPercentageOrAuto(lopa) => {
+            GenericMozLength::LengthOrPercentageOrAuto(lopa) => {
                 let result = match lopa {
                     LengthOrPercentageOrAuto::Length(px) => {
                         LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.)))
                     },
                     LengthOrPercentageOrAuto::Percentage(percentage) => {
                         LengthOrPercentageOrAuto::Percentage(Percentage(percentage.0.max(0.)))
                     },
                     _ => lopa,
                 };
-                ComputedMozLength::LengthOrPercentageOrAuto(result)
+                GenericMozLength::LengthOrPercentageOrAuto(result)
             },
             _ => animated,
         }
     }
 }
 
 impl ToAnimatedZero for Au {
     #[inline]
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -1,26 +1,25 @@
 /* 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/. */
 
 //! `<length>` computed values, and related ones.
 
 use app_units::Au;
-use logical_geometry::WritingMode;
 use ordered_float::NotNan;
-use properties::LonghandId;
 use std::fmt::{self, Write};
 use std::ops::{Add, Neg};
 use style_traits::{CssWriter, ToCss};
 use style_traits::values::specified::AllowedNumericType;
 use super::{Context, Number, Percentage, ToComputedValue};
 use values::{specified, Auto, CSSFloat, Either, Normal};
 use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
+use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength};
 use values::generics::NonNegative;
 use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength};
 use values::specified::length::ViewportPercentageLength;
 
 pub use super::image::Image;
 pub use values::specified::url::UrlOrNone;
 pub use values::specified::{Angle, BorderStyle, Time};
 
@@ -946,174 +945,38 @@ pub type NonNegativeLengthOrNormal = Eit
 
 /// Either a computed NonNegativeLengthOrPercentage or the `normal` keyword.
 pub type NonNegativeLengthOrPercentageOrNormal = Either<NonNegativeLengthOrPercentage, Normal>;
 
 /// A type for possible values for min- and max- flavors of width, height,
 /// block-size, and inline-size.
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)]
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo,
+         ToComputedValue, ToCss)]
 pub enum ExtremumLength {
     MozMaxContent,
     MozMinContent,
     MozFitContent,
     MozAvailable,
 }
 
-impl ExtremumLength {
-    /// Returns whether this size keyword can be used for the given writing-mode
-    /// and property.
-    ///
-    /// TODO: After these values are supported for both axes (and maybe
-    /// unprefixed, see bug 1322780) all this complexity can go away, and
-    /// everything can be derived (no need for uncacheable stuff).
-    fn valid_for(wm: WritingMode, longhand: LonghandId) -> bool {
-        // We only make sense on the inline axis.
-        match longhand {
-            // FIXME(emilio): The flex-basis thing is not quite clear...
-            LonghandId::FlexBasis |
-            LonghandId::MinWidth |
-            LonghandId::MaxWidth |
-            LonghandId::Width => !wm.is_vertical(),
-
-            LonghandId::MinHeight | LonghandId::MaxHeight | LonghandId::Height => wm.is_vertical(),
-
-            LonghandId::MinInlineSize | LonghandId::MaxInlineSize | LonghandId::InlineSize => true,
-            // The block-* properties are rejected at parse-time, so they're
-            // unexpected here.
-            _ => {
-                debug_assert!(
-                    false,
-                    "Unexpected property using ExtremumLength: {:?}",
-                    longhand,
-                );
-                false
-            },
-        }
-    }
-}
-
-/// A value suitable for a `min-width`, `min-height`, `width` or `height`
-/// property.
-///
-/// See values/specified/length.rs for more details.
-#[allow(missing_docs)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToAnimatedZero, ToCss)]
-pub enum MozLength {
-    LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
-    #[animation(error)]
-    ExtremumLength(ExtremumLength),
-}
+/// A computed value for `min-width`, `min-height`, `width` or `height` property.
+pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>;
 
 impl MozLength {
     /// Returns the `auto` value.
     #[inline]
     pub fn auto() -> Self {
-        MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto)
+        GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::Auto)
     }
 }
 
-impl ToComputedValue for specified::MozLength {
-    type ComputedValue = MozLength;
-
-    #[inline]
-    fn to_computed_value(&self, context: &Context) -> MozLength {
-        debug_assert!(
-            context.for_non_inherited_property.is_some(),
-            "Someone added a MozLength to an inherited property? Evil!"
-        );
-        match *self {
-            specified::MozLength::LengthOrPercentageOrAuto(ref lopoa) => {
-                MozLength::LengthOrPercentageOrAuto(lopoa.to_computed_value(context))
-            },
-            specified::MozLength::ExtremumLength(ext) => {
-                context
-                    .rule_cache_conditions
-                    .borrow_mut()
-                    .set_writing_mode_dependency(context.builder.writing_mode);
-                if !ExtremumLength::valid_for(
-                    context.builder.writing_mode,
-                    context.for_non_inherited_property.unwrap(),
-                ) {
-                    MozLength::auto()
-                } else {
-                    MozLength::ExtremumLength(ext)
-                }
-            },
-        }
-    }
-
-    #[inline]
-    fn from_computed_value(computed: &MozLength) -> Self {
-        match *computed {
-            MozLength::LengthOrPercentageOrAuto(ref lopoa) => {
-                specified::MozLength::LengthOrPercentageOrAuto(
-                    specified::LengthOrPercentageOrAuto::from_computed_value(lopoa),
-                )
-            },
-            MozLength::ExtremumLength(ext) => specified::MozLength::ExtremumLength(ext),
-        }
-    }
-}
-
-/// A value suitable for a `max-width` or `max-height` property.
-/// See values/specified/length.rs for more details.
-#[allow(missing_docs)]
-#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)]
-pub enum MaxLength {
-    LengthOrPercentageOrNone(LengthOrPercentageOrNone),
-    #[animation(error)]
-    ExtremumLength(ExtremumLength),
-}
+/// A computed value for `max-width` or `min-height` property.
+pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>;
 
 impl MaxLength {
     /// Returns the `none` value.
     #[inline]
     pub fn none() -> Self {
-        MaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None)
+        GenericMaxLength::LengthOrPercentageOrNone(LengthOrPercentageOrNone::None)
     }
 }
-
-impl ToComputedValue for specified::MaxLength {
-    type ComputedValue = MaxLength;
-
-    #[inline]
-    fn to_computed_value(&self, context: &Context) -> MaxLength {
-        debug_assert!(
-            context.for_non_inherited_property.is_some(),
-            "Someone added a MaxLength to an inherited property? Evil!"
-        );
-        match *self {
-            specified::MaxLength::LengthOrPercentageOrNone(ref lopon) => {
-                MaxLength::LengthOrPercentageOrNone(lopon.to_computed_value(context))
-            },
-            specified::MaxLength::ExtremumLength(ext) => {
-                context
-                    .rule_cache_conditions
-                    .borrow_mut()
-                    .set_writing_mode_dependency(context.builder.writing_mode);
-                if !ExtremumLength::valid_for(
-                    context.builder.writing_mode,
-                    context.for_non_inherited_property.unwrap(),
-                ) {
-                    MaxLength::none()
-                } else {
-                    MaxLength::ExtremumLength(ext)
-                }
-            },
-        }
-    }
-
-    #[inline]
-    fn from_computed_value(computed: &MaxLength) -> Self {
-        match *computed {
-            MaxLength::LengthOrPercentageOrNone(ref lopon) => {
-                specified::MaxLength::LengthOrPercentageOrNone(
-                    specified::LengthOrPercentageOrNone::from_computed_value(&lopon),
-                )
-            },
-            MaxLength::ExtremumLength(ref ext) => specified::MaxLength::ExtremumLength(ext.clone()),
-        }
-    }
-}
new file mode 100644
--- /dev/null
+++ b/servo/components/style/values/generics/length.rs
@@ -0,0 +1,54 @@
+/* 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/. */
+
+//! Generic types for CSS values related to length.
+
+use values::computed::ExtremumLength;
+
+/// A generic value for the `width`, `height`, `min-width`, or `min-height` property.
+///
+/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
+/// and cannot be `none`.
+///
+/// Note that it only accepts non-negative values.
+#[allow(missing_docs)]
+#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+#[derive(
+    Animate,
+    Clone,
+    ComputeSquaredDistance,
+    Copy,
+    Debug,
+    PartialEq,
+    SpecifiedValueInfo,
+    ToAnimatedZero,
+    ToComputedValue,
+    ToCss,
+)]
+pub enum MozLength<LengthOrPercentageOrAuto> {
+    LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
+    #[animation(error)]
+    ExtremumLength(ExtremumLength),
+}
+
+/// A generic value for the `max-width` or `max-height` property.
+#[allow(missing_docs)]
+#[cfg_attr(feature = "servo", derive(MallocSizeOf))]
+#[derive(
+    Animate,
+    Clone,
+    ComputeSquaredDistance,
+    Copy,
+    Debug,
+    PartialEq,
+    SpecifiedValueInfo,
+    ToAnimatedZero,
+    ToComputedValue,
+    ToCss
+)]
+pub enum MaxLength<LengthOrPercentageOrNone> {
+    LengthOrPercentageOrNone(LengthOrPercentageOrNone),
+    #[animation(error)]
+    ExtremumLength(ExtremumLength),
+}
--- a/servo/components/style/values/generics/mod.rs
+++ b/servo/components/style/values/generics/mod.rs
@@ -22,16 +22,17 @@ pub mod column;
 pub mod counters;
 pub mod effects;
 pub mod flex;
 pub mod font;
 #[cfg(feature = "gecko")]
 pub mod gecko;
 pub mod grid;
 pub mod image;
+pub mod length;
 pub mod position;
 pub mod rect;
 pub mod size;
 pub mod svg;
 pub mod text;
 pub mod transform;
 pub mod ui;
 pub mod url;
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -13,16 +13,17 @@ use font_metrics::FontMetricsQueryResult
 use parser::{Parse, ParserContext};
 use std::cmp;
 use std::ops::{Add, Mul};
 use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind};
 use style_traits::values::specified::AllowedNumericType;
 use super::{AllowQuirks, Number, Percentage, ToComputedValue};
 use values::{Auto, CSSFloat, Either, Normal};
 use values::computed::{self, CSSPixelLength, Context, ExtremumLength};
+use values::generics::length::{MaxLength as GenericMaxLength, MozLength as GenericMozLength};
 use values::generics::NonNegative;
 use values::specified::calc::CalcNode;
 
 pub use values::specified::calc::CalcLengthOrPercentage;
 pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
 pub use super::image::{GradientKind, Image};
 
 /// Number of app units per pixel
@@ -1183,28 +1184,18 @@ impl LengthOrNumber {
 
     /// Returns `0`.
     #[inline]
     pub fn zero() -> Self {
         Either::Second(Number::new(0.))
     }
 }
 
-/// A value suitable for a `min-width` or `min-height` property.
-///
-/// Unlike `max-width` or `max-height` properties, a MozLength can be `auto`,
-/// and cannot be `none`.
-///
-/// Note that it only accepts non-negative values.
-#[allow(missing_docs)]
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
-pub enum MozLength {
-    LengthOrPercentageOrAuto(LengthOrPercentageOrAuto),
-    ExtremumLength(ExtremumLength),
-}
+/// A specified value for `min-width`, `min-height`, `width` or `height` property.
+pub type MozLength = GenericMozLength<LengthOrPercentageOrAuto>;
 
 impl Parse for MozLength {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         MozLength::parse_quirky(context, input, AllowQuirks::No)
     }
@@ -1214,54 +1205,49 @@ impl MozLength {
     /// Parses, without quirks, and disallowing ExtremumLength values.
     ///
     /// Used for logical props in the block direction.
     pub fn parse_disallow_keyword<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let length = LengthOrPercentageOrAuto::parse_non_negative(context, input)?;
-        Ok(MozLength::LengthOrPercentageOrAuto(length))
+        Ok(GenericMozLength::LengthOrPercentageOrAuto(length))
     }
 
     /// Parses, with quirks.
     pub fn parse_quirky<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
         allow_quirks: AllowQuirks,
     ) -> Result<Self, ParseError<'i>> {
         if let Ok(l) = input.try(ExtremumLength::parse) {
-            return Ok(MozLength::ExtremumLength(l));
+            return Ok(GenericMozLength::ExtremumLength(l));
         }
 
         let length =
             LengthOrPercentageOrAuto::parse_non_negative_quirky(context, input, allow_quirks)?;
-        Ok(MozLength::LengthOrPercentageOrAuto(length))
+        Ok(GenericMozLength::LengthOrPercentageOrAuto(length))
     }
 
     /// Returns `auto`.
     #[inline]
     pub fn auto() -> Self {
-        MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto())
+        GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::auto())
     }
 
     /// Returns `0%`.
     #[inline]
     pub fn zero_percent() -> Self {
-        MozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent())
+        GenericMozLength::LengthOrPercentageOrAuto(LengthOrPercentageOrAuto::zero_percent())
     }
 }
 
-/// A value suitable for a `max-width` or `max-height` property.
-#[allow(missing_docs)]
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
-pub enum MaxLength {
-    LengthOrPercentageOrNone(LengthOrPercentageOrNone),
-    ExtremumLength(ExtremumLength),
-}
+/// A specified value for `max-width` or `max-height` property.
+pub type MaxLength = GenericMaxLength<LengthOrPercentageOrNone>;
 
 impl Parse for MaxLength {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         MaxLength::parse_quirky(context, input, AllowQuirks::No)
     }
@@ -1271,26 +1257,26 @@ impl MaxLength {
     /// Parses, without quirks, and disallowing ExtremumLength values.
     ///
     /// Used for logical props in the block direction.
     pub fn parse_disallow_keyword<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let length = LengthOrPercentageOrNone::parse_non_negative(context, input)?;
-        Ok(MaxLength::LengthOrPercentageOrNone(length))
+        Ok(GenericMaxLength::LengthOrPercentageOrNone(length))
     }
 
     /// Parses, with quirks.
     pub fn parse_quirky<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
         allow_quirks: AllowQuirks,
     ) -> Result<Self, ParseError<'i>> {
         if let Ok(l) = input.try(ExtremumLength::parse) {
-            return Ok(MaxLength::ExtremumLength(l));
+            return Ok(GenericMaxLength::ExtremumLength(l));
         }
 
         let length =
             LengthOrPercentageOrNone::parse_non_negative_quirky(context, input, allow_quirks)?;
-        Ok(MaxLength::LengthOrPercentageOrNone(length))
+        Ok(GenericMaxLength::LengthOrPercentageOrNone(length))
     }
 }
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -4187,17 +4187,18 @@ pub extern "C" fn Servo_DeclarationBlock
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property: nsCSSPropertyID,
     value: f32
 ) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
-    use style::values::specified::{BorderSideWidth, MozLength, BorderCornerRadius};
+    use style::values::generics::length::MozLength;
+    use style::values::specified::{BorderSideWidth, BorderCornerRadius};
     use style::values::specified::length::{NoCalcLength, NonNegativeLength, LengthOrPercentage};
 
     let long = get_longhand_from_id!(property);
     let nocalc = NoCalcLength::from_px(value);
 
     let prop = match_wrap_declared! { long,
         Height => MozLength::LengthOrPercentageOrAuto(nocalc.into()),
         Width => MozLength::LengthOrPercentageOrAuto(nocalc.into()),
@@ -4244,17 +4245,17 @@ pub extern "C" fn Servo_DeclarationBlock
 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property: nsCSSPropertyID,
     value: f32,
     unit: structs::nsCSSUnit,
 ) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
-    use style::values::specified::MozLength;
+    use style::values::generics::length::MozLength;
     use style::values::specified::length::{AbsoluteLength, FontRelativeLength};
     use style::values::specified::length::{LengthOrPercentage, NoCalcLength};
 
     let long = get_longhand_from_id!(property);
     let nocalc = match unit {
         structs::nsCSSUnit::eCSSUnit_EM => NoCalcLength::FontRelative(FontRelativeLength::Em(value)),
         structs::nsCSSUnit::eCSSUnit_XHeight => NoCalcLength::FontRelative(FontRelativeLength::Ex(value)),
         structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
@@ -4302,17 +4303,17 @@ pub extern "C" fn Servo_DeclarationBlock
 #[no_mangle]
 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property: nsCSSPropertyID,
     value: f32,
 ) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::values::computed::Percentage;
-    use style::values::specified::MozLength;
+    use style::values::generics::length::MozLength;
     use style::values::specified::length::LengthOrPercentage;
 
     let long = get_longhand_from_id!(property);
     let pc = Percentage(value);
 
     let prop = match_wrap_declared! { long,
         Height => MozLength::LengthOrPercentageOrAuto(pc.into()),
         Width => MozLength::LengthOrPercentageOrAuto(pc.into()),
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
@@ -1,18 +1,16 @@
 # 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/.
 
 from __future__ import absolute_import, print_function
 
 import urllib
 
-from unittest import skip
-
 from marionette_driver import errors
 from marionette_driver.by import By
 from marionette_harness import MarionetteTestCase
 
 
 def inline(doc):
     return "data:text/html;charset=utf-8,{}".format(urllib.quote(doc))
 
@@ -39,42 +37,42 @@ class TestServerQuitApplication(Marionet
 
         self.assertIn("cause", resp)
 
         self.marionette.client.close()
         self.marionette.instance.runner.wait()
 
         return resp["cause"]
 
-    def test_types(self):
+    def tst_types(self):
         for typ in [42, True, "foo", []]:
             print("testing type {}".format(type(typ)))
             with self.assertRaises(errors.InvalidArgumentException):
                 self.marionette._send_message("quit", typ)
 
         with self.assertRaises(errors.InvalidArgumentException):
             self.quit("foo")
 
-    def test_undefined_default(self):
+    def tst_undefined_default(self):
         cause = self.quit()
         self.assertEqual("shutdown", cause)
 
-    def test_empty_default(self):
+    def tst_empty_default(self):
         cause = self.quit(())
         self.assertEqual("shutdown", cause)
 
-    def test_incompatible_flags(self):
+    def tst_incompatible_flags(self):
         with self.assertRaises(errors.InvalidArgumentException):
             self.quit(("eAttemptQuit", "eForceQuit"))
 
-    def test_attempt_quit(self):
+    def tst_attempt_quit(self):
         cause = self.quit(("eAttemptQuit",))
         self.assertEqual("shutdown", cause)
 
-    def test_force_quit(self):
+    def tst_force_quit(self):
         cause = self.quit(("eForceQuit",))
         self.assertEqual("shutdown", cause)
 
 
 class TestQuitRestart(MarionetteTestCase):
 
     def setUp(self):
         MarionetteTestCase.setUp(self)
@@ -112,117 +110,116 @@ class TestQuitRestart(MarionetteTestCase
             Components.utils.import("resource://gre/modules/Services.jsm");
             let flags = Ci.nsIAppStartup.eAttemptQuit;
             if (arguments[0]) {
               flags |= Ci.nsIAppStartup.eRestart;
             }
             Services.startup.quit(flags);
         """, script_args=(restart,))
 
-    def test_force_restart(self):
+    def tst_force_restart(self):
         self.marionette.restart()
         self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
 
         # A forced restart will cause a new process id
         self.assertNotEqual(self.marionette.process_id, self.pid)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_force_clean_restart(self):
+    def tst_force_clean_restart(self):
         self.marionette.restart(clean=True)
         self.assertNotEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         # A forced restart will cause a new process id
         self.assertNotEqual(self.marionette.process_id, self.pid)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_force_quit(self):
+    def tst_force_quit(self):
         self.marionette.quit()
 
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
             self.marionette.get_url()
 
-    def test_force_clean_quit(self):
+    def tst_force_clean_quit(self):
         self.marionette.quit(clean=True)
 
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
         self.assertNotEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_no_in_app_clean_restart(self):
+    def tst_no_in_app_clean_restart(self):
         # Test that in_app and clean cannot be used in combination
         with self.assertRaisesRegexp(ValueError, "cannot be triggered with the clean flag set"):
             self.marionette.restart(in_app=True, clean=True)
 
-    def test_in_app_restart(self):
+    def tst_in_app_restart(self):
         self.marionette.restart(in_app=True)
 
         self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
 
         # An in-app restart will keep the same process id only on Linux
         if self.marionette.session_capabilities["platformName"] == "linux":
             self.assertEqual(self.marionette.process_id, self.pid)
         else:
             self.assertNotEqual(self.marionette.process_id, self.pid)
 
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_in_app_restart_with_callback(self):
+    def tst_in_app_restart_with_callback(self):
         self.marionette.restart(in_app=True,
                                 callback=lambda: self.shutdown(restart=True))
 
         self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
 
         # An in-app restart will keep the same process id only on Linux
         if self.marionette.session_capabilities["platformName"] == "linux":
             self.assertEqual(self.marionette.process_id, self.pid)
         else:
             self.assertNotEqual(self.marionette.process_id, self.pid)
 
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_in_app_restart_with_callback_not_callable(self):
+    def tst_in_app_restart_with_callback_not_callable(self):
         with self.assertRaisesRegexp(ValueError, "is not callable"):
             self.marionette.restart(in_app=True, callback=4)
 
-    def test_in_app_restart_with_callback_but_process_quit(self):
+    def tst_in_app_restart_with_callback_but_process_quit(self):
         timeout_shutdown = self.marionette.DEFAULT_SHUTDOWN_TIMEOUT
         # Wait at least 70s for the hang monitor in case of a shutdown hang
         self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = 70
 
         try:
             with self.assertRaisesRegexp(IOError, "Process unexpectedly quit without restarting"):
                 self.marionette.restart(in_app=True, callback=lambda: self.shutdown(restart=False))
         finally:
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = timeout_shutdown
 
-    def test_in_app_restart_with_callback_missing_shutdown(self):
+    def tst_in_app_restart_with_callback_missing_shutdown(self):
         try:
             timeout_shutdown = self.marionette.DEFAULT_SHUTDOWN_TIMEOUT
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = 5
 
             with self.assertRaisesRegexp(IOError, "the connection to Marionette server is lost"):
                 self.marionette.restart(in_app=True, callback=lambda: False)
         finally:
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = timeout_shutdown
 
-    @skip("Bug 1397612 - Hang of Marionette client after the restart")
     def test_in_app_restart_safe_mode(self):
 
         def restart_in_safe_mode():
             with self.marionette.using_context("chrome"):
                 self.marionette.execute_script("""
                   Components.utils.import("resource://gre/modules/Services.jsm");
 
                   let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
@@ -239,96 +236,96 @@ class TestQuitRestart(MarionetteTestCase
             self.assertFalse(self.is_safe_mode, "Safe Mode is unexpectedly enabled")
             self.marionette.restart(in_app=True, callback=restart_in_safe_mode)
             self.assertTrue(self.is_safe_mode, "Safe Mode is not enabled")
         finally:
             if self.marionette.session is None:
                 self.marionette.start_session()
             self.marionette.quit(clean=True)
 
-    def test_in_app_quit(self):
+    def tst_in_app_quit(self):
         self.marionette.quit(in_app=True)
 
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
         self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_in_app_quit_with_callback(self):
+    def tst_in_app_quit_with_callback(self):
         self.marionette.quit(in_app=True, callback=self.shutdown)
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.InvalidSessionIdException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
         self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:about")
 
-    def test_in_app_quit_with_callback_missing_shutdown(self):
+    def tst_in_app_quit_with_callback_missing_shutdown(self):
         try:
             timeout = self.marionette.DEFAULT_SHUTDOWN_TIMEOUT
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = 5
 
             with self.assertRaisesRegexp(IOError, "Process still running"):
                 self.marionette.quit(in_app=True, callback=lambda: False)
         finally:
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = timeout
 
-    def test_in_app_quit_with_callback_not_callable(self):
+    def tst_in_app_quit_with_callback_not_callable(self):
         with self.assertRaisesRegexp(ValueError, "is not callable"):
             self.marionette.restart(in_app=True, callback=4)
 
-    def test_in_app_quit_with_dismissed_beforeunload_prompt(self):
+    def tst_in_app_quit_with_dismissed_beforeunload_prompt(self):
         self.marionette.navigate(inline("""
           <input type="text">
           <script>
             window.addEventListener("beforeunload", function (event) {
               event.preventDefault();
             });
           </script>
         """))
 
         self.marionette.find_element(By.TAG_NAME, "input").send_keys("foo")
         self.marionette.quit(in_app=True)
         self.marionette.start_session()
 
-    def test_reset_context_after_quit_by_set_context(self):
+    def tst_reset_context_after_quit_by_set_context(self):
         # Check that we are in content context which is used by default in
         # Marionette
         self.assertNotIn("chrome://", self.marionette.get_url(),
                          "Context does not default to content")
 
         self.marionette.set_context("chrome")
         self.marionette.quit(in_app=True)
         self.assertEqual(self.marionette.session, None)
         self.marionette.start_session()
         self.assertNotIn("chrome://", self.marionette.get_url(),
                          "Not in content context after quit with using_context")
 
-    def test_reset_context_after_quit_by_using_context(self):
+    def tst_reset_context_after_quit_by_using_context(self):
         # Check that we are in content context which is used by default in
         # Marionette
         self.assertNotIn("chrome://", self.marionette.get_url(),
                          "Context does not default to content")
 
         with self.marionette.using_context("chrome"):
             self.marionette.quit(in_app=True)
             self.assertEqual(self.marionette.session, None)
             self.marionette.start_session()
             self.assertNotIn("chrome://", self.marionette.get_url(),
                              "Not in content context after quit with using_context")
 
-    def test_keep_context_after_restart_by_set_context(self):
+    def tst_keep_context_after_restart_by_set_context(self):
         # Check that we are in content context which is used by default in
         # Marionette
         self.assertNotIn("chrome://", self.marionette.get_url(),
                          "Context doesn't default to content")
 
         # restart while we are in chrome context
         self.marionette.set_context("chrome")
         self.marionette.restart(in_app=True)
@@ -337,17 +334,17 @@ class TestQuitRestart(MarionetteTestCase
         if self.marionette.session_capabilities["platformName"] == "linux":
             self.assertEqual(self.marionette.process_id, self.pid)
         else:
             self.assertNotEqual(self.marionette.process_id, self.pid)
 
         self.assertIn("chrome://", self.marionette.get_url(),
                       "Not in chrome context after a restart with set_context")
 
-    def test_keep_context_after_restart_by_using_context(self):
+    def tst_keep_context_after_restart_by_using_context(self):
         # Check that we are in content context which is used by default in
         # Marionette
         self.assertNotIn("chrome://", self.marionette.get_url(),
                          "Context does not default to content")
 
         # restart while we are in chrome context
         with self.marionette.using_context('chrome'):
             self.marionette.restart(in_app=True)
deleted file mode 100644
--- a/testing/web-platform/meta/payment-request/PaymentItem/type_member.https.html.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[type_member.https.html]
-  [Smoke test]
-    expected: 
-      if not e10s: FAIL
-
-  [An invalid enum value for PaymentDetailsInit.total's type throws TypeError]
-    expected: 
-      if not e10s: FAIL
-
-  [Invalid enum value for PaymentItem.type member throws a TypeError]
-    expected: 
-      if not e10s: FAIL
-
-  [Valid enum values for PaymentItem.type member does not throw]
-    expected: 
-      if not e10s: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/tests/payment-request/PaymentItem/type_member.https.html
+++ /dev/null
@@ -1,77 +0,0 @@
-<!doctype html>
-<meta charset="utf8">
-<link rel="help" href="https://w3c.github.io/payment-request/#dom-paymentitem-type">
-<title>
-  PaymentItem type member
-</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-const validMethods = [
-  { supportedMethods: "basic-card" },
-  { supportedMethods: "https://apple.com/apple-pay" },
-];
-const validTotal = {
-  label: "Total",
-  amount: {
-    currency: "USD",
-    value: "5.00",
-  },
-};
-const validDisplayItem = {
-  label: "Item",
-  amount: {
-    currency: "USD",
-    value: "1.00",
-  },
-};
-const validDetails = {
-  total: validTotal,
-  displayItems: [validDisplayItem],
-};
-
-test(() => {
-  new PaymentRequest(validMethods, validDetails);
-}, "Smoke test");
-
-test(() => {
-  // Let's make an invalid DisplayItem for the total
-  const invalidTotal = Object.assign({}, validTotal, {
-    type: "this is not valid",
-  });
-  const invalidDetails = Object.assign({}, validDetails, {
-    total: invalidTotal,
-  });
-  assert_throws(new TypeError(), () => {
-    new PaymentRequest(validMethods, invalidDetails);
-  });
-}, "An invalid enum value for PaymentDetailsInit.total's type throws TypeError");
-
-test(() => {
-  // Let's make an invalid DisplayItem to add to displayItems
-  const invalidDisplayItem = Object.assign({}, validDisplayItem, {
-    type: "this is not valid",
-  });
-  const invalidDetails = Object.assign({}, validDetails, {
-    displayItems: [invalidDisplayItem, validDisplayItem],
-  });
-  assert_throws(new TypeError(), () => {
-    new PaymentRequest(validMethods, invalidDetails);
-  });
-}, "Invalid enum value for PaymentItem.type member throws a TypeError");
-
-test(() => {
-  // Let's make an invalid DisplayItem to add to displayItems
-  const taxDisplayItem = Object.assign({}, validDisplayItem, { type: "tax" });
-  const taxTotal = Object.assign({}, validTotal, { type: "tax" });
-  const validDetailsWithType = Object.assign({}, validDetails, {
-    total: taxTotal,
-    displayItems: [taxDisplayItem],
-  });
-  try {
-    new PaymentRequest(validMethods, validDetailsWithType);
-  } catch (err) {
-    assert_unexpected(err.message);
-  }
-}, "Valid enum values for PaymentItem.type member does not throw");
-</script>
new file mode 100644
--- /dev/null
+++ b/third_party/rust/lalrpop-snap/src/parser/lrgrammar.rs
@@ -0,0 +1,89292 @@
+// auto-generated: "lalrpop-snap 0.15.1"
+use string_cache::DefaultAtom as Atom;
+use grammar::parse_tree::*;
+use grammar::pattern::*;
+use std::iter::once;
+use tok::{self, Tok};
+use util::strip;
+#[allow(unused_extern_crates)]
+extern crate lalrpop_util as ___lalrpop_util;
+
+#[cfg_attr(rustfmt, rustfmt_skip)]
+mod ___parse___Grammar {
+    #![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)]
+
+    use string_cache::DefaultAtom as Atom;
+    use grammar::parse_tree::*;
+    use grammar::pattern::*;
+    use std::iter::once;
+    use tok::{self, Tok};
+    use util::strip;
+    #[allow(unused_extern_crates)]
+    extern crate lalrpop_util as ___lalrpop_util;
+    use super::___ToTriple;
+    #[allow(dead_code)]
+    pub enum ___Symbol<'input>
+     {
+        Variant0(Tok<'input>),
+        Variant1(&'input str),
+        Variant2(::std::option::Option<Tok<'input>>),
+        Variant3(TypeRef),
+        Variant4(::std::option::Option<TypeRef>),
+        Variant5(Vec<TypeBoundParameter<TypeRef>>),
+        Variant6(::std::option::Option<Vec<TypeBoundParameter<TypeRef>>>),
+        Variant7(Condition),
+        Variant8(::std::option::Option<Condition>),
+        Variant9(()),
+        Variant10(Alternative),
+        Variant11(::std::vec::Vec<Alternative>),
+        Variant12(Conversion),
+        Variant13(::std::vec::Vec<Conversion>),
+        Variant14(FieldPattern<TypeRef>),
+        Variant15(::std::vec::Vec<FieldPattern<TypeRef>>),
+        Variant16(Parameter),
+        Variant17(::std::vec::Vec<Parameter>),
+        Variant18(WhereClause<TypeRef>),
+        Variant19(::std::vec::Vec<WhereClause<TypeRef>>),
+        Variant20(Atom),
+        Variant21(::std::vec::Vec<Atom>),
+        Variant22(MatchItem),
+        Variant23(::std::vec::Vec<MatchItem>),
+        Variant24(NonterminalString),
+        Variant25(::std::vec::Vec<NonterminalString>),
+        Variant26(Pattern<TypeRef>),
+        Variant27(::std::vec::Vec<Pattern<TypeRef>>),
+        Variant28(Symbol),
+        Variant29(::std::vec::Vec<Symbol>),
+        Variant30(TypeBound<TypeRef>),
+        Variant31(::std::vec::Vec<TypeBound<TypeRef>>),
+        Variant32(TypeBoundParameter<TypeRef>),
+        Variant33(::std::vec::Vec<TypeBoundParameter<TypeRef>>),
+        Variant34(TypeParameter),
+        Variant35(::std::vec::Vec<TypeParameter>),
+        Variant36(::std::vec::Vec<TypeRef>),
+        Variant37(usize),
+        Variant38(ActionKind),
+        Variant39(::std::option::Option<ActionKind>),
+        Variant40(::std::option::Option<Alternative>),
+        Variant41(Vec<Alternative>),
+        Variant42(Annotation),
+        Variant43(::std::vec::Vec<Annotation>),
+        Variant44(AssociatedType),
+        Variant45(::std::vec::Vec<AssociatedType>),
+        Variant46(Vec<Conversion>),
+        Variant47(Vec<Parameter>),
+        Variant48(Vec<WhereClause<TypeRef>>),
+        Variant49(Vec<Atom>),
+        Variant50(Vec<MatchItem>),
+        Variant51(Vec<NonterminalString>),
+        Variant52(Vec<Pattern<TypeRef>>),
+        Variant53(Vec<Symbol>),
+        Variant54(Vec<TypeParameter>),
+        Variant55(Vec<TypeRef>),
+        Variant56(ConditionOp),
+        Variant57(::std::option::Option<Conversion>),
+        Variant58(EnumToken),
+        Variant59(ExprSymbol),
+        Variant60(GrammarItem),
+        Variant61(::std::option::Option<FieldPattern<TypeRef>>),
+        Variant62(::std::option::Option<Vec<Atom>>),
+        Variant63(Grammar),
+        Variant64(::std::vec::Vec<GrammarItem>),
+        Variant65(::std::option::Option<Parameter>),
+        Variant66(::std::option::Option<Vec<Parameter>>),
+        Variant67(::std::option::Option<Vec<TypeParameter>>),
+        Variant68(::std::option::Option<WhereClause<TypeRef>>),
+        Variant69(::std::option::Option<Vec<WhereClause<TypeRef>>>),
+        Variant70(::std::option::Option<Atom>),
+        Variant71(MatchContents),
+        Variant72(::std::option::Option<MatchItem>),
+        Variant73(TerminalString),
+        Variant74(TerminalLiteral),
+        Variant75(MatchToken),
+        Variant76((NonterminalString, Vec<NonterminalString>)),
+        Variant77(::std::option::Option<NonterminalString>),
+        Variant78(Path),
+        Variant79(::std::option::Option<Pattern<TypeRef>>),
+        Variant80(PatternKind<TypeRef>),
+        Variant81(Vec<TypeBound<TypeRef>>),
+        Variant82(RepeatOp),
+        Variant83(String),
+        Variant84(::std::vec::Vec<String>),
+        Variant85(::std::option::Option<Symbol>),
+        Variant86(SymbolKind),
+        Variant87(::std::option::Option<TypeBound<TypeRef>>),
+        Variant88(::std::option::Option<TypeBoundParameter<TypeRef>>),
+        Variant89(::std::option::Option<TypeParameter>),
+        Variant90(Visibility),
+    }
+    const ___ACTION: &'static [i16] = &[
+        // State 0
+        0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+        // State 1
+        0, 0, 0, -124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -124, -124, 0, -124, 0, 0, 0, 0, 0, 0, 0, 0, 0, -124, 0, 0, 0, -124, 0, 0, 0, 0, 0, 0,
+        // State 2
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 3
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 4
+        0, 0, 0, -425, -425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -425, 0, 0, 0, 0, 0, -425, 0, 0, 0, 0,
+        // State 5
+        0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+        // State 6
+        0, 0, 0, -488, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0, 0, -488, 0, 0, 0, 0,
+        // State 7
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+        // State 8
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 9
+        0, 0, 0, -422, -422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -422, 0, 0, 0, 0, 0, -422, 0, 0, 0, 0,
+        // State 10
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 11
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 12
+        0, 0, 0, -125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -125, -125, 0, -125, 0, 0, 0, 0, 0, 0, 0, 0, 0, -125, 0, 0, 0, -125, 0, 0, 0, 0, 0, 0,
+        // State 13
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 34, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 14
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 15
+        0, 0, 0, -426, -426, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -426, 0, 0, 0, 0, 0, -426, 0, 0, 0, 0,
+        // State 16
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+        // State 17
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 41, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 18
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 19
+        0, 0, 0, -489, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0, 0, -489, 0, 0, 0, 0,
+        // State 20
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 46, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 21
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 22
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 23
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 24
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 25
+        0, 0, 0, 0, 0, 0, 0, -140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 26
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 27
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -172, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 28
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, -144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 29
+        0, 0, 0, -485, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -485, -485, 0, -485, 0, 0, 0, 0, 0, 0, 0, -485, 0, -485, 0, -485, 0, -485, 0, -485, 0, 0, 0, 0,
+        // State 30
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 31
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 32
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 33
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 34
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 102, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 35
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 36
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 107, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 37
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 38
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 39
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 40
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 41
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 118, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 42
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 43
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 44
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 45
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 46
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 47
+        0, 0, 0, 0, 0, 0, -360, -360, 0, -360, -360, 0, 0, -360, -360, -360, -360, -360, 0, 0, 0, 0, 0, -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -360, 0, 0,
+        // State 48
+        0, 0, 0, 0, 0, 0, -361, -361, 0, -361, -361, 0, 0, -361, -361, -361, -361, -361, 0, 0, 0, 0, 0, -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -361, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -361, 0, 0,
+        // State 49
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 50
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 51
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 52
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 53
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 54
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 55
+        0, 0, 0, 0, 0, 0, 0, -142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 56
+        0, 0, 0, 0, 0, 0, 0, 135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 57
+        0, 0, 0, 0, 0, 0, 0, -139, 0, 0, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 58
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 59
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0,
+        // State 60
+        0, 0, 0, -337, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -337, -337, 0, -337, 0, 0, 0, 0, 0, 0, 0, -337, 0, 0, 0, -337, 0, -337, 0, -337, 0, 0, 0, 0,
+        // State 61
+        0, 0, 0, -341, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -341, -341, 0, -341, 0, 0, 0, 0, 0, 0, 0, -341, 0, 0, 0, -341, 0, -341, 0, -341, 0, 0, 0, 0,
+        // State 62
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 63
+        0, 0, 0, -336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -336, -336, 0, -336, 0, 0, 0, 0, 0, 0, 0, -336, 0, 0, 0, -336, 0, -336, 0, -336, 0, 0, 0, 0,
+        // State 64
+        0, 0, 0, -374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -374, -374, 0, -374, 0, 0, 0, 0, 0, 140, 0, -374, 0, 0, 0, -374, 0, -374, 0, -374, 0, 0, 0, 0,
+        // State 65
+        0, 0, 0, -338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -338, -338, 0, -338, 0, 0, 0, 0, 0, 0, 0, -338, 0, 0, 0, -338, 0, -338, 0, -338, 0, 0, 0, 0,
+        // State 66
+        0, 0, 0, -335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -335, -335, 0, -335, 0, 0, 0, 0, 0, 0, 0, -335, 0, 0, 0, -335, 0, -335, 0, -335, 0, 0, 0, 0,
+        // State 67
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 145, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 68
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 0, 0,
+        // State 69
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 0, 0,
+        // State 70
+        0, 0, 0, 0, 0, 0, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -491, -491, 0, -491, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 71
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -174, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 72
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 73
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -468, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 74
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -467, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -467, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 75
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 76
+        0, 0, 0, -362, 0, -362, -362, 0, 0, -362, -362, 0, 0, -362, -362, -362, 0, 0, 0, 0, 0, 0, 0, -362, 0, 0, 0, 0, 0, -362, 0, -362, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -362, 0, 0, 0, 0, 0, 0, 0,
+        // State 77
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, -146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 78
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 79
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 80
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 81
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 156, 0, 0, 0, 0, -143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 82
+        0, 0, 0, 0, 0, 0, -389, -389, 0, -389, -389, 0, 0, -389, 157, -389, -389, -389, 0, 0, 0, 0, 0, -389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -389, 0, 0,
+        // State 83
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 84
+        0, 0, 0, 0, 0, 0, 0, -478, 0, -478, -478, 0, 0, -478, 0, -478, 159, -478, 0, 0, 0, 0, 0, -478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -478, 0, 0,
+        // State 85
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 86
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 87
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 0, 0, 0, 0, 0, 0, 0,
+        // State 88
+        0, 0, 0, 87, 0, 88, 89, -176, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 89
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 90
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 91
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 92
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 93
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 94
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 95
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 96
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 97
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 98
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 197, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 99
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 100
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 101
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 102
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 206, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 103
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 104
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 105
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 106
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 107
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 108
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 109
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 110
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 111
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 112
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 113
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 114
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 115
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 116
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 117
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 118
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 119
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 120
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 121
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 122
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 123
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 124
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 125
+        0, 0, 0, -121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -121, -121, 0, -121, 0, 0, 0, 0, 0, 0, 0, 0, 0, -121, 0, 0, 0, -121, 0, 0, 0, 0, 0, 0,
+        // State 126
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 127
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 128
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 129
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 130
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 131
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 132
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 133
+        0, 0, 0, 0, 0, 0, 0, -141, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 134
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -346, 0, 0, 0,
+        // State 135
+        0, 0, 0, 0, 0, 0, 0, -36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -36, 0, -36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 136
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 137
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 145, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 138
+        0, 0, 0, -342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -342, -342, 0, -342, 0, 0, 0, 0, 0, 0, 0, -342, 0, 0, 0, -342, 0, -342, 0, -342, 0, 0, 0, 0,
+        // State 139
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 0, 0,
+        // State 140
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 243, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 141
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 0, 0, 0, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 142
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -382, 0, 0, 0, -382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 143
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -383, 0, 0, 0, -383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 144
+        0, -384, -384, 0, 0, 0, 0, 0, 0, 0, -384, 0, 0, -384, 0, 0, 0, -384, -384, 0, 0, 0, 0, -384, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -384,
+        // State 145
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -365, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 146
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 251, 0,
+        // State 147
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 179, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -152, 0,
+        // State 148
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 149
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 150
+        0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -349, 0, 0, 0,
+        // State 151
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -91, 0, 0, 0, 0, 0, -91, -91, -91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 152
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, 0, 0, 0, 0, -145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 153
+        0, 0, 0, 0, 0, 0, -390, -390, 0, -390, -390, 0, 0, -390, 262, -390, -390, -390, 0, 0, 0, 0, 0, -390, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -390, 0, 0,
+        // State 154
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 155
+        0, 0, 0, -41, 0, -41, -41, 0, 0, 0, 0, 0, 0, 0, -41, -41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -41, -41, -41, 0, 0, 0, 0, 0, 0, 0, 0, -41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 156
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -46, 0, -46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 157
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -408, 0, 0, 0, 0, -408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 158
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, -180, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 159
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -412, 0, 0, 0, 90, -412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 160
+        -443, 0, 0, -443, 0, 0, -443, -443, -443, -443, -443, 0, 0, 0, 0, -443, -443, 0, 0, -443, -443, -443, -443, -443, -443, -443, -443, 0, -443, -443, 0, -443, -443, -443, 0, 0, 0, 0, 0, 0, 0, 0, -443, 0, 0, 0, 0, 0, 0, 0, -443, 0,
+        // State 161
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 162
+        -417, 0, 0, -417, 0, 0, -417, -417, -417, -417, -417, 0, 0, 0, 0, -417, -417, 0, 0, -417, -417, -417, -417, -417, -417, -417, -417, 0, -417, -417, 0, -417, -417, -417, 0, 0, 0, 0, 0, 0, 0, 0, -417, 0, 0, 0, 0, 0, 0, 0, -417, 0,
+        // State 163
+        -441, 0, 0, -441, 0, 0, -441, -441, -441, -441, -441, 0, 0, 0, 0, -441, -441, 0, 0, -441, -441, -441, -441, -441, -441, -441, -441, 0, -441, -441, 0, -441, -441, -441, 0, 0, 0, 0, 0, 0, 0, 0, -441, 0, 0, 0, 0, 0, 0, 0, -441, 0,
+        // State 164
+        -416, 0, 0, -416, 0, 0, -416, -416, -416, -416, -416, 0, 0, 0, 0, -416, -416, 0, 0, -416, -416, -416, -416, -416, -416, -416, -416, 0, -416, -416, 0, -416, -416, -416, 0, 0, 0, 0, 0, 0, 0, 0, -416, 0, 0, 0, 0, 0, 0, 0, -416, 0,
+        // State 165
+        -415, 0, 0, -415, 0, 0, -415, -415, -415, -415, -415, 0, 0, 0, 0, -415, -415, 0, 0, -415, -415, -415, -415, -415, -415, -415, -415, 0, -415, -415, 0, -415, -415, -415, 0, 0, 0, 0, 0, 0, 0, 0, -415, 0, 0, 0, 0, 0, 0, 0, -415, 0,
+        // State 166
+        0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 167
+        -430, 0, 0, -430, 0, 0, -430, -430, 282, 283, -430, 0, 0, 0, 0, -430, -430, 0, 0, -430, -430, -430, -430, -430, 284, -430, -430, 0, -430, -430, 0, -430, -430, -430, 0, 0, 0, 0, 0, 0, 0, 0, -430, 0, 0, 0, 0, 0, 0, 0, -430, 0,
+        // State 168
+        -435, 0, 0, -435, 0, 0, -435, -435, -435, -435, -435, 0, 0, 0, 0, -435, -435, 0, 0, -435, -435, -435, -435, -435, -435, -435, -435, 0, -435, -435, 0, -435, -435, -435, 0, 0, 0, 0, 0, 0, 0, 0, -435, 0, 0, 0, 0, 0, 0, 0, -435, 0,
+        // State 169
+        -437, 0, 0, -437, 0, 0, -437, -437, -437, -437, -437, 0, 0, 0, 0, -437, -437, 0, 0, -437, -437, -437, -437, -437, -437, -437, -437, 0, -437, -437, 0, -437, -437, -437, 0, 0, 0, 0, 0, 0, 0, 0, -437, 0, 0, 0, 0, 0, 0, 0, -437, 0,
+        // State 170
+        -447, 0, 0, -447, 0, 0, -447, -447, -447, -447, -447, 0, 0, 0, 0, -447, -447, 0, 0, -447, -447, -447, -447, -447, -447, -447, -447, 0, -447, -447, 0, -447, -447, -447, 0, 0, 0, 0, 0, 0, 0, 0, -447, 0, 0, 0, 0, 0, 0, 0, -447, 0,
+        // State 171
+        171, 0, 0, 0, 0, 0, 172, -193, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 172
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174, 175, 0, 176, 290, 0, 291, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 173
+        -445, 0, 0, -445, 0, 0, -445, -445, -445, -445, -445, 0, 0, 0, 0, -445, -445, 0, 0, -445, -445, -445, -445, -445, -445, -445, -445, 0, -445, -445, 0, -445, -445, -445, 0, 0, 0, 0, 0, 0, 0, 0, -445, 0, 0, 0, 0, 0, 0, 0, -445, 0,
+        // State 174
+        -446, 0, 0, -446, 0, 0, -446, -446, -446, -446, -446, 0, 0, 0, 0, -446, -446, 0, 0, -446, -446, -446, -446, -446, -446, -446, -446, 0, -446, -446, 0, -446, -446, -446, 0, 0, 0, 0, 0, 0, 0, 0, -446, 0, 0, 0, 0, 0, 0, 0, -446, 0,
+        // State 175
+        -192, 0, 0, -192, 0, 0, -192, -192, -192, -192, -192, 0, 0, 0, 0, -192, -192, 0, 0, -192, -192, -192, -192, -192, -192, -192, -192, 0, -192, -192, 0, -192, -192, -192, 0, 0, 0, 0, 0, 0, 0, 0, -192, 0, 0, 0, 0, 0, 0, 0, -192, 0,
+        // State 176
+        -442, 0, 0, -442, 0, 0, -442, -442, -442, -442, -442, 0, 0, 0, 0, -442, -442, 0, 0, -442, -442, -442, -442, -442, -442, -442, -442, 0, -442, -442, 0, -442, -442, -442, 0, 0, 0, 0, 0, 0, 0, 0, -442, 0, 0, 0, 0, 0, 0, 0, -442, 0,
+        // State 177
+        -418, 0, 0, -418, 0, 0, -418, -418, -418, -418, -418, 0, 0, 0, 0, -418, -418, 0, 0, -418, -418, -418, -418, -418, -418, -418, -418, 0, -418, -418, 0, -418, -418, -418, 0, 0, 0, 0, 0, 0, 0, 0, -418, 0, 0, 0, 0, 0, 0, 0, -418, 0,
+        // State 178
+        -427, 0, 0, -427, 0, 0, -427, -427, -427, -427, -427, 0, 0, 0, 0, -427, -427, 0, 0, -427, -427, -427, -427, -427, -427, -427, -427, 0, -427, -427, 0, -427, -427, -427, 0, 0, 0, 0, 0, 0, 0, 0, -427, 0, 0, 0, 0, 0, 0, 0, -427, 0,
+        // State 179
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 293, 0, 0, 0, 0, 0, 0, 0,
+        // State 180
+        0, 0, 0, 0, 0, 0, 0, -476, 0, -476, -476, 0, 0, -476, 0, -476, 0, -476, 0, 0, 0, 0, 0, -476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -476, 0, 0,
+        // State 181
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 182
+        0, 0, 0, 87, 0, 88, 89, -178, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 183
+        0, 0, 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 184
+        0, 0, 0, 0, 0, 0, 0, -175, 0, 0, 297, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 185
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 186
+        0, 0, 0, 0, 0, 0, -387, -387, 0, -387, -387, 0, 0, -387, 157, -387, -387, -387, 0, 0, 0, 0, 0, -387, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -387, 0, 0,
+        // State 187
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -148, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 188
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 189
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 190
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 191
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 192
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 193
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 194
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 195
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 196
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 197
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 198
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 199
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 200
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 201
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 202
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 203
+        0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 204
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 205
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 206
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 207
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 208
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 209
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 210
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 211
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 212
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 213
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 214
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 215
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 216
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 217
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 218
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 219
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 220
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 221
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 222
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 223
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 224
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 225
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 226
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 227
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 228
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 229
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 230
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 231
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 232
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 233
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 234
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 235
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 236
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 237
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 238
+        0, 0, 0, 0, 0, 0, 0, -37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -37, 0, -37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 239
+        0, 0, 0, 0, 0, 0, 0, -343, 0, 0, -343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 240
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 241
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 179, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -152, 0,
+        // State 242
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -156, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 243
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 244
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 354, 355, 356, 357, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 359, 0, 0,
+        // State 245
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, 0, 0, 0, 0, -129, 0, 0, 0, -129, 0,
+        // State 246
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 362, 0,
+        // State 247
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 364, 0,
+        // State 248
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 249
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 250
+        0, 0, 0, -199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -199, -199, 0, -199, 0, 0, 0, 0, 0, 0, 0, -199, 0, 0, 0, -199, 0, -199, 0, -199, 0, 0, 0, 0,
+        // State 251
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 178, 179, 0, 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -154, 0,
+        // State 252
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -366, 0,
+        // State 253
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 0,
+        // State 254
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -151, 0,
+        // State 255
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -368, 0, 0, 0, 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -368, 0,
+        // State 256
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -373, 0, 0, 0, 0, 0, 0, 0, 0, -373, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -373, 0,
+        // State 257
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -367, 0,
+        // State 258
+        0, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 259
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -92, 0, 0, 0, 0, 0, -92, -92, -92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 260
+        0, 0, 0, -42, 0, -42, -42, 0, 0, 0, 0, 0, 0, 0, -42, -42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -42, -42, -42, 0, 0, 0, 0, 0, 0, 0, 0, -42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 261
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -47, 0, -47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 262
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -412, 0, 0, 0, 90, -412, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 263
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -410, 0, 0, 0, 0, -410, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 264
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 374, -407, 0, 0, 0, 0, -407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 265
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -352, 0, 0, 0, 0, -352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 266
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, -182, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 267
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 268
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 269
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 270
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 271
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -414, 0, 0, 0, 90, -414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 77, 49, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 272
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 273
+        0, 0, 0, 0, 0, 0, 0, 0, 0, -450, -450, 0, 0, 0, 0, -450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 274
+        0, 0, 0, 0, 0, 0, 380, 0, 0, -458, -458, 0, 0, 0, 0, -458, 381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 275
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -466, 0, 0, 0, 0, -466, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 276
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 382, -411, 0, 0, 0, 0, -411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 277
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -354, 0, 0, 0, 0, -354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 278
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, -164, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 279
+        0, 0, 0, 0, 0, 0, 0, -472, 0, -472, -472, 0, 0, -472, 0, -472, 0, -472, 0, 0, 0, 0, 0, -472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -472, 0, 0,
+        // State 280
+        -436, 0, 0, -436, 0, 0, -436, -436, -436, -436, -436, 0, 0, 0, 0, -436, -436, 0, 0, -436, -436, -436, -436, -436, -436, -436, -436, 0, -436, -436, 0, -436, -436, -436, 0, 0, 0, 0, 0, 0, 0, 0, -436, 0, 0, 0, 0, 0, 0, 0, -436, 0,
+        // State 281
+        -420, 0, 0, -420, 0, 0, -420, -420, -420, -420, -420, 0, 0, 0, 0, -420, -420, 0, 0, -420, -420, -420, -420, -420, -420, -420, -420, 0, -420, -420, 0, -420, -420, -420, 0, 0, 0, 0, 0, 0, 0, 0, -420, 0, 0, 0, 0, 0, 0, 0, -420, 0,
+        // State 282
+        -419, 0, 0, -419, 0, 0, -419, -419, -419, -419, -419, 0, 0, 0, 0, -419, -419, 0, 0, -419, -419, -419, -419, -419, -419, -419, -419, 0, -419, -419, 0, -419, -419, -419, 0, 0, 0, 0, 0, 0, 0, 0, -419, 0, 0, 0, 0, 0, 0, 0, -419, 0,
+        // State 283
+        -421, 0, 0, -421, 0, 0, -421, -421, -421, -421, -421, 0, 0, 0, 0, -421, -421, 0, 0, -421, -421, -421, -421, -421, -421, -421, -421, 0, -421, -421, 0, -421, -421, -421, 0, 0, 0, 0, 0, 0, 0, 0, -421, 0, 0, 0, 0, 0, 0, 0, -421, 0,
+        // State 284
+        0, 0, 0, 0, 0, 0, 0, 386, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 285
+        -433, 0, 0, 0, 0, 0, -433, -433, 0, 0, -433, 0, 0, 0, 0, -433, -433, 0, 0, -433, -433, -433, -433, 0, 0, -433, -433, 0, -433, -433, 0, -433, -433, -433, 0, 0, 0, 0, 0, 0, 0, 0, -433, 0, 0, 0, 0, 0, 0, 0, -433, 0,
+        // State 286
+        171, 0, 0, 0, 0, 0, 172, -194, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 287
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 288
+        0, 0, 0, 0, 0, 0, 0, 0, 282, 283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 289
+        0, 0, 0, 0, 0, 0, 0, 0, -442, -442, 0, 0, 0, -360, 0, 0, 0, 0, 0, 0, 0, 0, 0, -442, -442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 290
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -361, 0, 0, -365, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 291
+        0, 0, 0, 0, 0, 0, 0, -475, 0, -475, -475, 0, 0, -475, 0, -475, 0, -475, 0, 0, 0, 0, 0, -475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -475, 0, 0,
+        // State 292
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 293
+        0, 0, 0, 0, 0, 0, 0, -474, 0, -474, -474, 0, 0, -474, 0, -474, 0, -474, 0, 0, 0, 0, 0, -474, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -474, 0, 0,
+        // State 294
+        0, 0, 0, 0, 0, 0, 0, -177, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 295
+        0, 0, 0, 0, 0, 0, 0, -471, 0, -471, -471, 0, 0, -471, 0, -471, 0, -471, 0, 0, 0, 0, 0, -471, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -471, 0, 0,
+        // State 296
+        0, 0, 0, -96, 0, -96, -96, -96, 0, 0, 0, 0, 0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -96, 0, -96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 297
+        0, 0, 0, 0, 0, 0, -388, -388, 0, -388, -388, 0, 0, -388, 262, -388, -388, -388, 0, 0, 0, 0, 0, -388, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -388, 0, 0,
+        // State 298
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -150, 0, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 299
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 300
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 301
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 302
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 303
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 304
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 305
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 306
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 307
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 308
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 309
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 310
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 311
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 312
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 313
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 314
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0,
+        // State 315
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 316
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 317
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 318
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 319
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 320
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 321
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 322
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 323
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 324
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 325
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 326
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 327
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 328
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 329
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 330
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 331
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 332
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 333
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 334
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 335
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 336
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 337
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 338
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 339
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 340
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 341
+        0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -492, -492, 0, -492, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 12, 0, 0, 0, 0,
+        // State 342
+        0, 0, 0, 87, 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 343
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 354, 355, 356, 357, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 359, 0, 0,
+        // State 344
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 419, 0,
+        // State 345
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -158, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 346
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 421, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 347
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 348
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 423, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 349
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -116, 0, 0, 0, 0, -116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -116, 0,
+        // State 350
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 351
+        0, 0, 0, -379, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -379, -379, 0, -379, 0, 0, 0, 0, 0, 0, 0, -379, 0, 0, 0, -379, 0, -379, 0, -379, 0, 0, 0, 0,
+        // State 352
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, -114, 0, 0, 0, 0, -114, 173, 0, 0, 354, 355, 356, 357, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 426, 0, 0, 0, 0, 0, 0, 0, -114, 0,
+        // State 353
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -107, 0, 0, 0, 0, -107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -107, 0,
+        // State 354
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -108, 0, 0, 0, 0, -108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -108, 0,
+        // State 355
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -105, 0, 0, 0, 0, -105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -105, 0,
+        // State 356
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -106, 0, 0, 0, 0, -106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -106, 0,
+        // State 357
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        // State 358
+        171, 0, 0, 0, 0, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 354, 355, 356, 357, 0, 0, 174, 175, 0, 176, 177, 0, 146, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 0, -132,