Merge mozilla-central to inbound. a=merge CLOSED TREE
authorCsoregi Natalia <ncsoregi@mozilla.com>
Mon, 13 Aug 2018 18:45:57 +0300
changeset 486364 b5a05c5f134c06a0f4419d2a27d53070e6831160
parent 486363 8289b70dc0dbbe144f0081c7d99add92707efe79 (current diff)
parent 486322 6296ed36532a887f88dfe4c6299f34811e694220 (diff)
child 486365 fb38cfb1031dcd9ca730d7aeac46c8dacf24c0e7
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.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
devtools/client/webconsole/test/mochitest/browser_jsterm_no_autocompletion_on_defined_variables.js
--- a/browser/base/content/aboutNetError-new.xhtml
+++ b/browser/base/content/aboutNetError-new.xhtml
@@ -61,16 +61,17 @@
         <h1 id="et_nssFailure2">&nssFailure2.title;</h1>
         <h1 id="et_nssBadCert">&certerror.longpagetitle2;</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>
       <div id="errorDescriptionsContainer">
         <div id="ed_generic">&generic.longDesc;</div>
         <div id="ed_captivePortal">&captivePortal.longDesc2;</div>
         <div id="ed_dnsNotFound">&dnsNotFound.longDesc1;</div>
         <div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
         <div id="ed_fileAccessDenied">&fileAccessDenied.longDesc;</div>
         <div id="ed_malformedURI"></div>
@@ -91,31 +92,32 @@
         <div id="ed_nssFailure2">&nssFailure2.longDesc2;</div>
         <div id="ed_nssBadCert">&certerror.introPara1;</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>
       <div id="errorDescriptions2Container">
           <div id="ed2_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE">&certerror.expiredCert.secondPara;</div>
       </div>
       <div id="whatCanYouDoAboutItTitleContainer">
         <div id="edd_nssBadCert"><strong>&certerror.whatCanYouDoAboutItTitle;</strong></div>
       </div>
       <div id="whatCanYouDoAboutItContainer">
         <div id="es_nssBadCert_SEC_ERROR_UNKNOWN_ISSUER">&certerror.unknownIssuer.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_SEC_ERROR_OCSP_FUTURE_RESPONSE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_SEC_ERROR_OCSP_OLD_RESPONSE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
-        <div id="es_nssBadCert_MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt;</div>
+        <div id="es_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE">&certerror.expiredCert.whatCanYouDoAboutIt2;</div>
+        <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>
     </div>
 
     <!-- PAGE CONTAINER (for styling purposes only) -->
     <div id="errorPageContainer" class="container">
       <div id="text-container">
@@ -171,29 +173,32 @@
         <div id="prefChangeContainer" class="button-container">
           <p>&prefReset.longDesc;</p>
           <button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
         </div>
 
         <div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
           <button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage1.label;</button>
           <button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
+          <button id="errorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
           <button id="advancedButton" autocomplete="off">&continue1.label;</button>
+          <button id="moreInformationButton" autocomplete="off">&moreInformation.label;</button>
         </div>
       </div>
 
       <div id="netErrorButtonContainer" class="button-container">
         <button id="errorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
       </div>
 
       <div id="advancedPanelContainer">
         <div id="badCertAdvancedPanel" class="advanced-panel">
           <p id="badCertTechnicalInfo"/>
           <div id="advancedPanelButtonContainer" class="button-container">
             <button id="advancedPanelReturnButton" class="primary" autocomplete="off">&returnToPreviousPage1.label;</button>
+            <button id="advancedPanelErrorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
             <div class="exceptionDialogButtonContainer">
               <button id="exceptionDialogButton">&securityOverride.exceptionButtonLabel;</button>
             </div>
           </div>
         </div>
 
         <div id="certificateErrorReporting">
             <p class="toggle-container-with-text">
--- a/browser/base/content/aboutNetError.js
+++ b/browser/base/content/aboutNetError.js
@@ -77,33 +77,35 @@ function showPrefChangeContainer() {
 function setupAdvancedButton() {
   // Get the hostname and add it to the panel
   var panel = document.getElementById("badCertAdvancedPanel");
   for (var span of panel.querySelectorAll("span.hostname")) {
     span.textContent = document.location.hostname;
   }
 
   // Register click handler for the weakCryptoAdvancedPanel
-  document.getElementById("advancedButton")
-          .addEventListener("click", function togglePanelVisibility() {
+  document.getElementById("advancedButton").addEventListener("click", togglePanelVisibility);
+  document.getElementById("moreInformationButton").addEventListener("click", togglePanelVisibility);
+
+  function togglePanelVisibility() {
     toggleDisplay(panel);
     if (gIsCertError) {
       // Toggling the advanced panel must ensure that the debugging
       // information panel is hidden as well, since it's opened by the
       // error code link in the advanced panel.
       var div = document.getElementById("certificateErrorDebugInformation");
       div.style.display = "none";
     }
 
     if (panel.style.display == "block") {
       // send event to trigger telemetry ping
       var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles: true});
       document.dispatchEvent(event);
     }
-  });
+  }
 
   if (!gIsCertError) {
     return;
   }
 
   if (getCSSClass() == "expertBadCert") {
     toggleDisplay(document.getElementById("badCertAdvancedPanel"));
     // Toggling the advanced panel must ensure that the debugging
@@ -372,12 +374,17 @@ function addAutofocus(buttonId, position
   }
 }
 
 let errorTryAgain = document.getElementById("errorTryAgain");
 errorTryAgain.addEventListener("click", function() {
   retryThis(this);
 });
 
+let advancedPanelErrorTryAgain = document.getElementById("advancedPanelErrorTryAgain");
+advancedPanelErrorTryAgain.addEventListener("click", function() {
+  retryThis(this);
+});
+
 // Note: It is important to run the script this way, instead of using
 // an onload handler. This is because error pages are loaded as
 // LOAD_BACKGROUND, which means that onload handlers will not be executed.
 initPage();
--- a/browser/base/content/aboutNetError.xhtml
+++ b/browser/base/content/aboutNetError.xhtml
@@ -145,26 +145,30 @@
           <p>&prefReset.longDesc;</p>
           <button id="prefResetButton" class="primary" autocomplete="off">&prefReset.label;</button>
         </div>
 
         <div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
           <button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage.label;</button>
           <button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
           <button id="advancedButton" autocomplete="off">&advanced.label;</button>
+          <button id="moreInformationButton" autocomplete="off">&moreInformation.label;</button>
         </div>
       </div>
 
       <div id="netErrorButtonContainer" class="button-container">
         <button id="errorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
       </div>
 
       <div id="advancedPanelContainer">
         <div id="badCertAdvancedPanel" class="advanced-panel">
           <p id="badCertTechnicalInfo"/>
+          <div id="advancedPanelButtonContainer" class="button-container">
+            <button id="advancedPanelErrorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
+          </div>
           <div class="exceptionDialogButtonContainer">
             <button id="exceptionDialogButton">&securityOverride.exceptionButtonLabel;</button>
           </div>
         </div>
 
         <div id="certificateErrorDebugInformation">
           <button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
           <div id="certificateErrorText"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3008,16 +3008,17 @@ var BrowserOnClick = {
         goBackFromErrorPage();
         break;
 
       case "advancedPanelReturnButton":
         goBackFromErrorPage();
         break;
 
       case "advancedButton":
+      case "moreInformationButton":
         if (isTopFrame) {
           secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
         }
 
         securityInfo = getSecurityInfo(securityInfoAsString);
         sslStatus = securityInfo.SSLStatus;
         let errorInfo = getDetailedCertErrorInfo(location,
                                                  securityInfo);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/illustrations/blue-berror.svg
@@ -0,0 +1,83 @@
+<!-- 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 221.72 184.08">
+  <defs>
+    <linearGradient id="a" x1="41.64" x2="186.34" y1="42.04" y2="186.73" gradientUnits="userSpaceOnUse">
+      <stop offset="0" stop-color="#ccfbff"/>
+      <stop offset="1" stop-color="#c9e4ff"/>
+    </linearGradient>
+    <linearGradient id="c" x1="70.5" x2="215.2" y1="13.17" y2="157.87" href="#a"/>
+    <linearGradient id="b" x1="58.88" x2="188.27" y1="46.79" y2="176.18" gradientUnits="userSpaceOnUse">
+      <stop offset="0" stop-color="#00c8d7"/>
+      <stop offset="1" stop-color="#0a84ff"/>
+    </linearGradient>
+    <linearGradient id="d" x1="55.56" x2="184.95" y1="50.11" y2="179.5" href="#b"/>
+    <linearGradient id="e" x1="28.59" x2="173.29" y1="55.09" y2="199.78" href="#a"/>
+    <linearGradient id="f" x1="66.82" x2="196.2" y1="38.86" y2="168.25" href="#b"/>
+    <linearGradient id="g" x1="51.82" x2="196.52" y1="31.85" y2="176.55" href="#a"/>
+    <linearGradient id="h" x1="46.04" x2="182.33" y1="46.64" y2="182.93" href="#b"/>
+    <linearGradient id="i" x1="74.81" x2="204.19" y1="30.87" y2="160.26" href="#b"/>
+    <linearGradient id="j" x1="71.48" x2="200.87" y1="34.19" y2="163.58" href="#b"/>
+    <linearGradient id="k" x1="58.65" x2="158.03" y1="76.32" y2="175.7" href="#a"/>
+    <linearGradient id="l" x1="47.95" x2="177.33" y1="57.73" y2="187.11" href="#b"/>
+    <linearGradient id="m" x1="66.54" x2="165.92" y1="68.43" y2="167.81" href="#a"/>
+    <linearGradient id="n" x1="62.64" x2="162.02" y1="72.32" y2="171.7" href="#a"/>
+    <linearGradient id="o" x1="65.19" x2="209.88" y1="18.49" y2="163.19" href="#a"/>
+    <linearGradient id="p" x1="72.88" x2="217.58" y1="10.8" y2="155.49" href="#a"/>
+    <linearGradient id="q" x1="61.64" x2="206.34" y1="22.03" y2="166.73" href="#a"/>
+    <linearGradient id="r" x1="63.95" x2="198.65" y1="31.06" y2="165.75" href="#b"/>
+    <linearGradient id="s" x1="69.39" x2="204.08" y1="25.62" y2="160.31" href="#b"/>
+    <linearGradient id="t" x1="66.77" x2="201.46" y1="28.24" y2="162.93" href="#b"/>
+    <linearGradient id="u" x1="71.02" x2="205.71" y1="23.99" y2="158.69" href="#b"/>
+    <linearGradient id="v" x1="69.27" x2="203.96" y1="25.74" y2="160.44" href="#b"/>
+    <linearGradient id="w" x1="64.3" x2="198.99" y1="30.71" y2="165.41" href="#b"/>
+    <linearGradient id="x" x1="65.73" x2="200.43" y1="29.27" y2="163.97" href="#b"/>
+  </defs>
+  <path fill="none" d="M180.15 34.4c-0.13 -0.34 -3.24 -8.16 -11.05 -7.09 -2.38 0.32 -4 1.25 -4.84 2.76a5.21 5.21 0 0 0 -0.51 1.36 6.79 6.79 0 0 1 4.85 -2.43c8.3 -1.13 11.59 7.4 11.59 7.4a6.23 6.23 0 0 1 0.72 -1.76 0.52 0.52 0 0 1 -0.25 0.11 0.51 0.51 0 0 1 -0.51 -0.35zm-9.99 93.38h0.14a0.44 0.44 0 0 1 0.13 -0.42 1.89 1.89 0 0 1 1.56 -0.62 1.23 1.23 0 0 1 0.47 0.22 1 1 0 0 0 0.32 -0.71c0 -0.83 -1.18 -1.53 -2.59 -1.54a1.39 1.39 0 0 1 0.09 0.5 1.5 1.5 0 0 1 -1.5 1.5 1.46 1.46 0 0 1 -0.66 -0.16 3.3 3.3 0 0 1 -0.43 0.19 2.93 2.93 0 0 0 2.47 1.04zm-3.48 -0.85h-0.27a3.88 3.88 0 0 1 -1.85 -0.47 17.88 17.88 0 0 1 -2.79 0.91 59.25 59.25 0 0 1 -2.77 7.83c-1.58 3.17 -4 6.33 -7.25 7.5a4.78 4.78 0 0 1 -4.52 -0.93c-0.25 1.62 -0.52 3.2 -0.79 4.72a62 62 0 0 0 3 6.08h13.58a59 59 0 0 0 3.45 -8.46 134.51 134.51 0 0 0 4 -15.34h-0.25a3.59 3.59 0 0 1 -3.54 -1.84zm-41.39 46.13a44.59 44.59 0 0 1 -0.26 -5.28c-4.57 0.43 -9.18 0.54 -12.7 0.54 -5.07 0 -10.14 -0.22 -14.61 -0.64a44.77 44.77 0 0 1 -0.27 5.46c4.48 -0.29 9.4 -0.45 14.57 -0.45 4.67 0 9.15 0.13 13.27 0.37zm30.87 -13.86c1.86 0 3.76 -1.58 5.65 -4.63h-11.24c1.79 2.7 3.72 4.63 5.59 4.63z"/>
+  <path fill="#eeeef2" d="M154 76.58h47.63a1 1 0 0 0 0 -2h-47.7a13.9 13.9 0 0 1 0.07 1.42v0.58z"/>
+  <path fill="#fff" d="M36.45 14.11a19.76 19.76 0 0 0 0.54 6h0.95a25.42 25.42 0 0 1 -1.49 -6z"/>
+  <path fill="#eeeef2" d="M157.67 69a0.5 0.5 0 0 0 0 1h33.63a0.5 0.5 0 0 0 0 -1zm-118.56 -48.13a0.51 0.51 0 0 0 0 -0.48c0 -0.06 -2.29 -5.24 -1.69 -10.21a10.4 10.4 0 0 1 1.17 -3.83c1.57 -2.83 4.6 -4.57 9 -5.17 14.41 -1.96 20.28 12.82 20.34 13a0.51 0.51 0 0 0 0.5 0.32 0.49 0.49 0 0 0 0.45 -0.4c0.12 -0.34 1.79 -8.35 10.12 -6.77s14.81 14.08 14.87 14.2a0.5 0.5 0 0 0 0.45 0.27h22a0.5 0.5 0 0 0 0.5 -0.5 0.5 0.5 0 0 0 -0.5 -0.5h-21.74c-1 -1.93 -7.15 -12.87 -15.44 -14.45 -7.14 -1.35 -9.91 3.75 -10.84 6.25 -1.82 -3.6 -8.21 -14.13 -20.82 -12.41 -4.72 0.64 -8 2.55 -9.73 5.67a13.77 13.77 0 0 0 -1.3 8.25 25.42 25.42 0 0 0 1.49 6h-24.47a0.5 0.5 0 0 0 -0.5 0.5 0.51 0.51 0 0 0 0.5 0.5h25.22a0.5 0.5 0 0 0 0.42 -0.24zm182.11 60.33h-68.31a13.196 13.196 0 0 1 -0.49 1h68.8a0.5 0.5 0 0 0 0.5 -0.5 0.5 0.5 0 0 0 -0.5 -0.5z"/>
+  <path fill="#fff" d="M13 26.2h104a1 1 0 0 0 0 -2h-24.1c-2.09 -3.88 -7.5 -12.62 -14.28 -13.91 -8.89 -1.69 -10.62 7.16 -10.62 7.16s-5.94 -15.35 -20.88 -13.31c-5.5 0.74 -8.33 3.15 -9.67 6 -0.6 5 1.67 10.15 1.69 10.21a0.5 0.5 0 0 1 -0.45 0.71h-1.45a22.73 22.73 0 0 0 1 2.95h-25.24l7.72 0.15h-7.72a1 1 0 1 0 0 2z"/>
+  <path fill="#eeeef2" d="M73.39 59.8a1 1 0 0 0 -1 -1h-39.83a1 1 0 0 0 0 2h39.83a1 1 0 0 0 1 -1zm-20.39 -4.87a0.5 0.5 0 0 0 0.5 -0.5 0.51 0.51 0 0 0 -0.5 -0.5h-11.3a0.5 0.5 0 0 0 -0.5 0.5 0.5 0.5 0 0 0 0.5 0.5zm6.33 56.77h-58.33a1 1 0 0 0 0 2h55.76a6.27 6.27 0 0 1 2.57 -2zm5.61 0h-0.74l0.39 0.16zm66.18 67.3a5.8 5.8 0 0 1 -3.66 -1.3c-1.18 -1 -1.84 -2.11 -2.17 -4.61 -4.12 -0.24 -8.6 -0.37 -13.27 -0.37 -5.17 0 -10.09 0.16 -14.57 0.45 -0.33 2.44 -1 3.58 -2.16 4.53a5.8 5.8 0 0 1 -3.66 1.3c-2.81 0 -5.08 -2 -6.84 -4.5 -6.35 1 -10.26 2.4 -10.26 3.91 0 3.15 16.78 5.7 37.49 5.7s37.49 -2.55 37.49 -5.7c0 -1.6 -4.39 -3 -11.43 -4.09 -1.77 2.56 -4.08 4.68 -6.96 4.68z"/>
+  <path fill="#fff" d="M147.18 141.77a4.78 4.78 0 0 0 4.52 0.93c3.25 -1.17 5.67 -4.33 7.25 -7.5a59.25 59.25 0 0 0 2.82 -7.81l-1.08 0.23a9 9 0 0 1 -2.51 0.55c-1.41 4.26 -4.32 11 -8.41 11a3.93 3.93 0 0 1 -1.9 -0.5l-0.23 0.11c-0.15 1.03 -0.3 2.02 -0.46 2.99z"/>
+  <path fill="#eeeef2" d="M29.08 107.44a0.5 0.5 0 0 0 0.5 0.5h38.49a0.5 0.5 0 0 0 0.5 -0.5 0.5 0.5 0 0 0 -0.5 -0.5h-38.49a0.5 0.5 0 0 0 -0.5 0.5z"/>
+  <path fill="#fff" d="M154 76.58v-0.56a13.9 13.9 0 0 0 -0.08 -1.44 12.73 12.73 0 0 0 -12.67 -11.31 12.58 12.58 0 0 0 -5.4 1.2l-1 2a16.24 16.24 0 0 1 1.27 1.1 9.76 9.76 0 0 1 11.75 15.36l-1.47 1.47c0.45 4 0.72 8.27 0.82 12.83a17.86 17.86 0 0 1 3.21 -1.66q-0.16 -5.3 -0.65 -10.07l0.46 -0.45a13.32 13.32 0 0 0 2.14 -2.84 13.196 13.196 0 0 0 0.49 -1 12.75 12.75 0 0 0 1.13 -4.63zm-80.63 44.29c-0.82 -1.14 -1.69 -2.27 -2.49 -3.19 0.84 1.19 1.75 2.57 2.56 3.7zm-11.13 -4.46a1.34 1.34 0 0 0 -0.72 -0.21h-0.1a4.16 4.16 0 0 1 0.91 0.26z"/>
+  <path fill="#fff" d="M141.43 154.62a62.66 62.66 0 0 1 -2.28 9.84c-1.22 3.46 -4.45 11.51 -8.28 11.51a2.8 2.8 0 0 1 -1.76 -0.62c-0.84 -0.68 -1.45 -1.18 -1.3 -10.93a122.38 122.38 0 0 1 -15.73 0.9 149.39 149.39 0 0 1 -17.65 -1c0.16 9.83 -0.48 10.35 -1.29 11a2.75 2.75 0 0 1 -1.76 0.63c-3.83 0 -7.06 -8.05 -8.28 -11.51a48.37 48.37 0 0 1 -1.54 -5.85c-1.94 -3.93 -3.47 -11.43 -4.55 -22.3a4.56 4.56 0 0 1 -3.01 -2.6c-1.14 -1.61 -3.87 -6.58 -5.28 -9.2l-1.94 0.49a7.76 7.76 0 0 1 -1.82 0.23 5.79 5.79 0 0 1 -4.12 -1.62l-2.56 -0.65a3.3 3.3 0 0 1 0.14 -6.42 3 3 0 0 1 0.41 -0.85 3.27 3.27 0 0 1 2.74 -1.47 3.33 3.33 0 0 1 1.83 0.55l0.94 0.63c2.54 -1.67 3.7 -1.67 4.11 -1.67a3.81 3.81 0 0 1 2.75 1.36l-0.34 -2.38a4.53 4.53 0 0 1 0 -1 4.62 4.62 0 0 1 0.1 -1.24 4.56 4.56 0 0 1 4.47 -3.54h0.17a202.19 202.19 0 0 1 0.74 -21.55l-2.9 -2.89a9.76 9.76 0 0 1 13.8 -13.8l1.75 1.75c2.26 -0.65 5 -1.44 7.74 -2.17a7.74 7.74 0 0 1 0.12 -1.07 7.1 7.1 0 0 1 0.79 -2.18c-2.43 0.64 -5.08 1.38 -7.6 2.1l-0.5 -0.5a12.76 12.76 0 0 0 -18 18l1.89 1.89c-0.41 4.63 -0.63 10.9 -0.63 18a7.55 7.55 0 0 0 -4.54 5.32 7.65 7.65 0 0 0 -0.15 0.94 8.93 8.93 0 0 0 -3.13 1l-0.35 0.16 -0.39 -0.16a6.15 6.15 0 0 0 -2.43 -0.5 6.32 6.32 0 0 0 -5 2.5c-0.07 0.1 -0.16 0.2 -0.23 0.31a0.57 0.57 0 0 0 -0.08 0.13 6.28 6.28 0 0 0 -3.25 4c-0.42 1.63 -0.53 4.06 0.33 5.51s2.38 4.08 4 4.5c1.55 1.21 5.5 1.25 7.63 0 0.63 -0.37 1.48 -0.08 2.23 -0.25 1.58 2.89 3.18 5.72 4.18 7.2a7.54 7.54 0 0 0 2.89 3.18c1.08 10 2.58 17.13 4.49 21.23a46 46 0 0 0 1.57 5.88 38.53 38.53 0 0 0 4.27 9c1.76 2.51 4 4.5 6.84 4.5a5.8 5.8 0 0 0 3.66 -1.3c1.17 -0.95 1.83 -2.09 2.16 -4.53a44.77 44.77 0 0 0 0.27 -5.46c4.47 0.42 9.54 0.64 14.61 0.64 3.52 0 8.13 -0.11 12.7 -0.54a44.59 44.59 0 0 0 0.26 5.28c0.33 2.5 1 3.65 2.17 4.61a5.8 5.8 0 0 0 3.66 1.3c2.88 0 5.19 -2.09 7 -4.68a38.86 38.86 0 0 0 4.15 -8.84 64.69 64.69 0 0 0 2.39 -10.24c0.48 -2 1 -4.4 1.45 -7 -1 -2.17 -1.76 -4.21 -2.3 -5.72 -0.86 4.65 -1.64 8.84 -2.43 12.16z"/>
+  <path fill="#fff" d="M58.93 118.47a1.27 1.27 0 0 0 -1.06 0.8 1.88 1.88 0 0 1 0.41 -0.32 3.43 3.43 0 0 0 0.65 -0.48zm85.46 -34.86l0.31 -0.31 -0.32 0.27zm-52.14 88.84a84.62 84.62 0 0 0 0.16 -9.43h-0.09c0.09 3.65 0.1 7.24 -0.07 9.43zm37.62 -9.51c0 2.2 -0.06 4.33 0 6.12 -0.08 -1.83 -0.05 -3.96 0 -6.12zm17.77 -24.13l0.23 -0.11a7.76 7.76 0 0 1 -3 -3.63 268.89 268.89 0 0 1 -0.79 5.4 76.1 76.1 0 0 0 2.29 6c0.27 -1.52 0.54 -3.1 0.79 -4.72 0.18 -0.95 0.33 -1.94 0.48 -2.94zm-4.52 -4.87c0.07 -0.69 0.15 -1.36 0.22 -2q-0.14 1.08 -0.27 2.13zm15.15 -6.03l-0.09 0.26a9 9 0 0 0 2.51 -0.55 20.79 20.79 0 0 1 -2.42 0.29zm4.39 -93.4a10.76 10.76 0 0 0 0.2 2.88h0.51a14.66 14.66 0 0 1 -0.71 -2.88z"/>
+  <path fill="#eeeef2" d="M164.52 38.16a0.51 0.51 0 0 0 0 -0.48 11.53 11.53 0 0 1 -0.81 -6.25 5.21 5.21 0 0 1 0.51 -1.36c0.84 -1.51 2.46 -2.44 4.84 -2.76 7.81 -1.07 10.92 6.75 11.05 7.09a0.51 0.51 0 0 0 0.51 0.32 0.52 0.52 0 0 0 0.25 -0.11 0.5 0.5 0 0 0 0.2 -0.29 4.39 4.39 0 0 1 5.33 -3.56c4.58 0.87 8.09 7.15 8.13 7.21a0.48 0.48 0 0 0 0.43 0.26h12.21a0.5 0.5 0 0 0 0.5 -0.5 0.5 0.5 0 0 0 -0.5 -0.5h-11.87c-0.74 -1.26 -4.12 -6.59 -8.66 -7.46a5.18 5.18 0 0 0 -6.1 3.17c-1.27 -2.35 -4.87 -7.5 -11.58 -6.59 -2.7 0.36 -4.58 1.46 -5.58 3.26a8.09 8.09 0 0 0 -0.72 4.93 14.66 14.66 0 0 0 0.71 2.88h-13.29a0.5 0.5 0 0 0 -0.5 0.5 0.5 0.5 0 0 0 0.5 0.5h14a0.5 0.5 0 0 0 0.44 -0.26z"/>
+  <path fill="#fff" d="M149.9 42.22h57.8a1 1 0 0 0 0 -2h-13.59c-1.13 -2.1 -4.16 -7.1 -8 -7.83a4.55 4.55 0 0 0 -5 1.9 0.5 0.5 0 0 1 -0.2 0.29 6.23 6.23 0 0 0 -0.72 1.76s-3.29 -8.5 -11.59 -7.34a6.79 6.79 0 0 0 -4.85 2.46 11.53 11.53 0 0 0 0.81 6.25 0.51 0.51 0 0 1 0 0.48 0.5 0.5 0 0 1 -0.42 0.23h-1a14 14 0 0 0 0.57 1.65h-14l9 0.18h-8.81a1 1 0 0 0 0 2zm-53.24 26.05c1.09 -0.3 2.16 -0.58 3.17 -0.84 0.65 -2.25 3.25 -3.8 7 -4.48l-0.79 -13.75a2.1 2.1 0 0 1 0 -0.66v-0.28a0.76 0.76 0 0 1 0.06 -0.16v-0.06c1 -3.36 9 -3.66 16.64 -2.19a38.87 38.87 0 0 1 10.41 3.42c3.88 2 4.43 3.89 4.2 5.06a2.48 2.48 0 0 1 -0.45 1l-5.88 12.17c0.22 0.13 0.46 0.27 0.67 0.41a15.76 15.76 0 0 1 2 1.55l0.34 -0.35a9.92 9.92 0 0 1 2 -1.56 16.24 16.24 0 0 0 -1.27 -1.1l1 -2 3.71 -7.67a5.25 5.25 0 0 0 0.76 -1.88 2.56 2.56 0 0 0 0.06 -0.57c0.62 -7.59 -14.08 -10.83 -17.05 -11.41a41.83 41.83 0 0 0 -11.81 -0.75c-6.2 0.64 -8 3.37 -8.42 5.54a5.49 5.49 0 0 0 0 2l0.64 10.93c-3.42 1.07 -5.2 2.77 -6.11 4.33a7.1 7.1 0 0 0 -0.86 2.23 7.74 7.74 0 0 0 -0.02 1.07z"/>
+  <path fill="#eeeef2" d="M72.38 152.57h-66.88a1 1 0 0 0 0 2h66.88a1 1 0 0 0 0 -2zm78.19 2h11.24a32.566 32.566 0 0 0 1.12 -2h-13.58c0.4 0.7 0.81 1.37 1.22 2zm65.18 0a1 1 0 0 0 0 -2h-51.75a33.88 33.88 0 0 1 -1.1 2zm-67.95 -1a1 1 0 0 0 1 1h0.58a40.557 40.557 0 0 1 -1.09 -1.84 1 1 0 0 0 -0.49 0.84z"/>
+  <path fill="url(#a)" d="M87.76 79.65a45.87 45.87 0 0 1 14.58 -6.38 7.65 7.65 0 0 1 -2.56 -3.76c-3.25 0.84 -7 1.9 -9.88 2.73a0.47 0.47 0 0 1 -0.25 0.18c-5.3 1.52 -6.41 5.17 -6.45 5.32a0.51 0.51 0 0 1 -0.48 0.36h-0.14a0.5 0.5 0 0 1 -0.34 -0.62c0 -0.16 1 -3.51 5.47 -5.41l-2 -2a7.75 7.75 0 0 0 -11 11l3.57 3.58a202.84 202.84 0 0 0 -0.82 23.9 2.91 2.91 0 0 0 2.65 1.38 5.08 5.08 0 0 0 2.89 -1.65c-0.43 -13.72 0.78 -25.99 4.76 -28.63z"/>
+  <path fill="url(#c)" d="M138.33 82.24a76.63 76.63 0 0 1 2.48 19.86 2.32 2.32 0 0 0 0.46 -0.54 3 3 0 0 0 0.25 -0.78 2.33 2.33 0 0 0 0 -0.83 1 1 0 0 1 0.72 -1.19 1.15 1.15 0 0 1 0.26 0 1 1 0 0 1 1 0.72 3.52 3.52 0 0 1 0.1 0.86c0.39 -0.4 0.79 -0.8 1.22 -1.19l0.52 -0.43a145.32 145.32 0 0 0 -0.95 -15l0.32 -0.27 1.79 -1.8a7.75 7.75 0 1 0 -11 -11l-0.4 0.4a6.7 6.7 0 0 1 0.77 1.25 12.86 12.86 0 0 1 6 5.68 0.51 0.51 0 0 1 -0.2 0.68 0.53 0.53 0 0 1 -0.24 0.06 0.49 0.49 0 0 1 -0.44 -0.26 12.09 12.09 0 0 0 -4.72 -4.84 4.08 4.08 0 0 1 0 1.35 4.61 4.61 0 0 1 -1.91 2.79c2.12 1.37 3.52 2.97 3.97 4.48z"/>
+  <path fill="#f2f8ff" d="M101.53 100.7a7.5 7.5 0 1 0 -7.53 -7.5 7.51 7.51 0 0 0 7.53 7.5zm-1.16 -9.81l1.63 -2.66a1.38 1.38 0 0 1 1.93 -0.44 1.4 1.4 0 0 1 0.44 1.93l-1.66 2.66a1.4 1.4 0 0 1 -2.38 -1.49zm-3.05 4.43a1 1 0 0 1 1.38 0.29 3.65 3.65 0 0 0 5.88 0 1 1 0 0 1 1.68 1.09 5.64 5.64 0 0 1 -9.23 0 1 1 0 0 1 0.29 -1.38z"/>
+  <path fill="#f2f8ff" d="M85.07 115.26c1.79 1.61 0.31 3.63 -1.31 6.21 1.29 14 3.84 26.85 6.42 30 9.77 12 39.38 11 45.06 -2.26 0.58 -1.38 4.27 -18.23 5.31 -36.28l-0.09 -0.08c-1.58 -1.77 -1.57 -4.61 -0.28 -7.58 -2.81 1.59 -7.3 2.4 -13.43 2.4h-1.7a2.34 2.34 0 0 1 -0.25 0.3c-7.4 7.17 -13.45 10.81 -18 10.81a7.05 7.05 0 0 1 -2.48 -0.43 4.84 4.84 0 0 1 -1.45 -0.81 4.31 4.31 0 0 1 -1.28 -1.47 1 1 0 0 1 1.76 -0.94 3.35 3.35 0 0 0 0.75 0.84 3.93 3.93 0 0 0 0.9 0.5 2.91 2.91 0 0 0 0.89 0.14 4.2 4.2 0 0 0 1.81 -0.47c1.9 -0.92 2.72 -2.9 3.67 -5.18a20.6 20.6 0 0 1 2.87 -5.27c2.18 -2.64 4.35 -4 6.44 -4a4.42 4.42 0 0 1 2.26 0.6c0.71 -1.32 2.28 -2.36 5.08 -2.36a13.29 13.29 0 0 1 1.93 0.14 16.6 16.6 0 0 1 4.69 1.59 10 10 0 0 0 3.88 1.22 3.84 3.84 0 0 0 1.07 -0.15 3.35 3.35 0 0 0 1.22 -0.65 76.63 76.63 0 0 0 -2.48 -19.86c-0.45 -1.51 -1.85 -3.11 -4 -4.59a12 12 0 0 1 -4.9 1.94 27.09 27.09 0 0 1 -5.19 0.46 41 41 0 0 1 -7.82 -0.79c-6.19 -1.2 -11.22 -3.43 -14.12 -6a45.87 45.87 0 0 0 -14.58 6.38c-4 2.64 -5.19 14.91 -4.81 28.63 3.37 -3.25 6.65 -10.76 8.09 -14.69a1.87 1.87 0 1 1 2.38 -2.87 8.53 8.53 0 1 1 -0.35 3 1.83 1.83 0 0 1 -0.9 0.24h-0.2c-1.07 2.83 -4.79 12.13 -9 15.65 0 1.08 0.09 2.16 0.14 3.25a10.17 10.17 0 0 0 2 2.43zm21.37 8.09a2.5 2.5 0 0 1 1.4 -1.8 4.18 4.18 0 0 1 3.5 -0.2 6.75 6.75 0 0 1 2.89 2.6 1.75 1.75 0 0 1 0.45 -0.55c1.18 -0.88 4.2 -1 5.1 -1a1 1 0 0 1 0.5 0.13l0.08 0.06a6.78 6.78 0 0 1 3.38 -2.33 4.31 4.31 0 0 1 3.45 0.65 2.63 2.63 0 0 1 1.28 2 5.41 5.41 0 0 1 -1.49 3.61c0.9 1.15 2.35 3.32 2 5.07a2.48 2.48 0 0 1 -1.4 1.8h-0.07c0.08 1.66 -0.15 3.57 -1.47 4.16 -2.5 1.11 -4.44 -2.77 -4.44 -2.77a13.26 13.26 0 0 1 -2.21 1.1c-1.39 0.56 -3.88 -0.55 -3.88 -0.55s-1.94 3.05 -4.71 2.77c-1.56 -0.15 -2 -2.13 -2 -3.84a7.105 7.105 0 0 1 -0.53 -0.3 2.67 2.67 0 0 1 -1.28 -2 5.44 5.44 0 0 1 1.5 -3.62c-0.93 -1.06 -2.39 -3.24 -2.05 -4.99zm26 -32.21l1.67 -2.66a1.38 1.38 0 0 1 1.93 -0.44 1.4 1.4 0 0 1 0.44 1.93l-1.66 2.66a1.4 1.4 0 0 1 -2.38 -1.49zm-3.05 4.43a1 1 0 0 1 1.38 0.29 3.72 3.72 0 0 0 2.94 1.49 3.66 3.66 0 0 0 2.94 -1.5 1 1 0 0 1 1.68 1.1 5.64 5.64 0 0 1 -9.23 0 1 1 0 0 1 0.32 -1.38zm-14.24 -0.83c3 -3.23 10 -4.76 12.31 -4.28a1.74 1.74 0 0 1 1.43 1.08 2.86 2.86 0 0 1 -0.33 2.43c-1.17 2.11 -4.76 4.78 -6.11 5.06a1.24 1.24 0 0 1 -0.31 0c-1.51 0 -6.38 -1 -7.2 -2.5a1.52 1.52 0 0 1 0.24 -1.79z"/>
+  <path fill="url(#b)" d="M100.82 92.82a1.41 1.41 0 0 0 1.93 -0.44l1.66 -2.66a1.4 1.4 0 0 0 -0.44 -1.93 1.38 1.38 0 0 0 -1.93 0.44l-1.67 2.66a1.4 1.4 0 0 0 0.45 1.93z"/>
+  <path fill="url(#d)" d="M101.64 99.1a5.71 5.71 0 0 0 4.62 -2.4 1 1 0 0 0 -1.68 -1.09 3.65 3.65 0 0 1 -5.88 0 1 1 0 1 0 -1.7 1.09 5.68 5.68 0 0 0 4.64 2.4z"/>
+  <path fill="url(#e)" d="M143.28 119a6.57 6.57 0 0 1 1.45 -4v-0.43a5.54 5.54 0 0 1 -4.2 -1.57c-1 18 -4.73 34.9 -5.31 36.28 -5.68 13.26 -35.29 14.24 -45.06 2.26 -2.58 -3.17 -5.13 -16 -6.42 -30 1.62 -2.58 3.1 -4.6 1.31 -6.21a10.17 10.17 0 0 1 -1.94 -2.43c0 -1.09 -0.1 -2.17 -0.14 -3.25a5.29 5.29 0 0 1 -2.67 1.34 3.11 3.11 0 0 1 -0.43 0 4 4 0 0 1 -3.12 -1.77l-0.75 -0.22a3 3 0 0 0 -0.59 -0.06 2.59 2.59 0 0 0 -2.52 2 2.53 2.53 0 0 0 0 0.82 2.5 2.5 0 0 0 0 0.67l1.26 9.57a57.556 57.556 0 0 0 -0.78 -1.1l0.07 0.51c-0.81 -1.13 -1.72 -2.51 -2.56 -3.7 -1 -1.16 -1.92 -2 -2.48 -2 -0.93 0 -2.59 1 -4.08 2.09l-2 -1.33a4.16 4.16 0 0 0 -0.91 -0.26 1.27 1.27 0 0 0 -1 0.56 1.29 1.29 0 0 0 0.35 1.79l0.74 0.49 -2.18 -0.55a1.17 1.17 0 0 0 -0.32 0h-0.11a3.43 3.43 0 0 1 -0.65 0.48 1.88 1.88 0 0 0 -0.41 0.32 0.8 0.8 0 0 0 -0.08 0.16 1.29 1.29 0 0 0 0.93 1.57l3.13 0.8a3.85 3.85 0 0 0 3.06 1.41 5.53 5.53 0 0 0 1.34 -0.17l3.45 -0.87s4.91 9.19 6 10.54a2.6 2.6 0 0 0 2.44 1.74 2.36 2.36 0 0 0 0.37 0l0.31 -0.08v0.34c1.54 -2.55 0 -13 -0.69 -16.85a0.5 0.5 0 0 1 0.85 -0.44l1.78 1.78a0.5 0.5 0 0 1 0 0.71 0.51 0.51 0 0 1 -0.71 0l-0.66 -0.66c0.67 4 2.06 13.82 0.1 16.29a1.79 1.79 0 0 1 -0.45 0.43c1 9.77 2.44 18 4.48 22a46 46 0 0 0 1.52 5.8c2.29 6.53 4.93 10.17 6.39 10.17a0.75 0.75 0 0 0 0.5 -0.18 2.63 2.63 0 0 0 0.37 -1.34c0.17 -2.19 0.16 -5.78 0.07 -9.46a18.09 18.09 0 0 1 -4.91 -2.74 0.5 0.5 0 0 1 -0.08 -0.7 0.51 0.51 0 0 1 0.71 -0.08 16.67 16.67 0 0 0 4.82 2.64 141.89 141.89 0 0 0 19.22 1.21 117.14 117.14 0 0 0 16 -1c2.25 -0.5 6.8 -2 6.85 -2.06a0.5 0.5 0 0 1 0.63 0.32 0.5 0.5 0 0 1 -0.31 0.63c-0.15 0 -3.08 1 -5.42 1.7 -0.05 2.16 -0.08 4.29 -0.06 6.12 0.05 2.59 0.21 4.45 0.56 4.73a0.75 0.75 0 0 0 0.5 0.18c1.46 0 4.1 -3.64 6.39 -10.17a62.11 62.11 0 0 0 2.21 -9.58c1.06 -4.47 2.4 -11.63 3.53 -20.14s0 0 0.06 -0.05q0.13 -1 0.27 -2.13a359.26 359.26 0 0 0 0.88 -9.7 6.32 6.32 0 0 1 -0.9 -3.17z"/>
+  <path fill="url(#f)" d="M122.17 99.06a1.24 1.24 0 0 0 0.31 0c1.35 -0.28 4.94 -3 6.11 -5.06a2.86 2.86 0 0 0 0.33 -2.43 1.74 1.74 0 0 0 -1.43 -1.08c-2.32 -0.48 -9.28 1.05 -12.31 4.28a1.52 1.52 0 0 0 -0.21 1.82c0.82 1.41 5.69 2.47 7.2 2.47z"/>
+  <path fill="url(#g)" d="M144.71 128.26a0.1 0.1 0 0 1 0.07 -0.06s0.06 0 0 0c1.56 6.7 3.31 9 5 9 2.71 0 5.22 -6 6.36 -9.28a19.57 19.57 0 0 1 -4.07 -0.59 3.12 3.12 0 0 1 -1.31 1.3 1.5 1.5 0 0 1 -0.55 0.11 1.31 1.31 0 0 1 -0.61 -0.15c-0.3 -0.15 -0.94 -0.47 -1.13 -2.61a11.46 11.46 0 0 1 -3.33 -2.54c-0.14 1.56 -0.28 3.15 -0.43 4.82z"/>
+  <path fill="url(#h)" d="M146.44 84.39l1.47 -1.47a9.76 9.76 0 0 0 -11.75 -15.36 9.92 9.92 0 0 0 -2 1.56l-0.34 0.35a15.76 15.76 0 0 0 -2 -1.55c-0.21 -0.14 -0.45 -0.28 -0.67 -0.41l5.88 -12.17a2.48 2.48 0 0 0 0.45 -1c0.23 -1.17 -0.32 -3 -4.2 -5.06a38.87 38.87 0 0 0 -10.41 -3.42c-7.61 -1.47 -15.64 -1.17 -16.64 2.19v0.06a0.76 0.76 0 0 0 -0.06 0.16v0.28a2.1 2.1 0 0 0 0 0.66l0.71 13.79c-3.8 0.68 -6.4 2.23 -7 4.48 -1 0.26 -2.08 0.54 -3.17 0.84 -2.69 0.73 -5.48 1.52 -7.74 2.17l-1.75 -1.75a9.76 9.76 0 0 0 -13.8 13.8l2.9 2.89a202.19 202.19 0 0 0 -0.74 21.55h-0.17a4.56 4.56 0 0 0 -4.47 3.54 4.62 4.62 0 0 0 -0.1 1.24 4.53 4.53 0 0 0 0 1l0.34 2.38a3.81 3.81 0 0 0 -2.75 -1.36c-0.41 0 -1.57 0 -4.11 1.67l-0.94 -0.63a3.33 3.33 0 0 0 -1.83 -0.55 3.27 3.27 0 0 0 -2.74 1.47 3 3 0 0 0 -0.41 0.85 3.3 3.3 0 0 0 -0.14 6.42l2.56 0.65a5.79 5.79 0 0 0 4.12 1.62 7.76 7.76 0 0 0 1.82 -0.23l1.94 -0.49c1.41 2.62 4.14 7.59 5.28 9.2a4.56 4.56 0 0 0 3.02 2.55c1.08 10.87 2.61 18.37 4.55 22.3a48.37 48.37 0 0 0 1.54 5.85c1.22 3.46 4.45 11.51 8.28 11.51a2.75 2.75 0 0 0 1.76 -0.63c0.81 -0.65 1.45 -1.17 1.29 -11a149.39 149.39 0 0 0 17.65 1 122.38 122.38 0 0 0 15.73 -0.9c-0.15 9.75 0.46 10.25 1.3 10.93a2.8 2.8 0 0 0 1.76 0.62c3.83 0 7.06 -8.05 8.28 -11.51a62.66 62.66 0 0 0 2.28 -9.84c0.79 -3.32 1.6 -7.51 2.34 -12.08 0.54 1.51 1.33 3.55 2.3 5.72 0.66 1.48 1.41 3 2.22 4.47 0.35 0.63 0.72 1.25 1.09 1.84 2 3.18 4.36 5.63 6.78 5.63s4.81 -2.29 6.78 -5.63a33.88 33.88 0 0 0 1.1 -2c4.15 -8.25 6.75 -20.56 7.27 -23.19a2.75 2.75 0 0 0 0.59 -0.07 1.45 1.45 0 0 0 1 -0.64 1.14 1.14 0 0 0 0 -0.84 2.1 2.1 0 0 0 0.8 -1.59c0 -1.42 -1.59 -2.54 -3.62 -2.54h-0.42a2.4 2.4 0 0 0 -0.31 -0.91 6.5 6.5 0 0 0 1.35 -3.87c0 -5 -6.15 -9 -13.75 -9a21.93 21.93 0 0 0 -2.45 0.15c5.09 -4.56 7 -10.71 4.3 -13.74 -1.74 -1.95 -5 -2.12 -8.42 -0.79a17.86 17.86 0 0 0 -3.21 1.66c0 -4.56 -0.27 -8.85 -0.72 -12.83zm-16.95 -18.24a28.52 28.52 0 0 1 -11.17 -0.86 52.63 52.63 0 0 1 -9.52 -3.84l-0.54 -9.39c2.7 2 7.5 3.73 12.41 4.68a44 44 0 0 0 8.2 0.85 26 26 0 0 0 2.73 -0.13 14.94 14.94 0 0 0 2.29 -0.4zm-0.2 1l-2 4.57a22.43 22.43 0 0 1 -10.15 -0.25 23.77 23.77 0 0 1 -8.5 -4v-5a53.39 53.39 0 0 0 9.34 3.72 29.54 29.54 0 0 0 11.31 1zm-14.63 -20.15a41.36 41.36 0 0 1 7.74 0.81 36.94 36.94 0 0 1 9.85 3.19c2.69 1.42 3.25 2.52 3.18 2.91s-1 1.21 -4 1.52a36.81 36.81 0 0 1 -10.34 -0.69c-8.86 -1.72 -13.25 -5 -13 -6.14 0.09 -0.74 2.44 -1.6 6.57 -1.6zm-13 21.15c0.27 -1.41 2.23 -2.58 5.31 -3.17l0.17 2.84a1.26 1.26 0 0 0 0.12 0.48c0.56 1.08 5 4.13 10.37 5.12a30.8 30.8 0 0 0 5.62 0.58c3.47 0 4.8 -0.87 5 -1a0.93 0.93 0 0 0 0.31 -0.37l1.6 -3.31 0.47 0.28c2.6 1.69 3.94 3.47 3.67 4.89s-2.18 2.56 -5.23 3.15a33.5 33.5 0 0 1 -12.25 -0.33c-9.59 -1.87 -15.68 -6.31 -15.13 -9.16zm41.65 63.75c-0.07 0.68 -0.15 1.35 -0.22 2l-0.05 0.09s0 0.05 -0.06 0.05c-1.13 8.51 -2.47 15.67 -3.53 20.14a62.11 62.11 0 0 1 -2.21 9.58c-2.24 6.57 -4.91 10.24 -6.37 10.24a0.75 0.75 0 0 1 -0.5 -0.18c-0.35 -0.28 -0.51 -2.14 -0.56 -4.73v-6.12c2.34 -0.65 5.27 -1.65 5.42 -1.7a0.5 0.5 0 0 0 0.31 -0.63 0.5 0.5 0 0 0 -0.63 -0.32c-0.05 0 -4.6 1.56 -6.85 2.06a117.14 117.14 0 0 1 -16 1 141.89 141.89 0 0 1 -19.22 -1.21 16.67 16.67 0 0 1 -4.84 -2.7 0.51 0.51 0 0 0 -0.71 0.08 0.5 0.5 0 0 0 0.08 0.7 18.09 18.09 0 0 0 4.95 2.75h0.09a84.62 84.62 0 0 1 -0.16 9.43 2.63 2.63 0 0 1 -0.37 1.34 0.75 0.75 0 0 1 -0.5 0.18c-1.46 0 -4.1 -3.64 -6.39 -10.17a46 46 0 0 1 -1.52 -5.78c-2 -3.93 -3.51 -12.2 -4.48 -22a1.79 1.79 0 0 0 0.54 -0.46c2 -2.47 0.57 -12.3 -0.1 -16.29l0.66 0.66a0.51 0.51 0 0 0 0.71 0 0.5 0.5 0 0 0 0 -0.71l-1.8 -1.8a0.5 0.5 0 0 0 -0.85 0.44c0.73 3.9 2.23 14.3 0.69 16.85v-0.34l-0.31 0.08a2.36 2.36 0 0 1 -0.37 0 2.6 2.6 0 0 1 -2.44 -1.74c-1.1 -1.35 -6 -10.54 -6 -10.54l-3.45 0.87a5.53 5.53 0 0 1 -1.34 0.17 3.85 3.85 0 0 1 -3.06 -1.41l-3.13 -0.8a1.29 1.29 0 0 1 -0.93 -1.57 0.8 0.8 0 0 1 0.08 -0.16 1.27 1.27 0 0 1 1.06 -0.8h0.05a1.17 1.17 0 0 1 0.32 0l2.18 0.55 -0.74 -0.49a1.29 1.29 0 0 1 -0.35 -1.79 1.27 1.27 0 0 1 1 -0.56h0.1a1.34 1.34 0 0 1 0.72 0.21l0.09 0.06 2 1.33c1.49 -1.1 3.15 -2.09 4.08 -2.09 0.56 0 1.47 0.81 2.48 2 0.8 0.92 1.67 2 2.49 3.19 0.27 0.37 0.53 0.74 0.78 1.1l-1.36 -9.56a2.5 2.5 0 0 1 0 -0.67 2.53 2.53 0 0 1 0 -0.82 2.59 2.59 0 0 1 2.52 -2 3 3 0 0 1 0.69 0.09l0.82 0.19a4 4 0 0 0 3.07 1.81 3.11 3.11 0 0 0 0.43 0 5.29 5.29 0 0 0 2.68 -1.42c4.18 -3.52 7.9 -12.82 9 -15.65h0.2a1.83 1.83 0 0 0 0.9 -0.24 8.46 8.46 0 1 0 0.35 -3 1.87 1.87 0 1 0 -2.45 2.87c-1.44 3.93 -4.72 11.44 -8 14.72a5.08 5.08 0 0 1 -2.76 1.65 2.91 2.91 0 0 1 -2.65 -1.38 202.84 202.84 0 0 1 0.82 -23.9l-3.57 -3.58a7.75 7.75 0 1 1 11 -11l2 2c-4.43 1.9 -5.43 5.25 -5.47 5.41a0.5 0.5 0 0 0 0.34 0.62h0.14a0.51 0.51 0 0 0 0.48 -0.36c0 -0.15 1.15 -3.8 6.45 -5.32a0.47 0.47 0 0 0 0.25 -0.18c2.9 -0.83 6.63 -1.89 9.88 -2.73a7.65 7.65 0 0 0 2.56 3.76c2.9 2.56 7.93 4.79 14.12 6a41 41 0 0 0 7.82 0.79 27.09 27.09 0 0 0 5.19 -0.46 12 12 0 0 0 4.9 -1.94 4.61 4.61 0 0 0 1.91 -2.79 4.08 4.08 0 0 0 0 -1.35 12.09 12.09 0 0 1 4.59 4.83 0.49 0.49 0 0 0 0.44 0.26 0.53 0.53 0 0 0 0.24 -0.06 0.51 0.51 0 0 0 0.2 -0.68 12.86 12.86 0 0 0 -6 -5.68 6.7 6.7 0 0 0 -0.77 -1.25l0.4 -0.4a7.75 7.75 0 0 1 11 11l-1.79 1.8 -0.31 0.31a145.32 145.32 0 0 1 0.95 15l-0.52 0.43a27.596 27.596 0 0 0 -1.22 1.19 3.52 3.52 0 0 0 -0.1 -0.86 1 1 0 0 0 -1 -0.72 1.15 1.15 0 0 0 -0.26 0 1 1 0 0 0 -0.72 1.19 2.33 2.33 0 0 1 0 0.83 3 3 0 0 1 -0.25 0.78 2.32 2.32 0 0 1 -0.46 0.54 3.35 3.35 0 0 1 -1.22 0.65 3.84 3.84 0 0 1 -1.07 0.15 10 10 0 0 1 -3.88 -1.22 16.6 16.6 0 0 0 -4.69 -1.59 13.29 13.29 0 0 0 -1.97 -0.02c-2.8 0 -4.37 1 -5.08 2.36a4.42 4.42 0 0 0 -2.26 -0.6c-2.09 0 -4.26 1.34 -6.44 4a20.6 20.6 0 0 0 -2.87 5.27c-1 2.28 -1.77 4.26 -3.67 5.18a4.2 4.2 0 0 1 -1.81 0.47 2.91 2.91 0 0 1 -0.89 -0.14 3.93 3.93 0 0 1 -0.9 -0.5 3.35 3.35 0 0 1 -0.75 -0.84 1 1 0 0 0 -1.76 0.94 4.31 4.31 0 0 0 1.28 1.47 4.84 4.84 0 0 0 1.45 0.81 7.05 7.05 0 0 0 2.48 0.43c4.55 0 10.6 -3.64 18 -10.81a2.34 2.34 0 0 0 0.25 -0.3h1.7c6.13 0 10.62 -0.81 13.43 -2.4 -1.29 3 -1.3 5.81 0.28 7.58l0.09 0.08a5.54 5.54 0 0 0 4.2 1.57v0.43a6.57 6.57 0 0 0 -1.45 4 6.32 6.32 0 0 0 0.94 3.25c-0.22 2.92 -0.52 6.22 -0.88 9.65zm-49.31 -38.7a7.5 7.5 0 1 1 7.5 7.5 7.51 7.51 0 0 1 -7.5 -7.5zm54.46 32.8c0.19 2.14 0.83 2.46 1.13 2.61a1.31 1.31 0 0 0 0.61 0.15 1.5 1.5 0 0 0 0.55 -0.11 3.12 3.12 0 0 0 1.31 -1.3 19.57 19.57 0 0 0 4.07 0.59c-1.14 3.23 -3.65 9.28 -6.36 9.28 -1.68 0 -3.43 -2.3 -5 -9a0.1 0.1 0 0 0 -0.07 0.06c0.15 -1.67 0.29 -3.28 0.42 -4.82a11.46 11.46 0 0 0 3.34 2.54zm17.92 18.13a59 59 0 0 1 -3.45 8.46 32.566 32.566 0 0 1 -1.12 2c-1.89 3.05 -3.79 4.63 -5.65 4.63s-3.8 -1.93 -5.59 -4.63a40.66 40.66 0 0 1 -1.22 -2 62 62 0 0 1 -3 -6.08c-1 -2.27 -1.76 -4.42 -2.29 -6a268.89 268.89 0 0 0 0.79 -5.4 7.76 7.76 0 0 0 3 3.63 3.93 3.93 0 0 0 1.9 0.5c4.09 0 7 -6.77 8.41 -11l0.09 -0.26a20.79 20.79 0 0 0 2.42 -0.29l1.08 -0.23a17.88 17.88 0 0 0 2.79 -0.91 3.88 3.88 0 0 0 1.85 0.47h0.27a3.59 3.59 0 0 0 3.48 1.85h0.25a134.51 134.51 0 0 1 -4.01 15.24zm1.74 -17.57a1.46 1.46 0 0 0 0.66 0.16 1.5 1.5 0 0 0 1.5 -1.5 1.39 1.39 0 0 0 -0.09 -0.5c1.41 0 2.59 0.71 2.59 1.54a1 1 0 0 1 -0.32 0.71 1.23 1.23 0 0 0 -0.47 -0.22 1.89 1.89 0 0 0 -1.56 0.62 0.44 0.44 0 0 0 -0.13 0.42h-0.14a2.93 2.93 0 0 1 -2.47 -1 3.3 3.3 0 0 0 0.43 -0.25zm-11.21 -14.88c5.83 0 10.55 2.52 10.55 5.64s-4.72 5.68 -10.55 5.68 -10.55 -2.53 -10.55 -5.65 4.72 -5.69 10.55 -5.69z"/>
+  <path fill="#59acff" d="M144.79 128.16s0.03 0 0 0z"/>
+  <path fill="url(#i)" d="M132.92 93.07a1.41 1.41 0 0 0 1.93 -0.44l1.66 -2.63a1.4 1.4 0 0 0 -0.44 -1.93 1.38 1.38 0 0 0 -1.93 0.44l-1.67 2.66a1.4 1.4 0 0 0 0.45 1.9z"/>
+  <path fill="url(#j)" d="M129.13 97a5.64 5.64 0 0 0 9.23 0 1 1 0 0 0 -1.68 -1.1 3.66 3.66 0 0 1 -2.94 1.5 3.72 3.72 0 0 1 -2.94 -1.49 1 1 0 0 0 -1.67 1.09z"/>
+  <path fill="#d9ebff" d="M124.1 133.65a6.12 6.12 0 0 1 -2.5 -2.05 6.08 6.08 0 0 1 -4.09 1.29 5.88 5.88 0 0 1 -1.79 -0.24 1.82 1.82 0 0 1 -0.6 -0.35 6.76 6.76 0 0 1 -3.43 2.38 4.07 4.07 0 0 1 -2.92 -0.34c0.07 1.71 0.49 3.69 2 3.84 2.77 0.28 4.71 -2.77 4.71 -2.77s2.49 1.11 3.88 0.55a13.26 13.26 0 0 0 2.21 -1.1s1.94 3.88 4.44 2.77c1.32 -0.59 1.55 -2.5 1.47 -4.16a4.43 4.43 0 0 1 -1.94 0.47 4 4 0 0 1 -1.44 -0.29z"/>
+  <path fill="url(#k)" d="M110.48 129.17c-0.68 0.66 -1.6 1.92 -1.53 2.67a0.68 0.68 0 0 0 0.37 0.52 2.38 2.38 0 0 0 1.9 0.38 5.58 5.58 0 0 0 2.78 -2.27l-0.14 -1.08 -1.76 1.45a0.52 0.52 0 0 1 -0.32 0.11 0.5 0.5 0 0 1 -0.31 -0.89l2.17 -1.78 -2.59 -1.39a0.5 0.5 0 0 1 -0.21 -0.68 0.51 0.51 0 0 1 0.68 -0.2l2.06 1.11v-0.18c-0.36 -0.93 -1.48 -3.14 -3 -3.74a2 2 0 0 0 -0.75 -0.14 2.5 2.5 0 0 0 -1.11 0.28 0.5 0.5 0 0 0 -0.33 0.39c-0.18 1 1.16 3 2.13 4a1 1 0 0 1 -0.04 1.44z"/>
+  <path fill="url(#l)" d="M107 132a2.67 2.67 0 0 0 1.28 2 7.105 7.105 0 0 0 0.53 0.3 4.07 4.07 0 0 0 2.92 0.34 6.76 6.76 0 0 0 3.43 -2.38 1.82 1.82 0 0 0 0.6 0.35 5.88 5.88 0 0 0 1.79 0.24 6.08 6.08 0 0 0 4.09 -1.29 6.12 6.12 0 0 0 2.5 2.05 4 4 0 0 0 1.49 0.29 4.43 4.43 0 0 0 1.94 -0.47h0.07a2.48 2.48 0 0 0 1.4 -1.8c0.33 -1.75 -1.12 -3.92 -2 -5.07a5.41 5.41 0 0 0 1.49 -3.61 2.63 2.63 0 0 0 -1.28 -2 4.31 4.31 0 0 0 -3.45 -0.65 6.78 6.78 0 0 0 -3.38 2.33l-0.08 -0.06a1 1 0 0 0 -0.5 -0.13c-0.9 0 -3.92 0.07 -5.1 1a1.75 1.75 0 0 0 -0.45 0.55 6.75 6.75 0 0 0 -2.89 -2.6 4.18 4.18 0 0 0 -3.5 0.2 2.5 2.5 0 0 0 -1.4 1.8c-0.34 1.75 1.12 3.93 2 5.07a5.44 5.44 0 0 0 -1.5 3.54zm17.26 -9.79a2.37 2.37 0 0 1 1.89 0.39 0.65 0.65 0 0 1 0.37 0.52c0.08 0.74 -0.85 2 -1.53 2.67a1 1 0 0 0 0 1.38c1 1.08 2.3 3.12 2.12 4.06 0 0.12 -0.06 0.25 -0.33 0.38a2.16 2.16 0 0 1 -1.86 0.14 6 6 0 0 1 -2.53 -2.79v-0.33l1.15 0.92a0.51 0.51 0 0 0 0.31 0.11 0.5 0.5 0 0 0 0.32 -0.89l-1.81 -1.45v-0.42l1.39 -1.39a0.5 0.5 0 0 0 0 -0.7 0.5 0.5 0 0 0 -0.71 0l-0.87 0.87a8.16 8.16 0 0 0 -0.44 -1.45 5.28 5.28 0 0 1 2.49 -1.98zm-8.32 2.79a10.91 10.91 0 0 1 3.52 -0.51c0.89 1 1.07 4.93 0.69 5.78 -0.34 0.45 -2.64 0.91 -3.72 0.56 -0.69 -0.62 -1.04 -4.83 -0.49 -5.83zm-7.54 -1.23a0.5 0.5 0 0 1 0.33 -0.39 2.5 2.5 0 0 1 1.11 -0.28 2 2 0 0 1 0.75 0.14c1.49 0.6 2.61 2.81 3 3.74v0.18l-2.07 -1.16a0.51 0.51 0 0 0 -0.68 0.2 0.5 0.5 0 0 0 0.21 0.68l2.59 1.39 -2.17 1.78a0.5 0.5 0 0 0 0.31 0.89 0.52 0.52 0 0 0 0.32 -0.11l1.76 -1.45 0.14 1.08a5.58 5.58 0 0 1 -2.78 2.27 2.38 2.38 0 0 1 -1.9 -0.38 0.68 0.68 0 0 1 -0.37 -0.52c-0.07 -0.75 0.85 -2 1.53 -2.67a1 1 0 0 0 0 -1.39c-0.92 -1.06 -2.26 -3.09 -2.08 -4.04z"/>
+  <path fill="url(#m)" d="M122.93 124.85a0.5 0.5 0 0 1 0.71 0 0.5 0.5 0 0 1 0 0.7l-1.39 1.39v0.42l1.81 1.45a0.5 0.5 0 0 1 -0.32 0.89 0.51 0.51 0 0 1 -0.31 -0.11l-1.15 -0.92v0.33a6 6 0 0 0 2.53 2.79 2.16 2.16 0 0 0 1.86 -0.14c0.27 -0.13 0.31 -0.26 0.33 -0.38 0.18 -0.94 -1.16 -3 -2.12 -4.06a1 1 0 0 1 0 -1.38c0.68 -0.66 1.61 -1.93 1.53 -2.67a0.65 0.65 0 0 0 -0.37 -0.52 2.37 2.37 0 0 0 -1.89 -0.39 5.28 5.28 0 0 0 -2.6 2 8.16 8.16 0 0 1 0.44 1.45z"/>
+  <path fill="url(#n)" d="M120.15 130.23c0.38 -0.85 0.2 -4.83 -0.69 -5.78a10.91 10.91 0 0 0 -3.52 0.51c-0.55 1 -0.2 5.25 0.49 5.83 1.08 0.35 3.38 -0.11 3.72 -0.56z"/>
+  <path fill="url(#o)" d="M116.84 77.3a33.5 33.5 0 0 0 12.25 0.33c3 -0.59 4.95 -1.74 5.23 -3.15s-1.07 -3.2 -3.67 -4.89l-0.47 -0.28 -1.6 3.31a0.93 0.93 0 0 1 -0.31 0.37c-0.19 0.14 -1.52 1 -5 1a30.8 30.8 0 0 1 -5.62 -0.58c-5.32 -1 -9.81 -4 -10.37 -5.12a1.26 1.26 0 0 1 -0.12 -0.48l-0.16 -2.81c-3.08 0.59 -5 1.76 -5.31 3.17 -0.55 2.83 5.54 7.27 15.15 9.13z"/>
+  <path fill="url(#p)" d="M128.87 57.59a44 44 0 0 1 -8.2 -0.85c-4.91 -1 -9.71 -2.65 -12.41 -4.68l0.54 9.39a52.63 52.63 0 0 0 9.52 3.84 28.52 28.52 0 0 0 11.17 0.86l4.4 -9.09a14.94 14.94 0 0 1 -2.29 0.4 26 26 0 0 1 -2.73 0.13z"/>
+  <path fill="#fff" d="M121.05 54.78a36.81 36.81 0 0 0 10.34 0.69c3 -0.31 4 -1.13 4 -1.52s-0.49 -1.49 -3.18 -2.91a36.94 36.94 0 0 0 -9.85 -3.23 41.36 41.36 0 0 0 -7.74 -0.81c-4.13 0 -6.48 0.86 -6.63 1.64 -0.19 1.18 4.2 4.42 13.06 6.14z"/>
+  <path fill="#f2f8ff" d="M108.71 62.53v5a23.77 23.77 0 0 0 8.5 4 22.43 22.43 0 0 0 10.15 0.25l2 -4.57a29.54 29.54 0 0 1 -11.24 -0.94 53.39 53.39 0 0 1 -9.41 -3.74z"/>
+  <path fill="url(#q)" d="M156.91 123c5.83 0 10.55 -2.53 10.55 -5.65s-4.72 -5.64 -10.55 -5.64 -10.55 2.52 -10.55 5.64 4.72 5.65 10.55 5.65zm-7.78 -6.75h0.37a4.49 4.49 0 0 1 2.2 -2 0.49 0.49 0 0 1 0.57 -0.79l0.6 0.32a12.44 12.44 0 0 1 3.54 -0.57v-0.32a0.5 0.5 0 0 1 1 0v0.33a11.84 11.84 0 0 1 3.78 0.78l0.62 -0.31a0.51 0.51 0 0 1 0.67 0.23 0.5 0.5 0 0 1 -0.17 0.63 4.06 4.06 0 0 1 1.6 1.59h0.5a0.5 0.5 0 0 1 0.5 0.5 0.5 0.5 0 0 1 -0.5 0.5h-0.23v0.05a2.92 2.92 0 0 1 -1.28 2.23 0.5 0.5 0 0 1 0 0.16 0.49 0.49 0 0 1 -0.46 0.31 0.47 0.47 0 0 1 -0.17 0 10.53 10.53 0 0 1 -4.58 1.28v0.38a0.5 0.5 0 1 1 -1 0v-0.35a12.1 12.1 0 0 1 -4.52 -0.85l-0.23 0.13a0.47 0.47 0 0 1 -0.25 0.07 0.5 0.5 0 0 1 -0.43 -0.25 0.48 0.48 0 0 1 0 -0.42 3.36 3.36 0 0 1 -1.91 -2.59h-0.13a0.51 0.51 0 0 1 -0.5 -0.47 0.5 0.5 0 0 1 0.41 -0.62z"/>
+  <path fill="#f2f8ff" d="M157.48 116.86l5.11 2a0.49 0.49 0 0 1 0.31 0.49 2.92 2.92 0 0 0 1.28 -2.23v-0.05h-1.4a0.5 0.5 0 0 1 -0.5 -0.5 0.51 0.51 0 0 1 0.5 -0.5h1.13a4.06 4.06 0 0 0 -1.6 -1.59h-0.06z"/>
+  <path fill="#f2f8ff" d="M151.78 116.54a0.49 0.49 0 0 1 -0.47 0.53l-2 0.12a3.36 3.36 0 0 0 1.91 2.59 0.45 0.45 0 0 1 0.21 -0.26l1.5 -0.88a0.5 0.5 0 0 1 0.5 0.87l-1.27 0.74a12.1 12.1 0 0 0 4.52 0.85v-1.1a0.5 0.5 0 0 1 1 0v1.12a10.53 10.53 0 0 0 4.58 -1.28l-5.75 -2.25a0.5 0.5 0 0 1 -0.29 -0.65 0.49 0.49 0 0 1 0.24 -0.63l4.75 -2.32a11.84 11.84 0 0 0 -3.78 -0.78v0.8a0.5 0.5 0 1 1 -1 0v-0.81a12.44 12.44 0 0 0 -3.54 0.57l0.78 0.43a0.49 0.49 0 0 1 0.2 0.67 0.49 0.49 0 0 1 -0.44 0.26 0.53 0.53 0 0 1 -0.24 -0.06l-1.38 -0.75 -0.09 -0.08a4.49 4.49 0 0 0 -2.2 2l1.75 -0.11a0.51 0.51 0 0 1 0.51 0.41z"/>
+  <path fill="url(#r)" d="M153.59 118.82a0.5 0.5 0 0 0 -0.68 -0.18l-1.5 0.88a0.45 0.45 0 0 0 -0.21 0.26 0.48 0.48 0 0 0 0 0.42 0.5 0.5 0 0 0 0.43 0.25 0.47 0.47 0 0 0 0.25 -0.07l0.23 -0.13 1.27 -0.74a0.51 0.51 0 0 0 0.21 -0.69z"/>
+  <path fill="url(#s)" d="M156.2 116.88a0.5 0.5 0 0 0 0.29 0.65l5.75 2.25a0.47 0.47 0 0 0 0.17 0 0.49 0.49 0 0 0 0.46 -0.31 0.5 0.5 0 0 0 0 -0.16 0.49 0.49 0 0 0 -0.31 -0.49l-5.11 -2 4.77 -2.34h0.06a0.5 0.5 0 0 0 0.17 -0.63 0.51 0.51 0 0 0 -0.67 -0.23l-0.62 0.31 -4.75 2.32a0.49 0.49 0 0 0 -0.21 0.63z"/>
+  <path fill="url(#t)" d="M153.17 115a0.53 0.53 0 0 0 0.24 0.06 0.49 0.49 0 0 0 0.44 -0.26 0.49 0.49 0 0 0 -0.2 -0.67l-0.78 -0.43 -0.6 -0.32a0.49 0.49 0 0 0 -0.57 0.79l0.09 0.08z"/>
+  <path fill="url(#u)" d="M162.28 116.57a0.5 0.5 0 0 0 0.5 0.5h1.63a0.5 0.5 0 0 0 0.5 -0.5 0.5 0.5 0 0 0 -0.5 -0.5h-1.63a0.51 0.51 0 0 0 -0.5 0.5z"/>
+  <path fill="url(#v)" d="M156.91 114.45a0.5 0.5 0 0 0 0.5 -0.5v-1.13a0.5 0.5 0 0 0 -1 0v1.18a0.5 0.5 0 0 0 0.5 0.45z"/>
+  <path fill="url(#w)" d="M149.16 117.2h0.13l2 -0.12a0.49 0.49 0 0 0 0.47 -0.53 0.51 0.51 0 0 0 -0.53 -0.47l-1.75 0.11h-0.37a0.5 0.5 0 0 0 -0.47 0.53 0.51 0.51 0 0 0 0.52 0.48z"/>
+  <path fill="url(#x)" d="M157.16 119.45a0.5 0.5 0 0 0 -0.5 0.5v1.5a0.5 0.5 0 1 0 1 0v-1.45a0.5 0.5 0 0 0 -0.5 -0.55z"/>
+</svg>
--- 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,17 +13,17 @@ let gWhitelist = [{
     key: "certerror.introPara",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "certerror.introPara1",
     type: "single-quote"
   }, {
     file: "netError.dtd",
-    key: "certerror.expiredCert.whatCanYouDoAboutIt",
+    key: "certerror.expiredCert.whatCanYouDoAboutIt2",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "certerror.whatShouldIDo.badStsCertExplanation1",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "inadequateSecurityError.longDesc",
@@ -32,16 +32,20 @@ let gWhitelist = [{
     file: "netError.dtd",
     key: "certerror.wrongSystemTime2",
     type: "single-quote"
   }, {
     file: "netError.dtd",
     key: "certerror.wrongSystemTimeWithoutReference",
     type: "single-quote"
   }, {
+    file: "netError.dtd",
+    key: "clockSkewError.longDesc",
+    type: "single-quote"
+  }, {
     file: "phishing-afterload-warning-message.dtd",
     key: "safeb.palm.advisory.desc2",
     type: "single-quote"
   }, {
     file: "phishing-afterload-warning-message.dtd",
     key: "safeb.blocked.malwarePage.errorDesc.override",
     type: "single-quote"
   }, {
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -13,16 +13,17 @@ browser.jar:
         content/browser/aboutRobots.xhtml             (content/aboutRobots.xhtml)
         content/browser/aboutRobots.js                (content/aboutRobots.js)
         content/browser/aboutRobots.css               (content/aboutRobots.css)
 
         content/browser/illustrations/error-connection-failure.svg (content/illustrations/error-connection-failure.svg)
         content/browser/illustrations/error-server-not-found.svg (content/illustrations/error-server-not-found.svg)
         content/browser/illustrations/error-malformed-url.svg (content/illustrations/error-malformed-url.svg)
         content/browser/illustrations/under-construction.svg (content/illustrations/under-construction.svg)
+        content/browser/illustrations/blue-berror.svg (content/illustrations/blue-berror.svg)
         content/browser/aboutNetError.xhtml            (content/aboutNetError.xhtml)
         content/browser/aboutNetError.js               (content/aboutNetError.js)
         content/browser/aboutNetError-new.xhtml        (content/aboutNetError-new.xhtml)
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
         content/browser/aboutTabCrashed.css           (content/aboutTabCrashed.css)
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -6,16 +6,17 @@
 %brandDTD;
 
 <!ENTITY loadError.label "Problem loading page">
 <!ENTITY retry.label "Try Again">
 <!ENTITY returnToPreviousPage.label "Go Back">
 <!ENTITY returnToPreviousPage1.label "Go Back (Recommended)">
 <!ENTITY advanced.label "Advanced">
 <!ENTITY continue1.label "Continue…">
+<!ENTITY moreInformation.label "More Information">
 
 <!-- Specific error messages -->
 
 <!ENTITY connectionFailure.title "Unable to connect">
 <!ENTITY connectionFailure.longDesc "&sharedLongDesc;">
 
 <!ENTITY deniedPortAccess.title "This address is restricted">
 <!ENTITY deniedPortAccess.longDesc "">
@@ -159,18 +160,18 @@ was trying to connect. -->
 
 <!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>
 ">
 
-<!ENTITY certerror.expiredCert.whatCanYouDoAboutIt "
-<p>Your computer clock is set to <span id='wrongSystemTime_systemDate'/>. Make sure your computer is set to the correct date, time, and time zone in your system settings, and then refresh <span class='hostname'/>.</p>
+<!ENTITY certerror.expiredCert.whatCanYouDoAboutIt2 "
+<p>Your computer clock is set to <span id='wrongSystemTime_systemDate2'/>. Make sure your computer is set to the correct date, time, and time zone in your system settings, and then refresh <span class='hostname'/>.</p>
 <p>If your clock is already set to the right time, the website is likely misconfigured, and there is nothing you can do to resolve the issue. You can notify the website’s administrator about the problem.</p>
 ">
 
 <!ENTITY certerror.badCertDomain.whatCanYouDoAboutIt "
 <p>The issue is most likely with the website, and there is nothing you can do to resolve it. You can notify the website’s administrator about the problem.</p>
 ">
 
 <!ENTITY sharedLongDesc "
@@ -221,10 +222,13 @@ certificate.">
 
 <!ENTITY inadequateSecurityError.title "Your connection is not secure">
 <!-- LOCALIZATION NOTE (inadequateSecurityError.longDesc) - Do not translate
      "NS_ERROR_NET_INADEQUATE_SECURITY". -->
 <!ENTITY inadequateSecurityError.longDesc "<p><span class='hostname'></span> uses security technology that is outdated and vulnerable to attack. An attacker could easily reveal information which you thought to be safe. The website administrator will need to fix the server first before you can visit the site.</p><p>Error code: NS_ERROR_NET_INADEQUATE_SECURITY</p>">
 
 <!ENTITY blockedByPolicy.title "Blocked Page">
 
+<!ENTITY clockSkewError.title "Your computer clock is wrong">
+<!ENTITY clockSkewError.longDesc "Your computer thinks it is <span id='wrongSystemTime_systemDate1'/>, which prevents &brandShortName; from connecting securely. To visit <span class='hostname'></span>, update your computer clock in your system settings to the current date, time, and time zone, and then refresh <span class='hostname'></span>.">
+
 <!ENTITY prefReset.longDesc "It looks like your network security settings might be causing this. Do you want the default settings to be restored?">
 <!ENTITY prefReset.label "Restore default settings">
--- a/browser/modules/NetErrorContent.jsm
+++ b/browser/modules/NetErrorContent.jsm
@@ -378,50 +378,31 @@ var NetErrorContent = {
       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";
-        if (newErrorPagesEnabled) {
-          let dateOptions = { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" };
-          let systemDate = new Services.intl.DateTimeFormat(undefined, dateOptions).format(new Date());
-          doc.getElementById("wrongSystemTime_systemDate").textContent = systemDate;
-          let errDesc = doc.getElementById("ed2_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE");
-          let sd = doc.getElementById("errorShortDescText2");
-          if (sd) {
-            // eslint-disable-next-line no-unsanitized/property
-            sd.innerHTML = errDesc.innerHTML;
-          }
-          if (es) {
-            // eslint-disable-next-line no-unsanitized/property
-            es.innerHTML = errWhatToDo.innerHTML;
-          }
-          if (est) {
-            // eslint-disable-next-line no-unsanitized/property
-            est.innerHTML = errWhatToDoTitle.innerHTML;
-          }
-          updateContainerPosition();
-        break;
-        }
+        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);
 
         let approximateDate = now - difference * 1000;
         // If the difference is more than a day, we last fetched the date in the last 5 days,
         // and adjusting the date per the interval would make the cert valid, warn the user:
         if (Math.abs(difference) > 60 * 60 * 24 && (now - lastFetched) <= 60 * 60 * 24 * 5 &&
             certRange.notBefore < approximateDate && certRange.notAfter > approximateDate) {
+          clockSkew = true;
           let formatter = new Services.intl.DateTimeFormat(undefined, {
             dateStyle: "short"
           });
           let systemDate = formatter.format(new Date());
           // negative difference means local time is behind server time
           approximateDate = formatter.format(new Date(approximateDate));
 
           doc.getElementById("wrongSystemTime_URL").textContent = doc.location.hostname;
@@ -443,28 +424,68 @@ var NetErrorContent = {
           let buildDate = new Date(year, month, day);
           let systemDate = new Date();
 
           // We don't check the notBefore of the cert with the build date,
           // as it is of course almost certain that it is now later than the build date,
           // so we shouldn't exclude the possibility that the cert has become valid
           // since the build date.
           if (buildDate > systemDate && new Date(certRange.notAfter) > buildDate) {
+            clockSkew = true;
             let formatter = new Services.intl.DateTimeFormat(undefined, {
               dateStyle: "short"
             });
 
             doc.getElementById("wrongSystemTimeWithoutReference_URL")
               .textContent = doc.location.hostname;
             doc.getElementById("wrongSystemTimeWithoutReference_systemDate")
               .textContent = formatter.format(systemDate);
-
-            doc.getElementById("errorShortDesc").style.display = "none";
-            doc.getElementById("wrongSystemTimeWithoutReferencePanel").style.display = "block";
+          }
+        }
+        if (!newErrorPagesEnabled) {
+          break;
+        }
+        let dateOptions = { year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "numeric" };
+        let systemDate = new Services.intl.DateTimeFormat(undefined, dateOptions).format(new Date());
+        doc.getElementById("wrongSystemTime_systemDate1").textContent = systemDate;
+        if (clockSkew) {
+          doc.body.classList.add("illustrated", "clockSkewError");
+          let clockErrTitle = doc.getElementById("et_clockSkewError");
+          let clockErrDesc = doc.getElementById("ed_clockSkewError");
+          // eslint-disable-next-line no-unsanitized/property
+          doc.querySelector(".title-text").textContent = clockErrTitle.textContent;
+          let desc = doc.getElementById("errorShortDescText");
+          doc.getElementById("errorShortDesc").style.display = "block";
+          doc.getElementById("wrongSystemTimePanel").style.display = "none";
+          doc.getElementById("certificateErrorReporting").style.display = "none";
+          if (desc) {
+            // eslint-disable-next-line no-unsanitized/property
+            desc.innerHTML = clockErrDesc.innerHTML;
           }
+          let errorPageContainer = doc.getElementById("errorPageContainer");
+          let textContainer = doc.getElementById("text-container");
+          errorPageContainer.style.backgroundPosition = `left top calc(50vh - ${textContainer.clientHeight / 2}px)`;
+        } else {
+            doc.getElementById("wrongSystemTime_systemDate2").textContent = systemDate;
+            let errDesc = doc.getElementById("ed2_nssBadCert_SEC_ERROR_EXPIRED_CERTIFICATE");
+            let sd = doc.getElementById("errorShortDescText2");
+            if (sd) {
+              // eslint-disable-next-line no-unsanitized/property
+              sd.innerHTML = errDesc.innerHTML;
+            }
+            if (es) {
+              // eslint-disable-next-line no-unsanitized/property
+              es.innerHTML = errWhatToDo.innerHTML;
+            }
+            if (est) {
+              // eslint-disable-next-line no-unsanitized/property
+              est.textContent = errWhatToDoTitle.textContent;
+              est.style.fontWeight = "bold";
+            }
+            updateContainerPosition();
         }
         break;
     }
   },
 
   handleEvent(aGlobal, aEvent) {
     // Documents have a null ownerDocument.
     let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
--- a/browser/themes/shared/aboutNetError-new.css
+++ b/browser/themes/shared/aboutNetError-new.css
@@ -23,16 +23,21 @@ body.captiveportal .title {
 body.certerror .title {
   background-image: url("cert-error-new.svg");
 }
 
 body.blocked .title {
   background-image: url("chrome://global/skin/icons/blocked.svg");
 }
 
+body.clockSkewError .title {
+  background-image: none;
+  background-repeat: no-repeat;
+}
+
 #errorContainer {
   display: none;
 }
 
 /* Pressing the retry button will cause the cursor to flicker from a pointer to
  * not-allowed. Override the disabled cursor behaviour since we will never show
  * the button disabled as the initial state. */
 button:disabled {
@@ -77,21 +82,33 @@ body:not(.neterror) #netErrorButtonConta
 body.captiveportal #returnButton {
   display: none;
 }
 
 body:not(.captiveportal) #openPortalLoginPageButton {
   display: none;
 }
 
+body:not(.clockSkewError) #errorTryAgain {
+  display: none;
+}
+
+body:not(.clockSkewError) #advancedPanelErrorTryAgain {
+  display: none;
+}
+
+body:not(.clockSkewError) #moreInformationButton {
+  display: none;
+}
+
 #openPortalLoginPageButton {
   margin-inline-start: 0;
 }
 
-body:not(.neterror) #advancedButton {
+body:not(.neterror):not(.clockSkewError) #advancedButton {
   display: block;
 }
 
 #certificateErrorReporting {
   display: none;
   padding-bottom: 10px;
 }
 
@@ -216,16 +233,44 @@ span#hostname {
 .dnsNotFound #errorPageContainer {
   background-image: url("chrome://browser/content/illustrations/error-server-not-found.svg");
 }
 
 .malformedURI #errorPageContainer {
   background-image: url("chrome://browser/content/illustrations/error-malformed-url.svg");
 }
 
+.clockSkewError #errorPageContainer {
+  background-image: url("chrome://browser/content/illustrations/blue-berror.svg");
+  background-size: 18.5em;
+}
+
+.clockSkewError #returnButton {
+  display: none;
+}
+
+.clockSkewError #advancedButton {
+  display: none;
+}
+
+.clockSkewError #advancedPanelErrorTryAgain,
+.clockSkewError #errorTryAgain,
+.clockSkewError #moreInformationButton {
+  display: block;
+  margin-top: 0.3em;
+}
+
+.clockSkewError #exceptionDialogButton {
+  display: none;
+}
+
+.clockSkewError #advancedPanelReturnButton {
+  display: none;
+}
+
 .malformedURI #errorTryAgain {
   display: none;
 }
 
 #wrongSystemTimePanel {
   display: none;
 }
 
--- a/browser/themes/shared/aboutNetError.css
+++ b/browser/themes/shared/aboutNetError.css
@@ -50,16 +50,24 @@ button:disabled {
 body:not(.neterror) #certErrorAndCaptivePortalButtonContainer {
   display: flex;
 }
 
 body:not(.neterror) #netErrorButtonContainer {
   display: none;
 }
 
+#advancedPanelErrorTryAgain {
+  display: none;
+}
+
+#moreInformationButton {
+  display: none;
+}
+
 #errorTryAgain {
   margin-top: 1.2em;
 }
 
 #advancedButton {
   display: none;
 }
 
--- a/devtools/client/sourceeditor/editor.js
+++ b/devtools/client/sourceeditor/editor.js
@@ -59,16 +59,17 @@ const CM_SCRIPTS = [
 const CM_IFRAME = "chrome://devtools/content/sourceeditor/codemirror/cmiframe.html";
 
 const CM_MAPPING = [
   "clearHistory",
   "defaultCharWidth",
   "extendSelection",
   "focus",
   "getCursor",
+  "getLine",
   "getScrollInfo",
   "getSelection",
   "getViewport",
   "hasFocus",
   "lineCount",
   "openDialog",
   "redo",
   "refresh",
--- a/devtools/client/webconsole/components/JSTerm.js
+++ b/devtools/client/webconsole/components/JSTerm.js
@@ -85,22 +85,16 @@ class JSTerm extends Component {
 
     const {
       hud,
     } = props;
 
     this.hud = hud;
     this.hudId = this.hud.hudId;
 
-    /**
-     * Stores the data for the last completion.
-     * @type object
-     */
-    this.lastCompletion = { value: null };
-
     this._keyPress = this._keyPress.bind(this);
     this._inputEventHandler = this._inputEventHandler.bind(this);
     this._blurEventHandler = this._blurEventHandler.bind(this);
     this.onContextMenu = this.onContextMenu.bind(this);
 
     this.SELECTED_FRAME = -1;
 
     /**
@@ -127,26 +121,22 @@ class JSTerm extends Component {
     this._lastFrameActorId = null;
 
     /**
      * Last input value.
      * @type string
      */
     this.lastInputValue = "";
 
+    this.currentAutoCompletionRequestId = null;
+
     this.autocompletePopup = null;
     this.inputNode = null;
     this.completeNode = null;
 
-    this.COMPLETE_FORWARD = 0;
-    this.COMPLETE_BACKWARD = 1;
-    this.COMPLETE_HINT_ONLY = 2;
-    this.COMPLETE_PAGEUP = 3;
-    this.COMPLETE_PAGEDOWN = 4;
-
     this._telemetry = new Telemetry();
 
     EventEmitter.decorate(this);
     hud.jsterm = this;
   }
 
   componentDidMount() {
     const autocompleteOptions = {
@@ -173,111 +163,104 @@ class JSTerm extends Component {
           lineWrapping: true,
           mode: Editor.modes.js,
           styleActiveLine: false,
           tabIndex: "0",
           viewportMargin: Infinity,
           extraKeys: {
             "Enter": () => {
               // No need to handle shift + Enter as it's natively handled by CodeMirror.
-              if (
-                !this.autocompletePopup.isOpen &&
-                !Debugger.isCompilableUnit(this.getInputValue())
-              ) {
+
+              const hasSuggestion = this.hasAutocompletionSuggestion();
+              if (!hasSuggestion && !Debugger.isCompilableUnit(this.getInputValue())) {
                 // incomplete statement
                 return "CodeMirror.Pass";
               }
 
-              if (
-                this.autocompletePopup.isOpen
-                && this.autocompletePopup.selectedIndex > -1
-              ) {
+              if (hasSuggestion) {
                 return this.acceptProposedCompletion();
               }
 
               this.execute();
               return null;
             },
 
             "Tab": () => {
-              // Generate a completion and accept the first proposed value.
-              if (
-                this.complete(this.COMPLETE_HINT_ONLY) &&
-                this.lastCompletion &&
-                this.acceptProposedCompletion()
-              ) {
-                return false;
-              }
-
               if (this.hasEmptyInput()) {
                 this.editor.codeMirror.getInputField().blur();
                 return false;
               }
 
-              if (!this.editor.somethingSelected()) {
+              const isSomethingSelected = this.editor.somethingSelected();
+              const hasSuggestion = this.hasAutocompletionSuggestion();
+
+              if (hasSuggestion && !isSomethingSelected) {
+                this.acceptProposedCompletion();
+                return false;
+              }
+
+              if (!isSomethingSelected) {
                 this.insertStringAtCursor("\t");
                 return false;
               }
 
-              // Input is not empty and some text is selected, let the editor handle this.
+              // Something is selected, let the editor handle the indent.
               return true;
             },
 
             "Up": () => {
               let inputUpdated;
               if (this.autocompletePopup.isOpen) {
-                inputUpdated = this.complete(this.COMPLETE_BACKWARD);
-              } else if (this.canCaretGoPrevious()) {
+                this.autocompletePopup.selectPreviousItem();
+                return null;
+              }
+
+              if (this.canCaretGoPrevious()) {
                 inputUpdated = this.historyPeruse(HISTORY_BACK);
               }
 
               if (!inputUpdated) {
                 return "CodeMirror.Pass";
               }
               return null;
             },
 
             "Down": () => {
               let inputUpdated;
               if (this.autocompletePopup.isOpen) {
-                inputUpdated = this.complete(this.COMPLETE_FORWARD);
-              } else if (this.canCaretGoNext()) {
+                this.autocompletePopup.selectNextItem();
+                return null;
+              }
+
+              if (this.canCaretGoNext()) {
                 inputUpdated = this.historyPeruse(HISTORY_FORWARD);
               }
 
               if (!inputUpdated) {
                 return "CodeMirror.Pass";
               }
               return null;
             },
 
             "Left": () => {
-              if (this.autocompletePopup.isOpen || this.lastCompletion.value) {
+              if (this.autocompletePopup.isOpen || this.getAutoCompletionText()) {
                 this.clearCompletion();
               }
               return "CodeMirror.Pass";
             },
 
             "Right": () => {
-              const haveSuggestion =
-                this.autocompletePopup.isOpen || this.lastCompletion.value;
-
-              if (
-                haveSuggestion &&
-                this.complete(this.COMPLETE_HINT_ONLY) &&
-                this.lastCompletion.value &&
-                this.acceptProposedCompletion()
-              ) {
+              // We only want to complete on Right arrow if the completion text is
+              // displayed.
+              if (this.getAutoCompletionText()) {
+                this.acceptProposedCompletion();
                 return null;
               }
 
-              if (this.autocompletePopup.isOpen) {
-                this.clearCompletion();
-              }
-
+              this.clearCompletion();
               return "CodeMirror.Pass";
             },
 
             "Ctrl-N": () => {
               // Control-N differs from down arrow: it ignores autocomplete state.
               // Note that we preserve the default 'down' navigation within
               // multiline text.
               if (
@@ -305,26 +288,26 @@ class JSTerm extends Component {
               }
 
               this.clearCompletion();
               return "CodeMirror.Pass";
             },
 
             "PageUp": () => {
               if (this.autocompletePopup.isOpen) {
-                this.complete(this.COMPLETE_PAGEUP);
+                this.autocompletePopup.selectPreviousPageItem();
                 return null;
               }
 
               return "CodeMirror.Pass";
             },
 
             "PageDown": () => {
               if (this.autocompletePopup.isOpen) {
-                this.complete(this.COMPLETE_PAGEDOWN);
+                this.autocompletePopup.selectNextPageItem();
                 return null;
               }
 
               return "CodeMirror.Pass";
             },
 
             "Home": () => {
               if (this.autocompletePopup.isOpen) {
@@ -669,20 +652,31 @@ class JSTerm extends Component {
    *
    * @param string newValue
    *        The new value to set.
    * @returns void
    */
   setInputValue(newValue = "") {
     if (this.props.codeMirrorEnabled) {
       if (this.editor) {
-        this.editor.setText(newValue);
-        // Set the cursor at the end of the input.
-        this.editor.setCursor({line: this.editor.getDoc().lineCount(), ch: 0});
-        this.editor.setAutoCompletionText();
+        // In order to get the autocomplete popup to work properly, we need to set the
+        // editor text and the cursor in the same operation. If we don't, the text change
+        // is done before the cursor is moved, and the autocompletion call to the server
+        // sends an erroneous query.
+        this.editor.codeMirror.operation(() => {
+          this.editor.setText(newValue);
+
+          // Set the cursor at the end of the input.
+          const lines = newValue.split("\n");
+          this.editor.setCursor({
+            line: lines.length - 1,
+            ch: lines[lines.length - 1].length
+          });
+          this.editor.setAutoCompletionText();
+        });
       }
     } else {
       if (!this.inputNode) {
         return;
       }
 
       this.inputNode.value = newValue;
       this.completeNode.value = "";
@@ -716,17 +710,17 @@ class JSTerm extends Component {
   /**
    * The inputNode "input" and "keyup" event handler.
    * @private
    */
   _inputEventHandler() {
     const value = this.getInputValue();
     if (this.lastInputValue !== value) {
       this.resizeInput();
-      this.complete(this.COMPLETE_HINT_ONLY);
+      this.updateAutocompletion();
       this.lastInputValue = value;
     }
   }
 
   /**
    * The window "blur" event handler.
    * @private
    */
@@ -819,64 +813,64 @@ class JSTerm extends Component {
         if (this.autocompletePopup.isOpen) {
           this.clearCompletion();
           event.preventDefault();
           event.stopPropagation();
         }
         break;
 
       case KeyCodes.DOM_VK_RETURN:
-        if (
-            this.autocompletePopup.isOpen &&
-            this.autocompletePopup.selectedIndex > -1) {
+        if (this.hasAutocompletionSuggestion()) {
           this.acceptProposedCompletion();
         } else {
           this.execute();
         }
         event.preventDefault();
         break;
 
       case KeyCodes.DOM_VK_UP:
         if (this.autocompletePopup.isOpen) {
-          inputUpdated = this.complete(this.COMPLETE_BACKWARD);
+          this.autocompletePopup.selectPreviousItem();
+          event.preventDefault();
         } else if (this.canCaretGoPrevious()) {
           inputUpdated = this.historyPeruse(HISTORY_BACK);
         }
         if (inputUpdated) {
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_DOWN:
         if (this.autocompletePopup.isOpen) {
-          inputUpdated = this.complete(this.COMPLETE_FORWARD);
+          this.autocompletePopup.selectNextItem();
+          event.preventDefault();
         } else if (this.canCaretGoNext()) {
           inputUpdated = this.historyPeruse(HISTORY_FORWARD);
         }
         if (inputUpdated) {
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_PAGE_UP:
         if (this.autocompletePopup.isOpen) {
-          inputUpdated = this.complete(this.COMPLETE_PAGEUP);
+          this.autocompletePopup.selectPreviousPageItem();
         } else {
           this.hud.outputScroller.scrollTop =
             Math.max(0,
               this.hud.outputScroller.scrollTop -
               this.hud.outputScroller.clientHeight
             );
         }
         event.preventDefault();
         break;
 
       case KeyCodes.DOM_VK_PAGE_DOWN:
         if (this.autocompletePopup.isOpen) {
-          inputUpdated = this.complete(this.COMPLETE_PAGEDOWN);
+          this.autocompletePopup.selectNextPageItem();
         } else {
           this.hud.outputScroller.scrollTop =
             Math.min(this.hud.outputScroller.scrollHeight,
               this.hud.outputScroller.scrollTop +
               this.hud.outputScroller.clientHeight
             );
         }
         event.preventDefault();
@@ -889,52 +883,43 @@ class JSTerm extends Component {
         } else if (inputValue.length <= 0) {
           this.hud.outputScroller.scrollTop = 0;
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_END:
         if (this.autocompletePopup.isOpen) {
-          this.autocompletePopup.selectedIndex =
-            this.autocompletePopup.itemCount - 1;
+          this.autocompletePopup.selectedIndex = this.autocompletePopup.itemCount - 1;
           event.preventDefault();
         } else if (inputValue.length <= 0) {
-          this.hud.outputScroller.scrollTop =
-            this.hud.outputScroller.scrollHeight;
+          this.hud.outputScroller.scrollTop = this.hud.outputScroller.scrollHeight;
           event.preventDefault();
         }
         break;
 
       case KeyCodes.DOM_VK_LEFT:
-        if (this.autocompletePopup.isOpen || this.lastCompletion.value) {
+        if (this.autocompletePopup.isOpen || this.getAutoCompletionText()) {
           this.clearCompletion();
         }
         break;
 
       case KeyCodes.DOM_VK_RIGHT:
-        const haveSuggestion = this.autocompletePopup.isOpen || this.lastCompletion.value;
-        if (
-          haveSuggestion &&
-          this.complete(this.COMPLETE_HINT_ONLY) &&
-          this.lastCompletion.value &&
-          this.acceptProposedCompletion()
-        ) {
+        // We only want to complete on Right arrow if the completion text is
+        // displayed.
+        if (this.getAutoCompletionText()) {
+          this.acceptProposedCompletion();
           event.preventDefault();
         }
-        if (this.autocompletePopup.isOpen) {
-          this.clearCompletion();
-        }
+        this.clearCompletion();
         break;
 
       case KeyCodes.DOM_VK_TAB:
-        // Generate a completion and accept the first proposed value.
-        if (this.complete(this.COMPLETE_HINT_ONLY) &&
-            this.lastCompletion &&
-            this.acceptProposedCompletion()) {
+        if (this.hasAutocompletionSuggestion()) {
+          this.acceptProposedCompletion();
           event.preventDefault();
         } else if (!this.hasEmptyInput()) {
           if (!event.shiftKey) {
             this.insertStringAtCursor("\t");
           }
           event.preventDefault();
         }
         break;
@@ -1047,230 +1032,114 @@ class JSTerm extends Component {
     if (node.selectionStart != node.selectionEnd) {
       return false;
     }
 
     return node.selectionStart == node.value.length ? true :
            node.selectionStart == 0 && !multiline;
   }
 
-  /**
-   * Completes the current typed text in the inputNode. Completion is performed
-   * only if the selection/cursor is at the end of the string. If no completion
-   * is found, the current inputNode value and cursor/selection stay.
-   *
-   * @param int type possible values are
-   *    - this.COMPLETE_FORWARD: If there is more than one possible completion
-   *          and the input value stayed the same compared to the last time this
-   *          function was called, then the next completion of all possible
-   *          completions is used. If the value changed, then the first possible
-   *          completion is used and the selection is set from the current
-   *          cursor position to the end of the completed text.
-   *          If there is only one possible completion, then this completion
-   *          value is used and the cursor is put at the end of the completion.
-   *    - this.COMPLETE_BACKWARD: Same as this.COMPLETE_FORWARD but if the
-   *          value stayed the same as the last time the function was called,
-   *          then the previous completion of all possible completions is used.
-   *    - this.COMPLETE_PAGEUP: Scroll up one page if available or select the
-   *          first item.
-   *    - this.COMPLETE_PAGEDOWN: Scroll down one page if available or select
-   *          the last item.
-   *    - this.COMPLETE_HINT_ONLY: If there is more than one possible
-   *          completion and the input value stayed the same compared to the
-   *          last time this function was called, then the same completion is
-   *          used again. If there is only one possible completion, then
-   *          the this.getInputValue() is set to this value and the selection
-   *          is set from the current cursor position to the end of the
-   *          completed text.
-   * @param function callback
-   *        Optional function invoked when the autocomplete properties are
-   *        updated.
-   * @returns boolean true if there existed a completion for the current input,
-   *          or false otherwise.
-   */
-  complete(type, callback) {
+  async updateAutocompletion() {
     const inputValue = this.getInputValue();
+    const {editor, inputNode} = this;
     const frameActor = this.getFrameActor(this.SELECTED_FRAME);
-    // If the inputNode has no value, then don't try to complete on it.
-    if (!inputValue) {
-      this.clearCompletion();
-      callback && callback(this);
-      this.emit("autocomplete-updated");
-      return false;
-    }
 
-    const {editor, inputNode} = this;
-    // Only complete if the selection is empty.
+    // Only complete if the selection is empty and the input value is not.
     if (
+      !inputValue ||
       (inputNode && inputNode.selectionStart != inputNode.selectionEnd) ||
-      (editor && editor.getSelection())
+      (editor && editor.getSelection()) ||
+      (this.lastInputValue === inputValue && frameActor === this._lastFrameActorId)
     ) {
       this.clearCompletion();
-      this.callback && callback(this);
       this.emit("autocomplete-updated");
-      return false;
-    }
-
-    // Update the completion results.
-    if (this.lastCompletion.value != inputValue || frameActor != this._lastFrameActorId) {
-      this._updateCompletionResult(type, callback);
-      return false;
-    }
-
-    const popup = this.autocompletePopup;
-    let accepted = false;
-
-    if (type != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) {
-      this.acceptProposedCompletion();
-      accepted = true;
-    } else if (type == this.COMPLETE_BACKWARD) {
-      popup.selectPreviousItem();
-    } else if (type == this.COMPLETE_FORWARD) {
-      popup.selectNextItem();
-    } else if (type == this.COMPLETE_PAGEUP) {
-      popup.selectPreviousPageItem();
-    } else if (type == this.COMPLETE_PAGEDOWN) {
-      popup.selectNextPageItem();
-    }
-
-    callback && callback(this);
-    this.emit("autocomplete-updated");
-    return accepted || popup.itemCount > 0;
-  }
-
-  /**
-   * Update the completion result. This operation is performed asynchronously by
-   * fetching updated results from the content process.
-   *
-   * @private
-   * @param int type
-   *        Completion type. See this.complete() for details.
-   * @param function [callback]
-   *        Optional, function to invoke when completion results are received.
-   */
-  _updateCompletionResult(type, callback) {
-    const value = this.getInputValue();
-    const frameActor = this.getFrameActor(this.SELECTED_FRAME);
-    if (this.lastCompletion.value == value && frameActor == this._lastFrameActorId) {
       return;
     }
 
-    const requestId = gSequenceId();
     const cursor = this.getSelectionStart();
-    const input = value.substring(0, cursor);
-    const cache = this._autocompleteCache;
+    const input = inputValue.substring(0, cursor);
 
     // If the current input starts with the previous input, then we already
     // have a list of suggestions and we just need to filter the cached
-    // suggestions. When the current input ends with a non-alphanumeric
-    // character we ask the server again for suggestions.
+    // suggestions. When the current input ends with a non-alphanumeric character we ask
+    // the server again for suggestions.
 
     // Check if last character is non-alphanumeric
     if (!/[a-zA-Z0-9]$/.test(input) || frameActor != this._lastFrameActorId) {
       this._autocompleteQuery = null;
       this._autocompleteCache = null;
     }
+
     if (this._autocompleteQuery && input.startsWith(this._autocompleteQuery)) {
       let filterBy = input;
       // Find the last non-alphanumeric other than "_", ":", or "$" if it exists.
       const lastNonAlpha = input.match(/[^a-zA-Z0-9_$:][a-zA-Z0-9_$:]*$/);
       // If input contains non-alphanumerics, use the part after the last one
       // to filter the cache.
       if (lastNonAlpha) {
         filterBy = input.substring(input.lastIndexOf(lastNonAlpha) + 1);
       }
 
-      const newList = cache.sort().filter(l => l.startsWith(filterBy));
+      const newList = this._autocompleteCache.sort().filter(l => l.startsWith(filterBy));
 
-      this.lastCompletion = {
-        requestId: null,
-        completionType: type,
-        value: null,
-      };
-
-      const response = { matches: newList, matchProp: filterBy };
-      this._receiveAutocompleteProperties(null, callback, response);
+      this._receiveAutocompleteProperties(null, {
+        matches: newList,
+        matchProp: filterBy
+      });
       return;
     }
+    const requestId = gSequenceId();
     this._lastFrameActorId = frameActor;
-
-    this.lastCompletion = {
-      requestId: requestId,
-      completionType: type,
-      value: null,
-    };
-
-    const autocompleteCallback =
-      this._receiveAutocompleteProperties.bind(this, requestId, callback);
+    this.currentAutoCompletionRequestId = requestId;
 
-    this.webConsoleClient.autocomplete(
-      input, cursor, autocompleteCallback, frameActor);
-  }
-
-  getInputValueBeforeCursor() {
-    if (this.editor) {
-      return this.editor.getDoc().getRange({line: 0, ch: 0}, this.editor.getCursor());
-    }
-
-    if (this.inputNode) {
-      const cursor = this.inputNode.selectionStart;
-      return this.getInputValue().substring(0, cursor);
-    }
-
-    return null;
+    const message = await this.webConsoleClient.autocomplete(input, cursor, frameActor);
+    this._receiveAutocompleteProperties(requestId, message);
   }
 
   /**
    * Handler for the autocompletion results. This method takes
    * the completion result received from the server and updates the UI
    * accordingly.
    *
    * @param number requestId
    *        Request ID.
-   * @param function [callback=null]
-   *        Optional, function to invoke when the completion result is received.
    * @param object message
    *        The JSON message which holds the completion results received from
    *        the content process.
    */
-  _receiveAutocompleteProperties(requestId, callback, message) {
-    const inputValue = this.getInputValue();
-    if (this.lastCompletion.value == inputValue ||
-        requestId != this.lastCompletion.requestId) {
+  _receiveAutocompleteProperties(requestId, message) {
+    if (this.currentAutoCompletionRequestId !== requestId) {
       return;
     }
+    this.currentAutoCompletionRequestId = null;
+
     // Cache whatever came from the server if the last char is
     // alphanumeric or '.'
     const inputUntilCursor = this.getInputValueBeforeCursor();
 
     if (requestId != null && /[a-zA-Z0-9.]$/.test(inputUntilCursor)) {
       this._autocompleteCache = message.matches;
       this._autocompleteQuery = inputUntilCursor;
     }
 
     const matches = message.matches;
     const lastPart = message.matchProp;
     if (!matches.length) {
       this.clearCompletion();
-      callback && callback(this);
       this.emit("autocomplete-updated");
       return;
     }
 
     const popup = this.autocompletePopup;
     const items = matches.map(match => ({ preLabel: lastPart, label: match }));
     popup.setItems(items);
 
-    const completionType = this.lastCompletion.completionType;
-    this.lastCompletion = {
-      value: inputValue,
-      matchProp: lastPart,
-    };
+    const minimumAutoCompleteLength = 2;
 
-    if (items.length > 0) {
+    if (items.length >= minimumAutoCompleteLength) {
       let popupAlignElement;
       let xOffset;
       let yOffset;
 
       if (this.editor) {
         popupAlignElement = this.node.querySelector(".CodeMirror-cursor");
         // We need to show the popup at the ".".
         xOffset = -1 * lastPart.length * this._inputCharWidth;
@@ -1281,61 +1150,43 @@ class JSTerm extends Component {
           lastPart.length;
         xOffset = (offset * this._inputCharWidth) + this._chevronWidth;
         popupAlignElement = this.inputNode;
       }
 
       if (popupAlignElement) {
         popup.openPopup(popupAlignElement, xOffset, yOffset);
       }
-    } else if (items.length === 0 && popup.isOpen) {
+    } else if (items.length < minimumAutoCompleteLength && popup.isOpen) {
       popup.hidePopup();
     }
 
-    if (items.length == 1) {
-      popup.selectedIndex = 0;
+    if (items.length > 0) {
+      const suffix = items[0].label.substring(lastPart.length);
+      this.setAutoCompletionText(suffix);
     }
-
-    this.onAutocompleteSelect();
-
-    if (completionType != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) {
-      this.acceptProposedCompletion();
-    } else if (completionType == this.COMPLETE_BACKWARD) {
-      popup.selectPreviousItem();
-    } else if (completionType == this.COMPLETE_FORWARD) {
-      popup.selectNextItem();
-    }
-
-    callback && callback(this);
     this.emit("autocomplete-updated");
   }
 
   onAutocompleteSelect() {
-    // Render the suggestion only if the cursor is at the end of the input.
-    if (this.getSelectionStart() != this.getInputValue().length) {
-      return;
-    }
-
-    const currentItem = this.autocompletePopup.selectedItem;
-    if (currentItem && this.lastCompletion.value) {
-      const suffix =
-        currentItem.label.substring(this.lastCompletion.matchProp.length);
-      this.updateCompleteNode(suffix);
+    const {selectedItem} = this.autocompletePopup;
+    if (selectedItem) {
+      const suffix = selectedItem.label.substring(selectedItem.preLabel.length);
+      this.setAutoCompletionText(suffix);
     } else {
-      this.updateCompleteNode("");
+      this.setAutoCompletionText("");
     }
   }
 
   /**
    * Clear the current completion information and close the autocomplete popup,
    * if needed.
    */
   clearCompletion() {
-    this.lastCompletion = { value: null };
-    this.updateCompleteNode("");
+    this.setAutoCompletionText("");
     if (this.autocompletePopup) {
       this.autocompletePopup.clearItems();
 
       if (this.autocompletePopup.isOpen) {
         // Trigger a blur/focus of the JSTerm input to force screen readers to read the
         // value again.
         if (this.inputNode) {
           this.inputNode.blur();
@@ -1351,30 +1202,49 @@ class JSTerm extends Component {
   /**
    * Accept the proposed input completion.
    *
    * @return boolean
    *         True if there was a selected completion item and the input value
    *         was updated, false otherwise.
    */
   acceptProposedCompletion() {
-    let updated = false;
+    let completionText = this.getAutoCompletionText();
+    // In some cases the completion text might not be displayed (e.g. there is some text
+    // just after the cursor so we can't display it). In those case, if the popup is
+    // open and has a selectedItem, we use it for completing the input.
+    if (
+      !completionText
+      && this.autocompletePopup.isOpen
+      && this.autocompletePopup.selectedItem
+    ) {
+      const {selectedItem} = this.autocompletePopup;
+      completionText = selectedItem.label.substring(selectedItem.preLabel.length);
+    }
 
-    const currentItem = this.autocompletePopup.selectedItem;
-    if (currentItem && this.lastCompletion.value) {
-      this.insertStringAtCursor(
-        currentItem.label.substring(this.lastCompletion.matchProp.length)
-      );
-
-      updated = true;
+    if (!completionText) {
+      return false;
     }
 
+    this.insertStringAtCursor(completionText);
     this.clearCompletion();
+    return true;
+  }
 
-    return updated;
+  getInputValueBeforeCursor() {
+    if (this.editor) {
+      return this.editor.getDoc().getRange({line: 0, ch: 0}, this.editor.getCursor());
+    }
+
+    if (this.inputNode) {
+      const cursor = this.inputNode.selectionStart;
+      return this.getInputValue().substring(0, cursor);
+    }
+
+    return null;
   }
 
   /**
    * Insert a string into the console at the cursor location,
    * moving the cursor to the end of the string.
    *
    * @param string str
    */
@@ -1396,33 +1266,87 @@ class JSTerm extends Component {
       this.editor.setCursor({
         line: editorCursor.line,
         ch: editorCursor.ch + str.length
       });
     }
   }
 
   /**
-   * Update the node that displays the currently selected autocomplete proposal.
+   * Set the autocompletion text of the input.
    *
    * @param string suffix
    *        The proposed suffix for the inputNode value.
    */
-  updateCompleteNode(suffix) {
+  setAutoCompletionText(suffix) {
+    if (suffix && !this.canDisplayAutoCompletionText()) {
+      suffix = "";
+    }
+
     if (this.completeNode) {
-      // completion prefix = input, with non-control chars replaced by spaces
-      const prefix = suffix ? this.getInputValue().replace(/[\S]/g, " ") : "";
-      this.completeNode.value = prefix + suffix;
+      const lines = this.getInputValueBeforeCursor().split("\n");
+      const lastLine = lines[lines.length - 1];
+      const prefix = ("\n".repeat(lines.length - 1)) + lastLine.replace(/[\S]/g, " ");
+      this.completeNode.value = suffix ? prefix + suffix : "";
     }
 
     if (this.editor) {
       this.editor.setAutoCompletionText(suffix);
     }
   }
 
+  getAutoCompletionText() {
+    if (this.completeNode) {
+      // Remove the spaces we set to align with the input value.
+      return this.completeNode.value.replace(/^\s+/gm, "");
+    }
+
+    if (this.editor) {
+      return this.editor.getAutoCompletionText();
+    }
+
+    return null;
+  }
+
+  /**
+   * Indicate if the input has an autocompletion suggestion, i.e. that there is either
+   * something in the autocompletion text or that there's a selected item in the
+   * autocomplete popup.
+   */
+  hasAutocompletionSuggestion() {
+    // We can have cases where the popup is opened but we can't display the autocompletion
+    // text.
+    return this.getAutoCompletionText() || (
+      this.autocompletePopup.isOpen &&
+      Number.isInteger(this.autocompletePopup.selectedIndex) &&
+      this.autocompletePopup.selectedIndex > -1
+    );
+  }
+
+  /**
+   * Returns a boolean indicating if we can display an autocompletion text in the input,
+   * i.e. if there is no characters displayed on the same line of the cursor and after it.
+   */
+  canDisplayAutoCompletionText() {
+    if (this.editor) {
+      const { ch, line } = this.editor.getCursor();
+      const lineContent = this.editor.getLine(line);
+      const textAfterCursor = lineContent.substring(ch);
+      return textAfterCursor === "";
+    }
+
+    if (this.inputNode) {
+      const value = this.getInputValue();
+      const textAfterCursor = value.substring(this.inputNode.selectionStart);
+      return textAfterCursor.split("\n")[0] === "";
+    }
+
+    return false;
+  }
+
   /**
    * Calculates and returns the width of a single character of the input box.
    * This will be used in opening the popup at the correct offset.
    *
    * @returns {Number|null}: Width off the "x" char, or null if the input does not exist.
    */
   _getInputCharWidth() {
     if (!this.inputNode && !this.node) {
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -219,17 +219,16 @@ skip-if = os != 'mac' # The tested ctrl+
 [browser_jsterm_hide_when_devtools_chrome_enabled_false.js]
 [browser_jsterm_history.js]
 [browser_jsterm_history_arrow_keys.js]
 [browser_jsterm_history_nav.js]
 [browser_jsterm_history_persist.js]
 [browser_jsterm_inspect.js]
 [browser_jsterm_instance_of.js]
 [browser_jsterm_multiline.js]
-[browser_jsterm_no_autocompletion_on_defined_variables.js]
 [browser_jsterm_no_input_and_tab_key_pressed.js]
 [browser_jsterm_null_undefined.js]
 [browser_jsterm_popup_close_on_tab_switch.js]
 [browser_jsterm_screenshot_command_clipboard.js]
 subsuite = clipboard
 [browser_jsterm_screenshot_command_user.js]
 subsuite = clipboard
 [browser_jsterm_screenshot_command_file.js]
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_accessibility.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_accessibility.js
@@ -6,31 +6,35 @@
 // Tests that the autocomplete input is being blurred and focused when selecting a value.
 // This will help screen-readers notify users of the value that was set in the input.
 
 "use strict";
 
 const TEST_URI = "data:text/html;charset=utf8,<p>test code completion";
 
 add_task(async function() {
-  const hud = await openNewTabAndConsole(TEST_URI);
+  // Only run test with legacy JsTerm
+  await pushPref("devtools.webconsole.jsterm.codeMirror", false);
 
-  const jsterm = hud.jsterm;
+  const {jsterm} = await openNewTabAndConsole(TEST_URI);
   const input = jsterm.inputNode;
 
   info("Test that the console input is not treated as a live region");
   ok(!isElementInLiveRegion(input), "Console input is not treated as a live region");
 
   info("Test the console input has no aria-activedescendant attribute");
   ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
 
   info("Type 'd' to open the autocomplete popup");
-  const onPopupOpen = jsterm.autocompletePopup.once("popup-opened");
-  autocomplete(jsterm, "d");
+  const {autocompletePopup} = jsterm;
+  const onPopupOpen = autocompletePopup.once("popup-opened");
+  EventUtils.sendString("d");
   await onPopupOpen;
+  ok(autocompletePopup.isOpen && autocompletePopup.itemCount > 0,
+    "Autocomplete popup is open and contains suggestions");
 
   info("Test the console input has an aria-activedescendant attribute");
   ok(input.hasAttribute("aria-activedescendant"), "aria-activedescendant");
 
   // Add listeners for focus and blur events.
   let wasBlurred = false;
   input.addEventListener("blur", () => {
     wasBlurred = true;
@@ -54,28 +58,16 @@ add_task(async function() {
   await onPopupClosed;
 
   ok(wasFocused, "jsterm input received a focus event");
 
   info("Test the console input has no aria-activedescendant attribute no more");
   ok(!input.hasAttribute("aria-activedescendant"), "no aria-activedescendant");
 });
 
-async function autocomplete(jsterm, value) {
-  const popup = jsterm.autocompletePopup;
-
-  await new Promise(resolve => {
-    jsterm.setInputValue(value);
-    jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
-  });
-
-  ok(popup.isOpen && popup.itemCount > 0,
-    "Autocomplete popup is open and contains suggestions");
-}
-
 function isElementInLiveRegion(element) {
   if (!element) {
     return false;
   }
 
   if (element.hasAttribute("aria-live")) {
     return element.getAttribute("aria-live") !== "off";
   }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete-properties-with-non-alphanumeric-names.js
@@ -35,14 +35,12 @@ async function performTests() {
   await jsterm.execute("let foobar = {a: ''}; const blargh = {a: 1};");
   await testAutocomplete(jsterm, "foobar");
   await testAutocomplete(jsterm, "blargh");
   await testAutocomplete(jsterm, "foobar.a");
   await testAutocomplete(jsterm, "blargh.a");
 }
 
 async function testAutocomplete(jsterm, inputString) {
-  jsterm.setInputValue(inputString);
-  await new Promise(resolve => jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve));
-
+  await setInputValueForAutocompletion(jsterm, inputString);
   const popup = jsterm.autocompletePopup;
   ok(popup.itemCount > 0, `There's ${popup.itemCount} suggestions for '${inputString}'`);
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_cached_results.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_cached_results.js
@@ -19,17 +19,17 @@ add_task(async function() {
   await performTests();
 });
 
 async function performTests() {
   const { jsterm } = await openNewTabAndConsole(TEST_URI);
   const { autocompletePopup: popup } = jsterm;
 
   const jstermComplete = (value, caretPosition) =>
-    jstermSetValueAndComplete(jsterm, value, caretPosition);
+    setInputValueForAutocompletion(jsterm, value, caretPosition);
 
   // Test if 'doc' gives 'document'
   await jstermComplete("doc");
   is(jsterm.getInputValue(), "doc", "'docu' completion (input.value)");
   checkJsTermCompletionValue(jsterm, "   ument", "'docu' completion (completeNode)");
 
   // Test typing 'window.'.'
   await jstermComplete("window.");
@@ -71,27 +71,31 @@ async function performTests() {
   ok(getPopupLabels(popup).includes("getComputedStyle"),
     "autocomplete results do contain getComputedStyle");
 
   // Test if 'dump(d' gives non-zero results
   await jstermComplete("dump(d");
   ok(popup.getItems().length > 0, "'dump(d' gives non-zero results");
 
   // Test that 'dump(window.)' works.
-  await jstermComplete("dump(window.)", -1);
+  await jstermComplete("dump(window)", -1);
+  onUpdated = jsterm.once("autocomplete-updated");
+  EventUtils.sendString(".");
+  await onUpdated;
   ok(popup.getItems().length > 0, "'dump(window.' gave a list of suggestions");
 
   info("Add a property on the window object");
   await ContentTask.spawn(gBrowser.selectedBrowser, {}, () => {
     content.wrappedJSObject.window.docfoobar = true;
   });
 
   // Make sure 'dump(window.d)' does not contain 'docfoobar'.
   onUpdated = jsterm.once("autocomplete-updated");
-  EventUtils.synthesizeKey("d");
+  EventUtils.sendString("d");
   await onUpdated;
+
   ok(!getPopupLabels(popup).includes("docfoobar"),
     "autocomplete cached results do not contain docfoobar. list has not been updated");
 }
 
 function getPopupLabels(popup) {
   return popup.getItems().map(item => item.label);
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_extraneous_closing_brackets.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_extraneous_closing_brackets.js
@@ -18,14 +18,14 @@ add_task(async function() {
   await pushPref("devtools.webconsole.jsterm.codeMirror", true);
   await performTests();
 });
 
 async function performTests() {
   const { jsterm } = await openNewTabAndConsole(TEST_URI);
 
   try {
-    await jstermSetValueAndComplete(jsterm, "document.getElementById)");
+    await setInputValueForAutocompletion(jsterm, "document.getElementById)");
     ok(true, "no error was thrown when an extraneous bracket was inserted");
   } catch (ex) {
     ok(false, "an error was thrown when an extraneous bracket was inserted");
   }
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_helpers.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_helpers.js
@@ -23,23 +23,20 @@ async function performTests() {
   const {jsterm} = await openNewTabAndConsole(TEST_URI);
   await testInspectAutoCompletion(jsterm, "i", true);
   await testInspectAutoCompletion(jsterm, "window.", false);
   await testInspectAutoCompletion(jsterm, "dump(i", true);
   await testInspectAutoCompletion(jsterm, "window.dump(i", true);
 }
 
 async function testInspectAutoCompletion(jsterm, inputValue, expectInspect) {
-  jsterm.setInputValue(inputValue);
-  await complete(jsterm);
+  jsterm.setInputValue("");
+  jsterm.focus();
+  const updated = jsterm.once("autocomplete-updated");
+  EventUtils.sendString(inputValue);
+  await updated;
   is(getPopupItemsLabel(jsterm.autocompletePopup).includes("inspect"), expectInspect,
     `autocomplete results${expectInspect ? "" : " does not"} contain helper 'inspect'`);
 }
 
-function complete(jsterm) {
-  const updated = jsterm.once("autocomplete-updated");
-  jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
-  return updated;
-}
-
 function getPopupItemsLabel(popup) {
   return popup.getItems().map(item => item.label);
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_in_chrome_tab.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_in_chrome_tab.js
@@ -21,11 +21,11 @@ async function performTests() {
   ok(hud, "we have a console");
   ok(hud.iframeWindow, "we have the console UI window");
 
   const {jsterm} = hud;
   ok(jsterm, "we have a jsterm");
   ok(hud.outputNode, "we have an output node");
 
   // Test typing 'docu'.
-  await jstermSetValueAndComplete(jsterm, "docu");
+  await setInputValueForAutocompletion(jsterm, "docu");
   checkJsTermCompletionValue(jsterm, "    ment", "'docu' completion");
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_in_debugger_stackframe.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_in_debugger_stackframe.js
@@ -27,17 +27,17 @@ async function performTests() {
   const { jsterm } = await openNewTabAndConsole(TEST_URI);
   const {
     autocompletePopup: popup,
   } = jsterm;
 
   const target = TargetFactory.forTab(gBrowser.selectedTab);
   const toolbox = gDevTools.getToolbox(target);
 
-  const jstermComplete = value => jstermSetValueAndComplete(jsterm, value);
+  const jstermComplete = value => setInputValueForAutocompletion(jsterm, value);
 
   // Test that document.title gives string methods. Native getters must execute.
   await jstermComplete("document.title.");
 
   const newItemsLabels = getPopupLabels(popup);
   ok(newItemsLabels.length > 0, "'document.title.' gave a list of suggestions");
   ok(newItemsLabels.includes("substr"), `results do contain "substr"`);
   ok(newItemsLabels.includes("toLowerCase"), `results do contain "toLowerCase"`);
@@ -45,16 +45,17 @@ async function performTests() {
 
   // Test if 'foo' gives 'foo1' but not 'foo2' or 'foo3'
   await jstermComplete("foo");
   is(getPopupLabels(popup).join("-"), "foo1-foo1Obj",
     `"foo" gave the expected suggestions`);
 
   // Test if 'foo1Obj.' gives 'prop1' and 'prop2'
   await jstermComplete("foo1Obj.");
+  checkJsTermCompletionValue(jsterm, "        prop1", "foo1Obj completion");
   is(getPopupLabels(popup).join("-"), "prop1-prop2",
     `"foo1Obj." gave the expected suggestions`);
 
   // Test if 'foo1Obj.prop2.' gives 'prop21'
   await jstermComplete("foo1Obj.prop2.");
   ok(getPopupLabels(popup).includes("prop21"),
     `"foo1Obj.prop2." gave the expected suggestions`);
 
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_inside_text.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_autocomplete_inside_text.js
@@ -1,22 +1,28 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// See Bug 812618.
+// Test that editing text inside parens behave as expected, i.e.
+// - it does not show the autocompletion text
+// - show popup when there's properties to complete
+// - insert the selected item from the popup in the input
+// - right arrow dismiss popup and don't autocomplete
+// - tab key when there is not visible autocomplete suggestion insert a tab
+// See Bug 812618, 1479521 and 1334130.
 
 const TEST_URI = `data:text/html;charset=utf-8,
 <head>
   <script>
-    window.testBugA = "hello world";
-    window.testBugB = "hello world 2";
+    window.testBugAA = "hello world";
+    window.testBugBB = "hello world 2";
   </script>
 </head>
 <body>bug 812618 - test completion inside text</body>`;
 
 add_task(async function() {
   // Run test with legacy JsTerm
   await pushPref("devtools.webconsole.jsterm.codeMirror", false);
   await performTests();
@@ -26,40 +32,83 @@ add_task(async function() {
 });
 
 async function performTests() {
   const { jsterm } = await openNewTabAndConsole(TEST_URI);
   info("web console opened");
 
   const { autocompletePopup: popup } = jsterm;
 
-  const onPopUpOpen = popup.once("popup-opened");
-
-  const dumpString = "dump(window.testBu)";
-  jstermSetValueAndComplete(jsterm, dumpString, -1);
-
-  await onPopUpOpen;
+  await setInitialState(jsterm);
 
   ok(popup.isOpen, "popup is open");
   is(popup.itemCount, 2, "popup.itemCount is correct");
   is(popup.selectedIndex, 0, "popup.selectedIndex is correct");
+  ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
 
+  info("Pressing arrow right");
+  let onPopupClose = popup.once("popup-closed");
+  EventUtils.synthesizeKey("KEY_ArrowRight");
+  await onPopupClose;
+  ok(true, "popup was closed");
+  let expectedInput = "dump(window.testB)";
+  is(jsterm.getInputValue(), expectedInput, "input wasn't modified");
+  checkJsTermCursor(jsterm, expectedInput.length, "cursor was moved to the right");
+
+  await setInitialState(jsterm);
   EventUtils.synthesizeKey("KEY_ArrowDown");
   is(popup.selectedIndex, 1, "popup.selectedIndex is correct");
   ok(!getJsTermCompletionValue(jsterm), "completeNode.value is empty");
 
   const items = popup.getItems().map(e => e.label);
-  const expectedItems = ["testBugA", "testBugB"];
+  const expectedItems = ["testBugAA", "testBugBB"];
   is(items.join("-"), expectedItems.join("-"), "getItems returns the items we expect");
 
   info("press Tab and wait for popup to hide");
-  const onPopupClose = popup.once("popup-closed");
+  onPopupClose = popup.once("popup-closed");
   EventUtils.synthesizeKey("KEY_Tab");
-
   await onPopupClose;
 
   // At this point the completion suggestion should be accepted.
   ok(!popup.isOpen, "popup is not open");
-  const expectedInput = "dump(window.testBugB)";
+  expectedInput = "dump(window.testBugBB)";
   is(jsterm.getInputValue(), expectedInput, "completion was successful after VK_TAB");
   checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
-  ok(!getJsTermCompletionValue(jsterm), "completeNode is empty");
+  ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
+
+  info("Test ENTER key when popup is visible with a selected item");
+  await setInitialState(jsterm);
+  info("press Enter and wait for popup to hide");
+  onPopupClose = popup.once("popup-closed");
+  EventUtils.synthesizeKey("KEY_Enter");
+  await onPopupClose;
+
+  ok(!popup.isOpen, "popup is not open");
+  expectedInput = "dump(window.testBugAA)";
+  is(jsterm.getInputValue(), expectedInput, "completion was successful after Enter");
+  checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
+  ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
+
+  info("Test TAB key when there is no autocomplete suggestion");
+  jsterm.setInputValue("dump()");
+  EventUtils.synthesizeKey("KEY_ArrowLeft");
+  const onAutocompleteUpdated = jsterm.once("autocomplete-updated");
+  EventUtils.sendString("window.testBugA");
+  await onAutocompleteUpdated;
+  ok(!popup.isOpen, "popup is not open");
+  ok(!getJsTermCompletionValue(jsterm), "there is no completion text");
+
+  EventUtils.synthesizeKey("KEY_Tab");
+
+  expectedInput = "dump(window.testBugAA)";
+  is(jsterm.getInputValue(), "dump(window.testBugA\t)", "Tab inserted a tab char");
+  checkJsTermCursor(jsterm, expectedInput.length - 1, "cursor location is correct");
 }
+
+function setInitialState(jsterm) {
+  jsterm.focus();
+  jsterm.setInputValue("dump()");
+  EventUtils.synthesizeKey("KEY_ArrowLeft");
+
+  const onPopUpOpen = jsterm.autocompletePopup.once("popup-opened");
+  EventUtils.sendString("window.testB");
+  return onPopUpOpen;
+}
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_completion.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_completion.js
@@ -18,67 +18,84 @@ add_task(async function() {
   await performTests();
 });
 
 async function performTests() {
   const {jsterm, ui} = await openNewTabAndConsole(TEST_URI);
   const {autocompletePopup} = jsterm;
 
   // Test typing 'docu'.
-  await jstermSetValueAndComplete(jsterm, "docu");
+  await setInputValueForAutocompletion(jsterm, "docu");
   is(jsterm.getInputValue(), "docu", "'docu' completion (input.value)");
   checkJsTermCompletionValue(jsterm, "    ment", "'docu' completion (completeNode)");
   is(autocompletePopup.items.length, 1, "autocomplete popup has 1 item");
-  ok(autocompletePopup.isOpen, "autocomplete popup is open with 1 item");
+  is(autocompletePopup.isOpen, false, "autocomplete popup is not open");
 
   // Test typing 'docu' and press tab.
-  await jstermSetValueAndComplete(jsterm, "docu", undefined, jsterm.COMPLETE_FORWARD);
+  EventUtils.synthesizeKey("KEY_Tab");
   is(jsterm.getInputValue(), "document", "'docu' tab completion");
 
   checkJsTermCursor(jsterm, "document".length, "cursor is at the end of 'document'");
   is(getJsTermCompletionValue(jsterm).replace(/ /g, ""), "", "'docu' completed");
 
   // Test typing 'window.Ob' and press tab.  Just 'window.O' is
   // ambiguous: could be window.Object, window.Option, etc.
-  await jstermSetValueAndComplete(jsterm, "window.Ob", undefined,
-                                  jsterm.COMPLETE_FORWARD);
+  await setInputValueForAutocompletion(jsterm, "window.Ob");
+  EventUtils.synthesizeKey("KEY_Tab");
   is(jsterm.getInputValue(), "window.Object", "'window.Ob' tab completion");
 
   // Test typing 'document.getElem'.
-  await jstermSetValueAndComplete(
-    jsterm, "document.getElem", undefined, jsterm.COMPLETE_FORWARD);
+  const onPopupOpened = autocompletePopup.once("popup-opened");
+  await setInputValueForAutocompletion(jsterm, "document.getElem");
   is(jsterm.getInputValue(), "document.getElem", "'document.getElem' completion");
   checkJsTermCompletionValue(jsterm, "                entById",
      "'document.getElem' completion");
 
-  // Test pressing tab another time.
-  await jsterm.complete(jsterm.COMPLETE_FORWARD);
+  // Test pressing key down.
+  await onPopupOpened;
+  EventUtils.synthesizeKey("KEY_ArrowDown");
   is(jsterm.getInputValue(), "document.getElem", "'document.getElem' completion");
   checkJsTermCompletionValue(jsterm, "                entsByClassName",
      "'document.getElem' another tab completion");
 
-  // Test pressing shift_tab.
-  await jstermComplete(jsterm, jsterm.COMPLETE_BACKWARD);
+  // Test pressing key up.
+  EventUtils.synthesizeKey("KEY_ArrowUp");
+  await waitFor(() => (getJsTermCompletionValue(jsterm) || "").includes("entById"));
   is(jsterm.getInputValue(), "document.getElem", "'document.getElem' untab completion");
   checkJsTermCompletionValue(jsterm, "                entById",
      "'document.getElem' completion");
 
   ui.clearOutput();
 
-  await jstermSetValueAndComplete(jsterm, "docu");
+  await setInputValueForAutocompletion(jsterm, "docu");
   checkJsTermCompletionValue(jsterm, "    ment", "'docu' completion");
 
+  let onAutocompletUpdated = jsterm.once("autocomplete-updated");
   await jsterm.execute();
   checkJsTermCompletionValue(jsterm, "", "clear completion on execute()");
 
-  // Test multi-line completion works
-  await jstermSetValueAndComplete(jsterm, "console.log('one');\nconsol");
-  checkJsTermCompletionValue(jsterm, "                   \n      e",
-     "multi-line completion");
+  // Test multi-line completion works. We can't use setInputValueForAutocompletion because
+  // it would trigger an evaluation (because of the new line, an Enter keypress is
+  // simulated).
+  onAutocompletUpdated = jsterm.once("autocomplete-updated");
+  jsterm.setInputValue("console.log('one');\n");
+  EventUtils.sendString("consol");
+  await onAutocompletUpdated;
+  checkJsTermCompletionValue(jsterm, "\n      e", "multi-line completion");
+
+  // Test multi-line completion works even if there is text after the cursor
+  onAutocompletUpdated = jsterm.once("autocomplete-updated");
+  jsterm.setInputValue("{\n\n}");
+  EventUtils.synthesizeKey("KEY_ArrowUp");
+  EventUtils.sendString("console.g");
+  await onAutocompletUpdated;
+  checkJsTermValueAndCursor(jsterm, "{\nconsole.g|\n}");
+  checkJsTermCompletionValue(jsterm, "\n         roup", "multi-line completion");
+  is(autocompletePopup.isOpen, true, "popup is opened");
 
   // Test non-object autocompletion.
-  await jstermSetValueAndComplete(jsterm, "Object.name.sl");
+  await setInputValueForAutocompletion(jsterm, "Object.name.sl");
   checkJsTermCompletionValue(jsterm, "              ice", "non-object completion");
 
   // Test string literal autocompletion.
-  await jstermSetValueAndComplete(jsterm, "'Asimov'.sl");
+  await setInputValueForAutocompletion(jsterm, "'Asimov'.sl");
   checkJsTermCompletionValue(jsterm, "           ice", "string literal completion");
 }
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_content_defined_helpers.js
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_content_defined_helpers.js
@@ -45,17 +45,17 @@ add_task(async function() {
   await performTests();
 });
 
 async function performTests() {
   const {jsterm} = await openNewTabAndConsole(TEST_URI);
   const {autocompletePopup} = jsterm;
 
   for (const helper of HELPERS) {
-    await jstermSetValueAndComplete(jsterm, helper);
+    await setInputValueForAutocompletion(jsterm, helper);
     const autocompleteItems = getPopupLabels(autocompletePopup).filter(l => l === helper);
     is(autocompleteItems.length, 1,
       `There's no duplicated "${helper}" item in the autocomplete popup`);
     const msg = await jsterm.execute(`${helper}()`);
     ok(msg.textContent.includes(PREFIX + helper), `output is correct for ${helper}()`);
   }
 }
 
deleted file mode 100644
--- a/devtools/client/webconsole/test/mochitest/browser_jsterm_no_autocompletion_on_defined_variables.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Tests for bug 704295
-
-"use strict";
-
-const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
-                 "test/mochitest/test-console.html";
-
-add_task(async function() {
-  // 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() {
-  const hud = await openNewTabAndConsole(TEST_URI);
-  const jsterm = hud.jsterm;
-
-  // Test typing 'var d = 5;' and press RETURN
-  jsterm.setInputValue("var d = ");
-  EventUtils.sendString("5;");
-  is(jsterm.getInputValue(), "var d = 5;", "var d = 5;");
-  checkJsTermCompletionValue(jsterm, "", "no completion");
-  EventUtils.synthesizeKey("KEY_Enter");
-  checkJsTermCompletionValue(jsterm, "", "clear completion on execute()");
-
-  // Test typing 'var a = d' and press RETURN
-  jsterm.setInputValue("var a = ");
-  EventUtils.sendString("d");
-  is(jsterm.getInputValue(), "var a = d", "var a = d");
-  checkJsTermCompletionValue(jsterm, "", "no completion");
-  EventUtils.synthesizeKey("KEY_Enter");
-  checkJsTermCompletionValue(jsterm, "", "clear completion on execute()");
-}
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_closing_after_completion.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_closing_after_completion.js
@@ -12,17 +12,17 @@ const TEST_URI = "http://example.com/bro
                  "test/mochitest/test-console.html";
 
 add_task(async function() {
   const tab = await addTab(TEST_URI);
   const browser = tab.linkedBrowser;
   const hud = await openConsole();
 
   // Fire a completion.
-  await jstermSetValueAndComplete(hud.jsterm, "doc");
+  await setInputValueForAutocompletion(hud.jsterm, "doc");
 
   let errorWhileClosing = false;
   function errorListener() {
     errorWhileClosing = true;
   }
 
   browser.addEventListener("error", errorListener);
   const onToolboxDestroyed = gDevTools.once("toolbox-destroyed");
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_split_escape_key.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_split_escape_key.js
@@ -22,18 +22,17 @@ add_task(async function() {
   const hud = toolbox.getPanel("webconsole").hud;
   const jsterm = hud.jsterm;
   ok(toolbox.splitConsole, "Split console is created.");
 
   info("Wait for the autocomplete to show suggestions for `document.location.`");
   const popup = jsterm.autocompletePopup;
   const onPopupShown = popup.once("popup-opened");
   jsterm.focus();
-  jsterm.setInputValue("document.location.");
-  EventUtils.sendKey("TAB", hud.iframeWindow);
+  EventUtils.sendString("document.location.");
   await onPopupShown;
 
   info("Send ESCAPE key and check that it only hides the autocomplete suggestions");
 
   const onPopupClosed = popup.once("popup-closed");
   EventUtils.sendKey("ESCAPE", toolbox.win);
   await onPopupClosed;
 
--- a/devtools/client/webconsole/test/mochitest/head.js
+++ b/devtools/client/webconsole/test/mochitest/head.js
@@ -342,76 +342,53 @@ async function checkClickOnNode(hud, too
  * Returns true if the give node is currently focused.
  */
 function hasFocus(node) {
   return node.ownerDocument.activeElement == node
     && node.ownerDocument.hasFocus();
 }
 
 /**
- * Set the value of the JsTerm and its caret position, and fire a completion request.
+ * Set the value of the JsTerm and its caret position, and wait for the autocompletion
+ * to be updated.
  *
  * @param {JsTerm} jsterm
  * @param {String} value : The value to set the jsterm to.
  * @param {Integer} caretPosition : The index where to place the cursor. A negative
  *                  number will place the caret at (value.length - offset) position.
  *                  Default to value.length (caret set at the end).
- * @param {Integer} completionType : One of the following jsterm property
- *                   - COMPLETE_FORWARD
- *                   - COMPLETE_BACKWARD
- *                   - COMPLETE_HINT_ONLY
- *                   - COMPLETE_PAGEUP
- *                   - COMPLETE_PAGEDOWN
- *                  Will default to COMPLETE_HINT_ONLY.
  * @returns {Promise} resolves when the jsterm is completed.
  */
-function jstermSetValueAndComplete(
+async function setInputValueForAutocompletion(
   jsterm,
   value,
   caretPosition = value.length,
-  completionType
 ) {
-  jsterm.setInputValue(value);
+  jsterm.setInputValue("");
+  jsterm.focus();
+
+  const updated = jsterm.once("autocomplete-updated");
+  EventUtils.sendString(value);
+  await updated;
 
   if (caretPosition < 0) {
     caretPosition = value.length + caretPosition;
   }
 
   if (Number.isInteger(caretPosition)) {
     if (jsterm.inputNode) {
       const {inputNode} = jsterm;
       inputNode.value = value;
       inputNode.setSelectionRange(caretPosition, caretPosition);
     }
 
     if (jsterm.editor) {
       jsterm.editor.setCursor(jsterm.editor.getPosition(caretPosition));
     }
   }
-
-  return jstermComplete(jsterm, completionType);
-}
-
-/**
- * Fires a completion request on the jsterm with the specified completionType
- *
- * @param {JsTerm} jsterm
- * @param {Integer} completionType : One of the following jsterm property
- *                   - COMPLETE_FORWARD
- *                   - COMPLETE_BACKWARD
- *                   - COMPLETE_HINT_ONLY
- *                   - COMPLETE_PAGEUP
- *                   - COMPLETE_PAGEDOWN
- *                  Will default to COMPLETE_HINT_ONLY.
- * @returns {Promise} resolves when the jsterm is completed.
- */
-function jstermComplete(jsterm, completionType = jsterm.COMPLETE_HINT_ONLY) {
-  const updated = jsterm.once("autocomplete-updated");
-  jsterm.complete(completionType);
-  return updated;
 }
 
 /**
  * Checks if the jsterm has the expected completion value.
  *
  * @param {JsTerm} jsterm
  * @param {String} expectedValue
  * @param {String} assertionInfo: Description of the assertion passed to `is`.
--- a/devtools/server/actors/targets/browsing-context.js
+++ b/devtools/server/actors/targets/browsing-context.js
@@ -1602,26 +1602,29 @@ DebuggerProgressListener.prototype = {
     }
   }, "DebuggerProgressListener.prototype.observe"),
 
   onStateChange:
   DevToolsUtils.makeInfallible(function(progress, request, flag, status) {
     if (!this._targetActor.attached) {
       return;
     }
+    progress.QueryInterface(Ci.nsIDocShell);
+    if (progress.isBeingDestroyed()) {
+      return;
+    }
 
     const isStart = flag & Ci.nsIWebProgressListener.STATE_START;
     const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
     const isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
     const isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
 
     // Catch any iframe location change
     if (isDocument && isStop) {
       // Watch document stop to ensure having the new iframe url.
-      progress.QueryInterface(Ci.nsIDocShell);
       this._targetActor._notifyDocShellsUpdate([progress]);
     }
 
     const window = progress.DOMWindow;
     if (isDocument && isStart) {
       // One of the earliest events that tells us a new URI
       // is being loaded in this window.
       const newURI = request instanceof Ci.nsIChannel ? request.URI.spec : null;
--- a/devtools/shared/builtin-modules.js
+++ b/devtools/shared/builtin-modules.js
@@ -216,37 +216,36 @@ exports.modules = {
   // Expose "chrome" Promise, which aren't related to any document
   // and so are never frozen, even if the browser loader module which
   // pull it is destroyed. See bug 1402779.
   Promise,
   Services: Object.create(Services),
 };
 
 defineLazyGetter(exports.modules, "Debugger", () => {
-  // addDebuggerToGlobal only allows adding the Debugger object to a global. The
-  // this object is not guaranteed to be a global (in particular on B2G, due to
-  // compartment sharing), so add the Debugger object to a sandbox instead.
-  const sandbox = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
-  Cu.evalInSandbox(
-    "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
-    "addDebuggerToGlobal(this);",
-    sandbox
-  );
-  return sandbox.Debugger;
+  const global = Cu.getGlobalForObject(this);
+  // Debugger may already have been added by RecordReplayControl getter
+  if (global.Debugger) {
+    return global.Debugger;
+  }
+  const { addDebuggerToGlobal } = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {});
+  addDebuggerToGlobal(global);
+  return global.Debugger;
 });
 
 defineLazyGetter(exports.modules, "RecordReplayControl", () => {
   // addDebuggerToGlobal also adds the RecordReplayControl object.
-  const sandbox = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
-  Cu.evalInSandbox(
-    "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
-    "addDebuggerToGlobal(this);",
-    sandbox
-  );
-  return sandbox.RecordReplayControl;
+  const global = Cu.getGlobalForObject(this);
+  // RecordReplayControl may already have been added by Debugger getter
+  if (global.RecordReplayControl) {
+    return global.RecordReplayControl;
+  }
+  const { addDebuggerToGlobal } = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm", {});
+  addDebuggerToGlobal(global);
+  return global.RecordReplayControl;
 });
 
 defineLazyGetter(exports.modules, "Timer", () => {
   const {setTimeout, clearTimeout} = require("resource://gre/modules/Timer.jsm");
   // Do not return Cu.import result, as DevTools loader would freeze Timer.jsm globals...
   return {
     setTimeout,
     clearTimeout
--- a/devtools/shared/webconsole/client.js
+++ b/devtools/shared/webconsole/client.js
@@ -366,32 +366,30 @@ WebConsoleClient.prototype = {
 
   /**
    * Autocomplete a JavaScript expression.
    *
    * @param string string
    *        The code you want to autocomplete.
    * @param number cursor
    *        Cursor location inside the string. Index starts from 0.
-   * @param function onResponse
-   *        The function invoked when the response is received.
    * @param string frameActor
    *        The id of the frame actor that made the call.
    * @return request
    *         Request object that implements both Promise and EventEmitter interfaces
    */
-  autocomplete: function(string, cursor, onResponse, frameActor) {
+  autocomplete: function(string, cursor, frameActor) {
     const packet = {
       to: this._actor,
       type: "autocomplete",
       text: string,
       cursor: cursor,
       frameActor: frameActor,
     };
-    return this._client.request(packet, onResponse);
+    return this._client.request(packet);
   },
 
   /**
    * Clear the cache of messages (page errors and console API calls).
    *
    * @return request
    *         Request object that implements both Promise and EventEmitter interfaces
    */
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -475,17 +475,26 @@ NetworkResponseListener.prototype = {
     try {
       if (channel instanceof Ci.nsICacheInfoChannel) {
         isOptimizedContent = channel.alternativeDataType;
       }
     } catch (e) {
       // Accessing `alternativeDataType` for some SW requests throws.
     }
     if (isOptimizedContent) {
-      const charset = this.request.contentCharset || this.httpActivity.charset;
+      let charset;
+      try {
+        charset = this.request.contentCharset;
+      } catch (e) {
+        // Accessing the charset sometimes throws NS_ERROR_NOT_AVAILABLE when
+        // reloading the page
+      }
+      if (!charset) {
+        charset = this.httpActivity.charset;
+      }
       NetworkHelper.loadFromCache(this.httpActivity.url, charset,
                                   this._onComplete.bind(this));
       return;
     }
 
     // In the multi-process mode, the conversion happens on the child
     // side while we can only monitor the channel on the parent
     // side. If the content is gzipped, we have to unzip it
@@ -631,17 +640,26 @@ NetworkResponseListener.prototype = {
       this._fetchCacheInformation();
     }
 
     if (!this.httpActivity.discardResponseBody && this.receivedData.length) {
       this._onComplete(this.receivedData);
     } else if (!this.httpActivity.discardResponseBody &&
                this.httpActivity.responseStatus == 304) {
       // Response is cached, so we load it from cache.
-      const charset = this.request.contentCharset || this.httpActivity.charset;
+      let charset;
+      try {
+        charset = this.request.contentCharset;
+      } catch (e) {
+        // Accessing the charset sometimes throws NS_ERROR_NOT_AVAILABLE when
+        // reloading the page
+      }
+      if (!charset) {
+        charset = this.httpActivity.charset;
+      }
       NetworkHelper.loadFromCache(this.httpActivity.url, charset,
                                   this._onComplete.bind(this));
     } else {
       this._onComplete();
     }
   },
 
   /**
--- a/devtools/shared/webconsole/test/test_jsterm_autocomplete.html
+++ b/devtools/shared/webconsole/test/test_jsterm_autocomplete.html
@@ -19,19 +19,17 @@ let {MAX_AUTOCOMPLETE_ATTEMPTS,MAX_AUTOC
 
 function evaluateJS(input, options = {}) {
   return new Promise((resolve, reject) => {
     gState.client.evaluateJSAsync(input, resolve, options);
   });
 }
 
 function autocompletePromise(str, cursor = str.length, frameActor) {
-  return new Promise(resolve => {
-    gState.client.autocomplete(str, cursor, resolve, frameActor);
-  });
+  return gState.client.autocomplete(str, cursor, frameActor);
 }
 
 // This test runs all of its assertions twice - once with
 // the tab as a target and once with a worker
 let runningInTab = true;
 function startTest({worker}) {
   if (worker) {
     attachConsoleToWorker(["PageError"], onAttach.bind(null, true));
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -3891,17 +3891,17 @@ nsFocusManager::TryToMoveFocusToSubDocum
                                             bool aForDocumentNavigation,
                                             nsIContent** aResultContent)
 {
   nsIDocument* doc = aCurrentContent->GetComposedDoc();
   NS_ASSERTION(doc, "content not in document");
   nsIDocument* subdoc = doc->GetSubDocumentFor(aCurrentContent);
   if (subdoc && !subdoc->EventHandlingSuppressed()) {
     if (aForward) {
-      // when tabbing forward into a frame, return the root
+      // When tabbing forward into a frame, return the root
       // frame so that the canvas becomes focused.
       nsCOMPtr<nsPIDOMWindowOuter> subframe = subdoc->GetWindow();
       if (subframe) {
         *aResultContent = GetRootForFocus(subframe, subdoc, false, true);
         if (*aResultContent) {
           NS_ADDREF(*aResultContent);
           return true;
         }
--- a/dom/media/gtest/TestAudioDeviceEnumerator.cpp
+++ b/dom/media/gtest/TestAudioDeviceEnumerator.cpp
@@ -567,8 +567,18 @@ TEST(CubebDeviceEnumerator, EnumerateAnd
   nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
   enumerator.EnumerateAudioInputDevices(inputDevices);
   EXPECT_EQ(inputDevices.Length(), 1u) <<  "Android always exposes a single input device.";
   EXPECT_EQ(inputDevices[0]->MaxChannels(), 1u) << "With a single channel.";
   EXPECT_EQ(inputDevices[0]->DeviceID(), nullptr) << "It's always the default device.";
   EXPECT_TRUE(inputDevices[0]->Preferred()) << "it's always the prefered device.";
 }
 #endif
+
+TEST(CubebDeviceEnumerator, ForceNullCubebContext)
+{
+  mozilla::CubebUtils::ForceSetCubebContext(nullptr);
+  CubebDeviceEnumerator enumerator;
+  nsTArray<RefPtr<AudioDeviceInfo>> inputDevices;
+  enumerator.EnumerateAudioInputDevices(inputDevices);
+  EXPECT_EQ(inputDevices.Length(), 0u) << "Enumeration must fail device list must be empty.";
+}
+
--- a/dom/media/gtest/moz.build
+++ b/dom/media/gtest/moz.build
@@ -82,12 +82,15 @@ LOCAL_INCLUDES += [
     '/dom/media/platforms/agnostic',
     '/security/certverifier',
     '/security/pkix/include',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
-    CXXFLAGS += ['-Wno-error=shadow', '-Wno-unused-private-field']
+    CXXFLAGS += ['-Wno-error=shadow']
+
+if CONFIG['CC_TYPE'] == 'clang':
+    CXXFLAGS += ['-Wno-unused-private-field']
 
 if CONFIG['CC_TYPE'] == 'clang-cl':
     AllowCompilerWarnings()  # workaround for bug 1090497
--- a/dom/media/tests/mochitest/test_getUserMedia_cubebDisabled.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_cubebDisabled.html
@@ -15,44 +15,26 @@
    * during a gUM call.
    */
   runTest(async function () {
     info("Get user media with cubeb disabled starting");
     // Push prefs to ensure no cubeb context and no fake streams.
     await pushPrefs(["media.cubeb.force_null_context", true],
                     ["media.navigator.streams.fake", false]);
 
-    // Android has its own codepath which means it works even when cubeb is
-    // disabled. For examples see MediaEngineWebRTC::GetNumOfRecordingDevices and
-    // MediaEngineWebRTC::GetRecordingDeviceName.
-    let isAndroid = navigator.appVersion.includes("Android");
-    // We're on android we expect to get an audio stream, create an elem for it
-    let testAudio = createMediaElement('audio', 'testAudio');
-
     // Request audio only, to avoid cams
     let constraints = {audio: true, video: false};
     let stream;
     try {
       stream = await getUserMedia(constraints);
     } catch (e) {
-      if (isAndroid) {
-        ok(false, `getUserMedia expected to succeed on android, even with null cubeb context, but got ${e}`);
-        return;
-      }
-      // !isAndroid
       // We've got no audio backend, so we expect gUM to fail.
       ok(e.name == "NotFoundError", "Expected NotFoundError due to no audio tracks!");
       return;
     }
-    if (isAndroid) {
-      ok(stream, "getUserMedia expected to return a stream on Android even when cubeb context null!");
-      let playback = new LocalMediaStreamPlayback(testAudio, stream);
-      return playback.playMedia(false);
-    }
-    // !isAndroid
     // If we're not on android we should not have gotten a stream without a cubeb context!
     ok(false, "getUserMedia not expected to succeed when cubeb is disabled, but it did!");
   });
 
 
 </script>
 </pre>
 </body>
--- a/dom/media/webrtc/MediaEngineWebRTC.cpp
+++ b/dom/media/webrtc/MediaEngineWebRTC.cpp
@@ -386,55 +386,53 @@ CubebDeviceEnumerator::~CubebDeviceEnume
   }
 }
 
 void
 CubebDeviceEnumerator::EnumerateAudioInputDevices(nsTArray<RefPtr<AudioDeviceInfo>>& aOutDevices)
 {
   aOutDevices.Clear();
 
-#ifdef ANDROID
-  // Bug 1473346: enumerating devices is not supported on Android in cubeb,
-  // simply state that there is a single mic, that it is the default, and has a
-  // single channel. All the other values are made up and are not to be used.
-  RefPtr<AudioDeviceInfo> info = new AudioDeviceInfo(nullptr,
-                                                     NS_ConvertUTF8toUTF16(""),
-                                                     NS_ConvertUTF8toUTF16(""),
-                                                     NS_ConvertUTF8toUTF16(""),
-                                                     CUBEB_DEVICE_TYPE_INPUT,
-                                                     CUBEB_DEVICE_STATE_ENABLED,
-                                                     CUBEB_DEVICE_PREF_ALL,
-                                                     CUBEB_DEVICE_FMT_ALL,
-                                                     CUBEB_DEVICE_FMT_S16NE,
-                                                     1,
-                                                     44100,
-                                                     44100,
-                                                     41000,
-                                                     410,
-                                                     128);
-  if (mDevices.IsEmpty()) {
-    mDevices.AppendElement(info);
-  }
-  aOutDevices.AppendElements(mDevices);
-#else
   cubeb* context = GetCubebContext();
-
   if (!context) {
     return;
   }
 
   MutexAutoLock lock(mMutex);
 
+#ifdef ANDROID
+  if (mDevices.IsEmpty()) {
+    // Bug 1473346: enumerating devices is not supported on Android in cubeb,
+    // simply state that there is a single mic, that it is the default, and has a
+    // single channel. All the other values are made up and are not to be used.
+    RefPtr<AudioDeviceInfo> info = new AudioDeviceInfo(nullptr,
+                                                       NS_ConvertUTF8toUTF16(""),
+                                                       NS_ConvertUTF8toUTF16(""),
+                                                       NS_ConvertUTF8toUTF16(""),
+                                                       CUBEB_DEVICE_TYPE_INPUT,
+                                                       CUBEB_DEVICE_STATE_ENABLED,
+                                                       CUBEB_DEVICE_PREF_ALL,
+                                                       CUBEB_DEVICE_FMT_ALL,
+                                                       CUBEB_DEVICE_FMT_S16NE,
+                                                       1,
+                                                       44100,
+                                                       44100,
+                                                       41000,
+                                                       410,
+                                                       128);
+    mDevices.AppendElement(info);
+  }
+#else
   if (mDevices.IsEmpty() || mManualInvalidation) {
     mDevices.Clear();
     CubebUtils::GetDeviceCollection(mDevices, CubebUtils::Input);
   }
+#endif
 
   aOutDevices.AppendElements(mDevices);
-#endif
 }
 
 already_AddRefed<AudioDeviceInfo>
 CubebDeviceEnumerator::DeviceInfoFromID(CubebUtils::AudioDeviceID aID)
 {
   MutexAutoLock lock(mMutex);
 
   for (uint32_t i  = 0; i < mDevices.Length(); i++) {
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -340,17 +340,17 @@ nsHtml5StreamParser::SetupDecodingAndWri
   return rv;
 }
 
 nsresult
 nsHtml5StreamParser::SetupDecodingFromBom(NotNull<const Encoding*> aEncoding)
 {
   NS_ASSERTION(IsParserThread(), "Wrong thread!");
   mEncoding = aEncoding;
-  mUnicodeDecoder = mEncoding->NewDecoderWithBOMRemoval();
+  mUnicodeDecoder = mEncoding->NewDecoderWithoutBOMHandling();
   mCharsetSource = kCharsetFromByteOrderMark;
   mFeedChardet = false;
   mTreeBuilder->SetDocumentCharset(mEncoding, mCharsetSource);
   mSniffingBuffer = nullptr;
   mMetaScanner = nullptr;
   mBomState = BOM_SNIFFING_OVER;
   return NS_OK;
 }
--- a/taskcluster/docker/funsize-update-generator/Pipfile.lock
+++ b/taskcluster/docker/funsize-update-generator/Pipfile.lock
@@ -68,20 +68,20 @@
         "backports.lzma": {
             "hashes": [
                 "sha256:50829db66f0445442f6c796bba0ca62d1f87f54760c4682b6d1489e729a43744"
             ],
             "version": "==0.0.13"
         },
         "certifi": {
             "hashes": [
-                "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
-                "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
+                "sha256:4c1d68a1408dd090d2f3a869aa94c3947cc1d967821d1ed303208c9f41f0f2f4",
+                "sha256:b6e8b28b2b7e771a41ecdd12d4d43262ecab52adebbafa42c77d6b57fb6ad3a4"
             ],
-            "version": "==2018.4.16"
+            "version": "==2018.8.13"
         },
         "cffi": {
             "hashes": [
                 "sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
                 "sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
                 "sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
                 "sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
                 "sha256:3bb6bd7266598f318063e584378b8e27c67de998a43362e8fce664c54ee52d30",
@@ -372,25 +372,25 @@
             ],
             "version": "==4.0.1"
         },
         "urllib3": {
             "hashes": [
                 "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
                 "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
             ],
-            "markers": "python_version != '3.1.*' and python_version != '3.0.*' and python_version < '4' and python_version != '3.2.*' and python_version != '3.3.*' and python_version >= '2.6'",
+            "markers": "python_version != '3.3.*' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*' and python_version < '4' and python_version >= '2.6'",
             "version": "==1.23"
         },
         "virtualenv": {
             "hashes": [
                 "sha256:2ce32cd126117ce2c539f0134eb89de91a8413a29baac49cbab3eb50e2026669",
                 "sha256:ca07b4c0b54e14a91af9f34d0919790b016923d157afda5efdde55c96718f752"
             ],
-            "markers": "python_version != '3.1.*' and python_version != '3.0.*' and python_version != '3.2.*' and python_version >= '2.7'",
+            "markers": "python_version >= '2.7' and python_version != '3.1.*' and python_version != '3.2.*' and python_version != '3.0.*'",
             "version": "==16.0.0"
         },
         "yarl": {
             "hashes": [
                 "sha256:2556b779125621b311844a072e0ed367e8409a18fa12cbd68eb1258d187820f9",
                 "sha256:4aec0769f1799a9d4496827292c02a7b1f75c0bab56ab2b60dd94ebb57cbd5ee",
                 "sha256:55369d95afaacf2fa6b49c84d18b51f1704a6560c432a0f9a1aeb23f7b971308",
                 "sha256:6c098b85442c8fe3303e708bbb775afd0f6b29f77612e8892627bcab4b939357",
--- a/testing/talos/talos/tests/devtools/addon/content/tests/webconsole/autocomplete.js
+++ b/testing/talos/talos/tests/devtools/addon/content/tests/webconsole/autocomplete.js
@@ -47,28 +47,22 @@ module.exports = async function() {
 };
 
 async function showAndHideAutoCompletePopup(jsterm) {
   await triggerAutocompletePopup(jsterm);
   await hideAutocompletePopup(jsterm);
 }
 
 async function triggerAutocompletePopup(jsterm) {
+  const onPopupOpened = jsterm.autocompletePopup.once("popup-opened");
   jsterm.setInputValue("window.autocompleteTest.");
-  const onPopupOpened = jsterm.autocompletePopup.once("popup-opened");
-  // setInputValue does not trigger the autocompletion; we need to call `complete` in
-  // order to display the popup.
-  jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
   await onPopupOpened;
 
   const onPopupUpdated = jsterm.once("autocomplete-updated");
   jsterm.setInputValue("window.autocompleteTest.item9");
-  jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
-
   await onPopupUpdated;
 }
 
 function hideAutocompletePopup(jsterm) {
   let onPopUpClosed = jsterm.autocompletePopup.once("popup-closed");
   jsterm.setInputValue("");
-  jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
   return onPopUpClosed;
 }
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -275968,16 +275968,31 @@
      {}
     ]
    ],
    "encoding/resources/text-plain-charset.py": [
     [
      {}
     ]
    ],
+   "encoding/resources/two-boms-utf-16be.html": [
+    [
+     {}
+    ]
+   ],
+   "encoding/resources/two-boms-utf-16le.html": [
+    [
+     {}
+    ]
+   ],
+   "encoding/resources/two-boms-utf-8.html": [
+    [
+     {}
+    ]
+   ],
    "encoding/resources/utf-32-big-endian-bom.html": [
     [
      {}
     ]
    ],
    "encoding/resources/utf-32-big-endian-bom.xml": [
     [
      {}
@@ -348193,16 +348208,22 @@
     ],
     [
      "/encoding/legacy-mb-tchinese/big5/big5-encode-href.html?9001-10000",
      {
       "timeout": "long"
      }
     ]
    ],
+   "encoding/remove-only-one-bom.html": [
+    [
+     "/encoding/remove-only-one-bom.html",
+     {}
+    ]
+   ],
    "encoding/replacement-encodings.any.js": [
     [
      "/encoding/replacement-encodings.any.html",
      {}
     ],
     [
      "/encoding/replacement-encodings.any.worker.html",
      {}
@@ -582068,16 +582089,20 @@
   "encoding/legacy-mb-tchinese/big5/big5_errors.html.headers": [
    "49773a44f8de6275f1fa88dca396ec0178e90acf",
    "support"
   ],
   "encoding/legacy-mb-tchinese/big5/big5_index.js": [
    "9ab1182ad7292cd6e4d8c9c5739f534e21976fd0",
    "support"
   ],
+  "encoding/remove-only-one-bom.html": [
+   "8b91f7f349b6ca2585e1786e791bc88840262698",
+   "testharness"
+  ],
   "encoding/replacement-encodings.any.js": [
    "784dd953e33ef9134a1b9647327bf169f3116ef8",
    "testharness"
   ],
   "encoding/resources/decode-common.js": [
    "19dd6939ac197efc5cd38d133a8cdc66e321ad04",
    "support"
   ],
@@ -582104,16 +582129,28 @@
   "encoding/resources/single-byte-raw.py": [
    "b4a6c90405ec85d2d15222c2445fd9dcb12c8462",
    "support"
   ],
   "encoding/resources/text-plain-charset.py": [
    "a1c07e70189bce25c4002f447a544b64224967fd",
    "support"
   ],
+  "encoding/resources/two-boms-utf-16be.html": [
+   "6a5b0a5517fd422b7859f8332416523198aebec0",
+   "support"
+  ],
+  "encoding/resources/two-boms-utf-16le.html": [
+   "535a40d398d3b50bba40269639524022ae0c2fcf",
+   "support"
+  ],
+  "encoding/resources/two-boms-utf-8.html": [
+   "83ea941a53699c09d06ee4f952ddad699e8ba3d6",
+   "support"
+  ],
   "encoding/resources/utf-32-big-endian-bom.html": [
    "79679cac759429625fde26de63a959d9f4bcb782",
    "support"
   ],
   "encoding/resources/utf-32-big-endian-bom.xml": [
    "399c35af827db47ca43d09d552b973ef31208a08",
    "support"
   ],
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/encoding/remove-only-one-bom.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+setup({explicit_done:true});
+function runTests() {
+    for (var i = 0; i < window.frames.length; i++) {
+        test(function() {
+            assert_equals(window.frames[i].window.document.body.textContent, "\uFEFF");
+        }, "Should have removed only one BOM from frame " + i);
+    }
+    done();
+}
+</script>
+<body onload="runTests()">
+<iframe src="resources/two-boms-utf-8.html"></iframe>
+<iframe src="resources/two-boms-utf-16le.html"></iframe>
+<iframe src="resources/two-boms-utf-16be.html"></iframe>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/encoding/resources/two-boms-utf-16be.html
@@ -0,0 +1,1 @@
+
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/encoding/resources/two-boms-utf-16le.html
@@ -0,0 +1,1 @@
+
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/encoding/resources/two-boms-utf-8.html
@@ -0,0 +1,1 @@
+
\ No newline at end of file
--- a/widget/LookAndFeel.h
+++ b/widget/LookAndFeel.h
@@ -101,17 +101,19 @@ public:
     // Colors which will hopefully become CSS3
     eColorID__moz_field,
     eColorID__moz_fieldtext,
     eColorID__moz_dialog,
     eColorID__moz_dialogtext,
     // used to highlight valid regions to drop something onto
     eColorID__moz_dragtargetzone,
 
-    // used to cell text background, selected but not focus
+    // used to cell text background, selected but not focus.
+    // It is not necessarily a system color, but it is
+    // distinct from -moz-appearance: listbox; and Highlight
     eColorID__moz_cellhighlight,
     // used to cell text, selected but not focus
     eColorID__moz_cellhighlighttext,
     // used to html select cell text background, selected but not focus
     eColorID__moz_html_cellhighlight,
     // used to html select cell text, selected but not focus
     eColorID__moz_html_cellhighlighttext,
     // used to button text background, when mouse is over
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -119,16 +119,17 @@ else:
         'WidgetStyleCache.cpp',
     ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
+    '/layout/base',
     '/layout/generic',
     '/layout/xul',
     '/other-licenses/atk-1.0',
     '/widget',
     '/widget/headless',
 ]
 
 if CONFIG['MOZ_X11']:
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -27,16 +27,17 @@
 #include "WidgetUtils.h"
 #include "nsWindow.h"
 
 #include "mozilla/gfx/2D.h"
 
 #include <cairo-gobject.h>
 #include "WidgetStyleCache.h"
 #include "prenv.h"
+#include "nsCSSColorUtils.h"
 
 using namespace mozilla;
 using mozilla::LookAndFeel;
 
 #define GDK_COLOR_TO_NS_RGB(c) \
     ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
 #define GDK_RGBA_TO_NS_RGBA(c) \
     ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \
@@ -210,16 +211,68 @@ GetBorderColors(GtkStyleContext* aContex
 {
     GdkRGBA lightColor, darkColor;
     bool ret = GetBorderColors(aContext, &lightColor, &darkColor);
     *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor);
     *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor);
     return ret;
 }
 
+// Finds ideal cell highlight colors used for unfocused+selected cells distinct
+// from both Highlight, used as focused+selected background, and the listbox
+// background which is assumed to be similar to -moz-field
+nsresult
+nsLookAndFeel::InitCellHighlightColors() {
+    // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE is the a11y standard for text
+    // on a background. Use 20% of that standard since we have a background
+    // on top of another background
+    int32_t minLuminosityDifference = NS_SUFFICIENT_LUMINOSITY_DIFFERENCE / 5;
+    int32_t backLuminosityDifference = NS_LUMINOSITY_DIFFERENCE(
+        mMozWindowBackground, mMozFieldBackground);
+    if (backLuminosityDifference >= minLuminosityDifference) {
+        mMozCellHighlightBackground = mMozWindowBackground;
+        mMozCellHighlightText = mMozWindowText;
+        return NS_OK;
+    }
+
+    uint16_t hue, sat, luminance;
+    uint8_t alpha;
+    mMozCellHighlightBackground = mMozFieldBackground;
+    mMozCellHighlightText = mMozFieldText;
+
+    NS_RGB2HSV(mMozCellHighlightBackground, hue, sat, luminance, alpha);
+
+    uint16_t step = 30;
+    // Lighten the color if the color is very dark
+    if (luminance <= step) {
+        luminance += step;
+    }
+    // Darken it if it is very light
+    else if (luminance >= 255 - step) {
+        luminance -= step;
+    }
+    // Otherwise, compute what works best depending on the text luminance.
+    else {
+        uint16_t textHue, textSat, textLuminance;
+        uint8_t textAlpha;
+        NS_RGB2HSV(mMozCellHighlightText, textHue, textSat, textLuminance,
+            textAlpha);
+        // Text is darker than background, use a lighter shade
+        if (textLuminance < luminance) {
+            luminance += step;
+        }
+        // Otherwise, use a darker shade
+        else {
+            luminance -= step;
+        }
+    }
+    NS_HSV2RGB(mMozCellHighlightBackground, hue, sat, luminance, alpha);
+    return NS_OK;
+}
+
 void
 nsLookAndFeel::NativeInit()
 {
     EnsureInit();
 }
 
 void
 nsLookAndFeel::RefreshImpl()
@@ -266,30 +319,34 @@ nsLookAndFeel::NativeGetColor(ColorID aI
     case eColorID__moz_dialogtext:
         aColor = mMozWindowText;
         break;
     case eColorID_WidgetSelectBackground:
     case eColorID_TextSelectBackground:
     case eColorID_IMESelectedRawTextBackground:
     case eColorID_IMESelectedConvertedTextBackground:
     case eColorID__moz_dragtargetzone:
-    case eColorID__moz_cellhighlight:
     case eColorID__moz_html_cellhighlight:
     case eColorID_highlight: // preference selected item,
         aColor = mTextSelectedBackground;
         break;
     case eColorID_WidgetSelectForeground:
     case eColorID_TextSelectForeground:
     case eColorID_IMESelectedRawTextForeground:
     case eColorID_IMESelectedConvertedTextForeground:
     case eColorID_highlighttext:
-    case eColorID__moz_cellhighlighttext:
     case eColorID__moz_html_cellhighlighttext:
         aColor = mTextSelectedText;
         break;
+    case eColorID__moz_cellhighlight:
+        aColor = mMozCellHighlightBackground;
+        break;
+    case eColorID__moz_cellhighlighttext:
+        aColor = mMozCellHighlightText;
+        break;
     case eColorID_Widget3DHighlight:
         aColor = NS_RGB(0xa0,0xa0,0xa0);
         break;
     case eColorID_Widget3DShadow:
         aColor = NS_RGB(0x40,0x40,0x40);
         break;
     case eColorID_IMERawInputBackground:
     case eColorID_IMEConvertedTextBackground:
@@ -1017,16 +1074,19 @@ nsLookAndFeel::EnsureInit()
 
     // Get odd row background color
     gtk_style_context_save(style);
     gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     mOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_restore(style);
 
+    // Compute cell highlight colors
+    InitCellHighlightColors();
+
     // GtkFrame has a "border" subnode on which Adwaita draws the border.
     // Some themes do not draw on this node but draw a border on the widget
     // root node, so check the root node if no border is found on the border
     // node.
     style = GetStyleContext(MOZ_GTK_FRAME_BORDER);
     bool themeUsesColors =
         GetBorderColors(style, &mFrameOuterLightBorder, &mFrameInnerDarkBorder);
     if (!themeUsesColors) {
--- a/widget/gtk/nsLookAndFeel.h
+++ b/widget/gtk/nsLookAndFeel.h
@@ -72,25 +72,30 @@ protected:
     nscolor mComboBoxBackground;
     nscolor mMozFieldText;
     nscolor mMozFieldBackground;
     nscolor mMozWindowText;
     nscolor mMozWindowBackground;
     nscolor mMozWindowActiveBorder;
     nscolor mMozWindowInactiveBorder;
     nscolor mMozWindowInactiveCaption;
+    nscolor mMozCellHighlightBackground;
+    nscolor mMozCellHighlightText;
     nscolor mTextSelectedText;
     nscolor mTextSelectedBackground;
     nscolor mMozScrollbar;
     nscolor mInfoBarText;
     char16_t mInvisibleCharacter;
     float   mCaretRatio;
     bool    mMenuSupportsDrag;
     bool    mCSDAvailable;
     bool    mCSDMaximizeButton;
     bool    mCSDMinimizeButton;
     bool    mCSDCloseButton;
     bool    mInitialized;
 
     void EnsureInit();
+
+private:
+    nsresult InitCellHighlightColors();
 };
 
 #endif