Merge mozilla-central to inbound. a=merge CLOSED TREE
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Thu, 15 Feb 2018 22:43:18 +0200
changeset 404039 a7d2a49f46fbbe9e39650ea1e9acd457b01f8337
parent 403990 64db6b9c2139dbb7aec1850187516058e85e29cd (current diff)
parent 404038 994a8d6eccbcdc6106794705bd77e3ac5f031be2 (diff)
child 404040 a9db2b954595da03b7ca54fd1b9d76d9953564b0
push id99924
push userebalazs@mozilla.com
push dateThu, 15 Feb 2018 20:43:51 +0000
treeherdermozilla-inbound@a7d2a49f46fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.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
browser/base/content/defaultthemes/compact.header.png
devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_violation.js
devtools/client/webconsole/new-console-output/test/mochitest/test_bug_1247459_violation.html
dom/html/nsGenericHTMLElement.cpp
js/src/shell/js.cpp
modules/libpref/init/all.js
--- a/accessible/interfaces/gecko/Makefile.in
+++ b/accessible/interfaces/gecko/Makefile.in
@@ -7,17 +7,19 @@ GARBAGE += $(MIDL_GENERATED_FILES) done_
 MIDL_GENERATED_FILES = \
   dlldata.c \
   IGeckoCustom.h \
   IGeckoCustom_p.c \
   IGeckoCustom_i.c \
   IGeckoCustom.tlb \
   $(NULL)
 
-$(MIDL_GENERATED_FILES): done_gen
+# Bug 1420119: We need the trailing semicolon here to generate a recipe for the
+# midl targets to avoid timestamp caching issues.
+$(MIDL_GENERATED_FILES): done_gen ;
 
 done_gen: IGeckoCustom.idl
 	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -Oicf $(srcdir)/IGeckoCustom.idl
 	touch $@
 
 export:: done_gen
 
 midl_exports := \
--- a/accessible/interfaces/ia2/Makefile.in
+++ b/accessible/interfaces/ia2/Makefile.in
@@ -77,17 +77,19 @@ export:: midl
 include $(topsrcdir)/config/rules.mk
 
 # generate list of to-be-generated files that are missing
 # but ignore special file dlldata.c and .tlb files
 missing:=$(strip $(foreach onefile,$(strip $(patsubst %.tlb,,$(subst dlldata.c,,$(MIDL_GENERATED_FILES)))),$(if $(wildcard $(onefile)),,$(onefile))))
 
 missing_base:=$(sort $(basename $(subst _p.c,,$(subst _i.c,,$(missing)))))
 
-$(MIDL_GENERATED_FILES) : midl_done typelib_done
+# Bug 1420119: We need the trailing semicolon here to generate a recipe for the
+# midl targets to avoid timestamp caching issues.
+$(MIDL_GENERATED_FILES) : midl_done typelib_done ;
 
 ifneq ("$(missing)","")
 midl_done : FORCE
 endif
 
 midl_done : $(addprefix $(IA2DIR)/,$(MIDL_INTERFACES) $(MIDL_ENUMS))
 	for idl in $(sort $(subst FORCE,,$?) $(addsuffix .idl,$(addprefix $(IA2DIR)/,$(missing_base)))); do \
 	  $(MIDL) $(MIDL_FLAGS) -app_config -I $(IA2DIR) -Oicf $$idl; \
--- a/accessible/interfaces/msaa/Makefile.in
+++ b/accessible/interfaces/msaa/Makefile.in
@@ -7,17 +7,19 @@ GARBAGE += $(MIDL_GENERATED_FILES) done_
 MIDL_GENERATED_FILES = \
   dlldata.c \
   ISimpleDOM.h \
   ISimpleDOM_i.c \
   ISimpleDOM_p.c \
   ISimpleDOM.tlb \
   $(NULL)
 
-$(MIDL_GENERATED_FILES): done_gen
+# Bug 1420119: We need the trailing semicolon here to generate a recipe for the
+# midl targets to avoid timestamp caching issues.
+$(MIDL_GENERATED_FILES): done_gen ;
 
 done_gen: ISimpleDOM.idl \
           ISimpleDOMNode.idl \
           ISimpleDOMDocument.idl \
           ISimpleDOMText.idl
 
 	$(MIDL) $(MIDL_FLAGS) -I $(srcdir) -robust -Oicf $(srcdir)/ISimpleDOM.idl
 	touch $@
--- a/accessible/ipc/win/handler/Makefile.in
+++ b/accessible/ipc/win/handler/Makefile.in
@@ -12,17 +12,19 @@ MIDL_GENERATED_FILES = \
   HandlerData_c.c \
   HandlerData_i.c \
   HandlerData_p.c \
   HandlerData.tlb \
   $(NULL)
 
 export:: $(MIDL_GENERATED_FILES)
 
-$(MIDL_GENERATED_FILES): midl_done
+# Bug 1420119: We need the trailing semicolon here to generate a recipe for the
+# midl targets to avoid timestamp caching issues.
+$(MIDL_GENERATED_FILES): midl_done ;
 
 midl_done: HandlerData.acf HandlerData.idl
 	$(MIDL) $(MIDL_FLAGS) $(DEFINES) -I $(topobjdir) -I $(DIST)/include -I $(IA2DIR) -I $(MSAADIR) -Oicf -acf $(srcdir)/HandlerData.acf $(srcdir)/HandlerData.idl
 	touch $@
 
 INSTALL_TARGETS += midl
 midl_FILES := HandlerData.h \
               HandlerData_i.c \
--- a/accessible/ipc/win/typelib/Makefile.in
+++ b/accessible/ipc/win/typelib/Makefile.in
@@ -6,17 +6,19 @@ GARBAGE += $(MIDL_GENERATED_FILES) done_
 
 MIDL_GENERATED_FILES = \
   Accessible.h \
   Accessible_i.c \
   Accessible_p.c \
   Accessible.tlb \
   $(NULL)
 
-$(MIDL_GENERATED_FILES): done_gen
+# Bug 1420119: We need the trailing semicolon here to generate a recipe for the
+# midl targets to avoid timestamp caching issues.
+$(MIDL_GENERATED_FILES): done_gen ;
 
 done_gen: Accessible.idl
 	$(MIDL) $(MIDL_FLAGS) -Oicf $(srcdir)/Accessible.idl
 	touch $@
 
 export:: done_gen
 
 midl_exports := \
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,10 +1,10 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<blocklist lastupdate="1518553957211" xmlns="http://www.mozilla.org/2006/addons-blocklist">
+<blocklist lastupdate="1518640450735" xmlns="http://www.mozilla.org/2006/addons-blocklist">
   <emItems>
     <emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1211" id="flvto@hotger.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
@@ -2190,16 +2190,20 @@
     <emItem blockID="2104a522-bb2f-4b04-ad0d-b0c571644552" id="{ed352072-ddf0-4cb4-9cb6-d8aa3741c2de}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="646e2384-f894-41bf-b7fc-8879e0095109" id="/^(https|youtube)@vietbacsecurity\.com$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="cc5848e8-23d5-4655-b45c-dc239839b74e" id="/^(\{01c9a4a4-06dd-426b-9500-2ea6fe841b88\}|{5e024309-042c-4b9d-a634-5d92cf9c7514\}|{f4262989-6de0-4604-918f-663b85fad605\}|{e341ed12-a703-47fe-b8dd-5948c38070e4\}|{cd89045b-2e06-46bb-9e34-48e8799e5ef2\}|{ac296b47-7c03-486f-a1d6-c48b24419749\}|{5da81d3d-5db1-432a-affc-4a2fe9a70749\}|{df09f268-3c92-49db-8c31-6a25a6643896\}|{81ac42f3-3d17-4cff-85af-8b7f89c8826b\}|{09c8fa16-4eec-4f78-b19d-9b24b1b57e1e\}|{71639610-9cc3-47e0-86ed-d5b99eaa41d5\}|{83d38ac3-121b-4f28-bf9c-1220bd3c643b\}|{7f8bc48d-1c7c-41a0-8534-54adc079338f\})$/">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
   </emItems>
   <pluginItems>
     <pluginItem blockID="p1063">
       <match exp="Java(\(TM\))? Plug-in 10\.(8[1-9]|90)(\.[0-9]+)?([^\d\._]|$)" name="name"/>
       <match exp="libnpjp2\.so" name="filename"/>
       <infoURL>https://java.com/</infoURL>
       <versionRange severity="0" vulnerabilitystatus="1"/>
     </pluginItem>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -13,21 +13,25 @@
 }
 
 :root:-moz-lwtheme {
   color: var(--lwt-text-color) !important;
 }
 
 :root:-moz-lwtheme {
   background-color: var(--lwt-accent-color) !important;
-  background-image: var(--lwt-header-image), var(--lwt-additional-images) !important;
+  background-image: var(--lwt-additional-images) !important;
   background-position: var(--lwt-background-alignment) !important;
   background-repeat: var(--lwt-background-tiling) !important;
 }
 
+:root:-moz-lwtheme[lwtheme-image] {
+  background-image: var(--lwt-header-image), var(--lwt-additional-images) !important;
+}
+
 :root:-moz-lwtheme:-moz-window-inactive {
   background-color: var(--lwt-accent-color-inactive, var(--lwt-accent-color)) !important;
 }
 
 #main-window:not([chromehidden~="toolbar"]) {
 %ifdef XP_MACOSX
   min-width: 335px;
 %else
deleted file mode 100644
index e4e8dcaa3b3cd01a1287359902561166d7f942ee..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
--- a/browser/base/content/test/general/browser_compacttheme.js
+++ b/browser/base/content/test/general/browser_compacttheme.js
@@ -41,17 +41,16 @@ add_task(async function startTests() {
   LightweightThemeManager.currentTheme = null;
   ok(!CompactTheme.isStyleSheetEnabled, "There is no compact style sheet when no lw theme is applied.");
 });
 
 function dummyLightweightTheme(id) {
   return {
     id,
     name: id,
-    headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
     iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
     textcolor: "red",
     accentcolor: "blue"
   };
 }
 
 add_task(async function testLightweightThemePreview() {
   info("Setting compact to current and previewing others");
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -91,17 +91,16 @@ browser.jar:
         content/browser/defaultthemes/3.icon.png      (content/defaultthemes/3.icon.png)
         content/browser/defaultthemes/3.preview.png   (content/defaultthemes/3.preview.png)
         content/browser/defaultthemes/4.header.png    (content/defaultthemes/4.header.png)
         content/browser/defaultthemes/4.icon.png      (content/defaultthemes/4.icon.png)
         content/browser/defaultthemes/4.preview.png   (content/defaultthemes/4.preview.png)
         content/browser/defaultthemes/5.header.png    (content/defaultthemes/5.header.png)
         content/browser/defaultthemes/5.icon.jpg      (content/defaultthemes/5.icon.jpg)
         content/browser/defaultthemes/5.preview.jpg   (content/defaultthemes/5.preview.jpg)
-        content/browser/defaultthemes/compact.header.png    (content/defaultthemes/compact.header.png)
         content/browser/defaultthemes/dark.icon.svg  (content/defaultthemes/dark.icon.svg)
         content/browser/defaultthemes/light.icon.svg (content/defaultthemes/light.icon.svg)
         content/browser/newtab/newTab.xhtml           (content/newtab/newTab.xhtml)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/alternativeDefaultSites.json   (content/newtab/alternativeDefaultSites.json)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
--- a/browser/components/customizableui/content/toolbar.xml
+++ b/browser/components/customizableui/content/toolbar.xml
@@ -4,19 +4,16 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <bindings id="browserToolbarBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="toolbar">
-    <resources>
-      <stylesheet src="chrome://global/skin/toolbar.css"/>
-    </resources>
     <implementation>
       <field name="overflowedDuringConstruction">null</field>
 
       <constructor><![CDATA[
           let scope = {};
           ChromeUtils.import("resource:///modules/CustomizableUI.jsm", scope);
           let CustomizableUI = scope.CustomizableUI;
           // Add an early overflow event listener that will mark if the
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -695,27 +695,25 @@ BrowserGlue.prototype = {
     SessionStore.init();
 
     let vendorShortName = gBrandBundle.GetStringFromName("vendorShortName");
 
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-compact-light@mozilla.org",
       name: gBrowserBundle.GetStringFromName("lightTheme.name"),
       description: gBrowserBundle.GetStringFromName("lightTheme.description"),
-      headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/light.icon.svg",
       textcolor: "black",
       accentcolor: "white",
       author: vendorShortName,
     });
     LightweightThemeManager.addBuiltInTheme({
       id: "firefox-compact-dark@mozilla.org",
       name: gBrowserBundle.GetStringFromName("darkTheme.name"),
       description: gBrowserBundle.GetStringFromName("darkTheme.description"),
-      headerURL: "resource:///chrome/browser/content/browser/defaultthemes/compact.header.png",
       iconURL: "resource:///chrome/browser/content/browser/defaultthemes/dark.icon.svg",
       textcolor: "white",
       accentcolor: "black",
       author: vendorShortName,
     });
 
 
     // Initialize the default l10n resource sources for L10nRegistry.
--- a/browser/components/preferences/clearSiteData.js
+++ b/browser/components/preferences/clearSiteData.js
@@ -51,28 +51,31 @@ var gClearSiteDataDialog = {
   onCheckboxCommand(event) {
     this._clearButton.disabled =
       !(this._clearSiteDataCheckbox.checked || this._clearCacheCheckbox.checked);
   },
 
   onClear() {
     let allowed = true;
 
+    if (this._clearCacheCheckbox.checked && allowed) {
+      SiteDataManager.removeCache();
+      // If we're not clearing site data, we need to tell the
+      // SiteDataManager to signal that it's updating.
+      if (!this._clearSiteDataCheckbox.checked) {
+        SiteDataManager.updateSites();
+      }
+    }
+
     if (this._clearSiteDataCheckbox.checked) {
       allowed = SiteDataManager.promptSiteDataRemoval(window);
       if (allowed) {
         SiteDataManager.removeSiteData();
       }
     }
 
-    if (this._clearCacheCheckbox.checked && allowed) {
-      SiteDataManager.removeCache();
-      // Update cache UI in about:preferences
-      window.opener.gPrivacyPane.updateActualCacheSize();
-    }
-
     if (allowed) {
       window.close();
     }
   },
 };
 
 window.addEventListener("load", () => gClearSiteDataDialog.init());
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -106,21 +106,16 @@ Preferences.addAll([
   { id: "browser.safebrowsing.phishing.enabled", type: "bool" },
 
   { id: "browser.safebrowsing.downloads.enabled", type: "bool" },
 
   { id: "urlclassifier.malwareTable", type: "string" },
 
   { id: "browser.safebrowsing.downloads.remote.block_potentially_unwanted", type: "bool" },
   { id: "browser.safebrowsing.downloads.remote.block_uncommon", type: "bool" },
-
-  // Network tab
-  { id: "browser.cache.disk.capacity", type: "int" },
-
-  { id: "browser.cache.disk.smart_size.enabled", type: "bool", inverted: "true" },
 ]);
 
 // Data Choices tab
 if (AppConstants.NIGHTLY_BUILD) {
   Preferences.add({ id: "browser.chrome.errorReporter.enabled", type: "bool" });
 }
 if (AppConstants.MOZ_CRASHREPORTER) {
   Preferences.add({ id: "browser.crashReports.unsubmittedCheck.autoSubmit2", type: "bool" });
@@ -323,24 +318,20 @@ var gPrivacyPane = {
     setEventListener("showPasswords", "command",
       gPrivacyPane.showPasswords);
     setEventListener("addonExceptions", "command",
       gPrivacyPane.showAddonExceptions);
     setEventListener("viewCertificatesButton", "command",
       gPrivacyPane.showCertificates);
     setEventListener("viewSecurityDevicesButton", "command",
       gPrivacyPane.showSecurityDevices);
-    setEventListener("clearCacheButton", "command",
-      gPrivacyPane.clearCache);
 
     this._pane = document.getElementById("panePrivacy");
     this._initMasterPasswordUI();
     this._initSafeBrowsing();
-    this.updateCacheSizeInputField();
-    this.updateActualCacheSize();
 
     setEventListener("notificationSettingsButton", "command",
       gPrivacyPane.showNotificationExceptions);
     setEventListener("locationSettingsButton", "command",
       gPrivacyPane.showLocationExceptions);
     setEventListener("cameraSettingsButton", "command",
       gPrivacyPane.showCameraExceptions);
     setEventListener("microphoneSettingsButton", "command",
@@ -365,19 +356,16 @@ var gPrivacyPane = {
       checkbox.setAttribute("accesskey", bundlePrefs.getString("pauseNotifications.accesskey"));
       if (AlertsServiceDND.manualDoNotDisturb) {
         let notificationsDoNotDisturb =
           document.getElementById("notificationsDoNotDisturb");
         notificationsDoNotDisturb.setAttribute("checked", true);
       }
     }
 
-    setEventListener("cacheSize", "change",
-      gPrivacyPane.updateCacheSizePref);
-
     if (Services.prefs.getBoolPref("browser.storageManager.enabled")) {
       Services.obs.addObserver(this, "sitedatamanager:sites-updated");
       Services.obs.addObserver(this, "sitedatamanager:updating-sites");
       let unload = () => {
         window.removeEventListener("unload", unload);
         Services.obs.removeObserver(this, "sitedatamanager:sites-updated");
         Services.obs.removeObserver(this, "sitedatamanager:updating-sites");
       };
@@ -1413,121 +1401,41 @@ var gPrivacyPane = {
 
   /**
    * Displays a dialog from which the user can manage his security devices.
    */
   showSecurityDevices() {
     gSubDialog.open("chrome://pippki/content/device_manager.xul");
   },
 
-  /**
-   * Clears the cache.
-   */
-  clearCache() {
-    try {
-      Services.cache2.clear();
-    } catch (ex) { }
-    this.updateActualCacheSize();
-  },
-
   showSiteDataSettings() {
     gSubDialog.open("chrome://browser/content/preferences/siteDataSettings.xul");
   },
 
   toggleSiteData(shouldShow) {
     let clearButton = document.getElementById("clearSiteDataButton");
     let settingsButton = document.getElementById("siteDataSettings");
     clearButton.disabled = !shouldShow;
     settingsButton.disabled = !shouldShow;
   },
 
-  updateTotalDataSizeLabel(usage) {
-    let prefStrBundle = document.getElementById("bundlePreferences");
+  showSiteDataLoading() {
     let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
-    if (usage < 0) {
-      totalSiteDataSizeLabel.textContent = prefStrBundle.getString("loadingSiteDataSize");
-    } else {
-      let size = DownloadUtils.convertByteUnits(usage);
-      totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize", size);
-    }
-  },
-
-  // Retrieves the amount of space currently used by disk cache
-  updateActualCacheSize() {
-    var actualSizeLabel = document.getElementById("actualDiskCacheSize");
-    var prefStrBundle = document.getElementById("bundlePreferences");
-
-    // Needs to root the observer since cache service keeps only a weak reference.
-    this.observer = {
-      onNetworkCacheDiskConsumption(consumption) {
-        var size = DownloadUtils.convertByteUnits(consumption);
-        // The XBL binding for the string bundle may have been destroyed if
-        // the page was closed before this callback was executed.
-        if (!prefStrBundle.getFormattedString) {
-          return;
-        }
-        actualSizeLabel.textContent = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
-      },
-
-      QueryInterface: XPCOMUtils.generateQI([
-        Components.interfaces.nsICacheStorageConsumptionObserver,
-        Components.interfaces.nsISupportsWeakReference
-      ])
-    };
-
-    actualSizeLabel.textContent = prefStrBundle.getString("actualDiskCacheSizeCalculated");
-
-    try {
-      Services.cache2.asyncGetDiskConsumption(this.observer);
-    } catch (e) { }
+    let prefStrBundle = document.getElementById("bundlePreferences");
+    totalSiteDataSizeLabel.textContent = prefStrBundle.getString("loadingSiteDataSize1");
   },
 
-  updateCacheSizeUI(smartSizeEnabled) {
-    document.getElementById("useCacheBefore").disabled = smartSizeEnabled;
-    document.getElementById("cacheSize").disabled = smartSizeEnabled;
-    document.getElementById("useCacheAfter").disabled = smartSizeEnabled;
-  },
-
-  readSmartSizeEnabled() {
-    // The smart_size.enabled preference element is inverted="true", so its
-    // value is the opposite of the actual pref value
-    var disabled = Preferences.get("browser.cache.disk.smart_size.enabled").value;
-    this.updateCacheSizeUI(!disabled);
-  },
-
-  /**
-   * Converts the cache size from units of KB to units of MB and stores it in
-   * the textbox element.
-   *
-   * Preferences:
-   *
-   * browser.cache.disk.capacity
-   * - the size of the browser cache in KB
-   * - Only used if browser.cache.disk.smart_size.enabled is disabled
-   */
-  updateCacheSizeInputField() {
-    let cacheSizeElem = document.getElementById("cacheSize");
-    let cachePref = Preferences.get("browser.cache.disk.capacity");
-    cacheSizeElem.value = cachePref.value / 1024;
-    if (cachePref.locked)
-      cacheSizeElem.disabled = true;
-  },
-
-  /**
-   * Updates the cache size preference once user enters a new value.
-   * We intentionally do not set preference="browser.cache.disk.capacity"
-   * onto the textbox directly, as that would update the pref at each keypress
-   * not only after the final value is entered.
-   */
-  updateCacheSizePref() {
-    let cacheSizeElem = document.getElementById("cacheSize");
-    let cachePref = Preferences.get("browser.cache.disk.capacity");
-    // Converts the cache size as specified in UI (in MB) to KB.
-    let intValue = parseInt(cacheSizeElem.value, 10);
-    cachePref.value = isNaN(intValue) ? 0 : intValue * 1024;
+  updateTotalDataSizeLabel(siteDataUsage) {
+    SiteDataManager.getCacheSize().then(function(cacheUsage) {
+      let prefStrBundle = document.getElementById("bundlePreferences");
+      let totalSiteDataSizeLabel = document.getElementById("totalSiteDataSize");
+      let totalUsage = siteDataUsage + cacheUsage;
+      let size = DownloadUtils.convertByteUnits(totalUsage);
+      totalSiteDataSizeLabel.textContent = prefStrBundle.getFormattedString("totalSiteDataSize1", size);
+    });
   },
 
   clearSiteData() {
     gSubDialog.open("chrome://browser/content/preferences/clearSiteData.xul");
   },
 
   initDataCollection() {
     this._setupLearnMoreLink("toolkit.datacollection.infoURL",
@@ -1588,17 +1496,17 @@ var gPrivacyPane = {
     Services.prefs.setBoolPref(PREF_UPLOAD_ENABLED, checkbox.checked);
   },
 
   observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "sitedatamanager:updating-sites":
         // While updating, we want to disable this section and display loading message until updated
         this.toggleSiteData(false);
-        this.updateTotalDataSizeLabel(-1);
+        this.showSiteDataLoading();
         break;
 
       case "sitedatamanager:sites-updated":
         this.toggleSiteData(true);
         SiteDataManager.getTotalUsage()
           .then(this.updateTotalDataSizeLabel.bind(this));
         break;
     }
--- a/browser/components/preferences/in-content/privacy.xul
+++ b/browser/components/preferences/in-content/privacy.xul
@@ -256,43 +256,16 @@
   <checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
             accesskey="&locbar.openpage.accesskey;"
             preference="browser.urlbar.suggest.openpage"/>
   <label class="text-link" id="openSearchEnginePreferences">
     &suggestionSettings2.label;
   </label>
 </groupbox>
 
-<!-- Cache -->
-<groupbox id="cacheGroup" data-category="panePrivacy" hidden="true">
-  <caption><label>&httpCache.label;</label></caption>
-
-  <hbox align="center">
-    <label id="actualDiskCacheSize" flex="1"/>
-    <button id="clearCacheButton"
-            class="accessory-button"
-            icon="clear"
-            label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"/>
-  </hbox>
-  <checkbox preference="browser.cache.disk.smart_size.enabled"
-            id="allowSmartSize"
-            onsyncfrompreference="return gPrivacyPane.readSmartSizeEnabled();"
-            label="&overrideSmartCacheSize.label;"
-            accesskey="&overrideSmartCacheSize.accesskey;"/>
-  <hbox align="center" class="indent">
-    <label id="useCacheBefore" control="cacheSize"
-            accesskey="&limitCacheSizeBefore.accesskey;">
-      &limitCacheSizeBefore.label;
-    </label>
-    <textbox id="cacheSize" type="number" size="4" max="1024"
-              aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
-    <label id="useCacheAfter" flex="1">&limitCacheSizeAfter.label;</label>
-  </hbox>
-</groupbox>
-
 <!-- Site Data -->
 <groupbox id="siteDataGroup" hidden="true" data-category="panePrivacy" data-hidden-from-search="true">
   <caption><label>&siteData.label;</label></caption>
 
   <hbox align="baseline">
     <vbox flex="1">
       <description flex="1">
         <label id="totalSiteDataSize" class="tail-with-learn-more"></label>
--- a/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
+++ b/browser/components/preferences/in-content/tests/browser_bug795764_cachedisabled.js
@@ -11,20 +11,16 @@ function test() {
   // Otherwise, without any site then it would just return so we would end up in not testing SiteDataManager.
   let principal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin("https://www.foo.com");
   Services.perms.addFromPrincipal(principal, "persistent-storage", Ci.nsIPermissionManager.ALLOW_ACTION);
   registerCleanupFunction(function() {
     Services.perms.removeFromPrincipal(principal, "persistent-storage");
   });
 
   SpecialPowers.pushPrefEnv({set: [
-    ["browser.cache.offline.enable", false],
-    ["browser.cache.disk.enable", false],
-    ["browser.cache.memory.enable", false],
-    ["browser.storageManager.enabled", true],
     ["privacy.userContext.ui.enabled", true]
   ]}).then(() => open_preferences(runTest));
 }
 
 function runTest(win) {
   is(gBrowser.currentURI.spec, "about:preferences", "about:preferences loaded");
 
   let tab = win.document;
--- a/browser/components/preferences/in-content/tests/browser_clearSiteData.js
+++ b/browser/components/preferences/in-content/tests/browser_clearSiteData.js
@@ -11,45 +11,16 @@ const { DownloadUtils } = ChromeUtils.im
 const TEST_QUOTA_USAGE_HOST = "example.com";
 const TEST_QUOTA_USAGE_ORIGIN = "https://" + TEST_QUOTA_USAGE_HOST;
 const TEST_QUOTA_USAGE_URL = TEST_QUOTA_USAGE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/site_data_test.html";
 const TEST_OFFLINE_HOST = "example.org";
 const TEST_OFFLINE_ORIGIN = "https://" + TEST_OFFLINE_HOST;
 const TEST_OFFLINE_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/offline/offline.html";
 const TEST_SERVICE_WORKER_URL = TEST_OFFLINE_ORIGIN + "/browser/browser/components/preferences/in-content/tests/service_worker_test.html";
 
-// XXX: The intermittent bug 1331851
-// The implementation of nsICacheStorageConsumptionObserver must be passed as weak referenced,
-// so we must hold this observer here well. If we didn't, there would be a chance that
-// in Linux debug test run the observer was released before the operation at gecko was completed
-// (may be because of a relatively quicker GC cycle or a relatively slower operation).
-// As a result of that, we would never get the cache usage we want so the test would fail from timeout.
-const cacheUsageGetter = {
-  _promise: null,
-  _resolve: null,
-  get() {
-    if (!this._promise) {
-      this._promise = new Promise(resolve => {
-        this._resolve = resolve;
-        Services.cache2.asyncGetDiskConsumption(this);
-      });
-    }
-    return this._promise;
-  },
-  // nsICacheStorageConsumptionObserver implementations
-  onNetworkCacheDiskConsumption(usage) {
-    cacheUsageGetter._promise = null;
-    cacheUsageGetter._resolve(usage);
-  },
-  QueryInterface: XPCOMUtils.generateQI([
-    Components.interfaces.nsICacheStorageConsumptionObserver,
-    Components.interfaces.nsISupportsWeakReference
-  ]),
-};
-
 async function testClearData(clearSiteData, clearCache) {
   let quotaURI = Services.io.newURI(TEST_QUOTA_USAGE_ORIGIN);
   SitePermissions.set(quotaURI, "persistent-storage", SitePermissions.ALLOW);
 
   // Open a test site which saves into appcache.
   await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL);
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 
@@ -64,23 +35,28 @@ async function testClearData(clearSiteDa
 
   // Register some service workers.
   await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL);
   await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL);
 
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
 
   // Test the initial states.
-  let cacheUsage = await cacheUsageGetter.get();
+  let cacheUsage = await SiteDataManager.getCacheSize();
   let quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
   let totalUsage = await SiteDataManager.getTotalUsage();
   Assert.greater(cacheUsage, 0, "The cache usage should not be 0");
   Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
   Assert.greater(totalUsage, 0, "The total usage should not be 0");
 
+  let initialSizeLabelValue = await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
+    let sizeLabel = content.document.getElementById("totalSiteDataSize");
+    return sizeLabel.textContent;
+  });
+
   let doc = gBrowser.selectedBrowser.contentDocument;
   let clearSiteDataButton = doc.getElementById("clearSiteDataButton");
 
   let dialogOpened = promiseLoadSubDialog("chrome://browser/content/preferences/clearSiteData.xul");
   clearSiteDataButton.doCommand();
   let dialogWin = await dialogOpened;
 
   // Convert the usage numbers in the same way the UI does it to assert
@@ -140,47 +116,48 @@ async function testClearData(clearSiteDa
   if (clearSiteData) {
     await acceptPromise;
   }
 
   await dialogClosed;
 
   if (clearCache) {
     TestUtils.waitForCondition(async function() {
-      let usage = await cacheUsageGetter.get();
+      let usage = await SiteDataManager.getCacheSize();
       return usage == 0;
     }, "The cache usage should be removed");
   } else {
-    Assert.greater(await cacheUsageGetter.get(), 0, "The cache usage should not be 0");
+    Assert.greater(await SiteDataManager.getCacheSize(), 0, "The cache usage should not be 0");
   }
 
   if (clearSiteData) {
     await updatePromise;
     await cookiesClearedPromise;
     await promiseServiceWorkersCleared();
 
     TestUtils.waitForCondition(async function() {
       let usage = await SiteDataManager.getTotalUsage();
       return usage == 0;
     }, "The total usage should be removed");
-
-    // Check that the size label in about:preferences updates after we cleared data.
-    await ContentTask.spawn(gBrowser.selectedBrowser, null, async function() {
-      let sizeLabel = content.document.getElementById("totalSiteDataSize");
-
-      await ContentTaskUtils.waitForCondition(
-        () => sizeLabel.textContent.includes("0"), "Site data size label should have updated.");
-    });
   } else {
     quotaUsage = await getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN);
     totalUsage = await SiteDataManager.getTotalUsage();
     Assert.greater(quotaUsage, 0, "The quota usage should not be 0");
     Assert.greater(totalUsage, 0, "The total usage should not be 0");
   }
 
+  if (clearCache || clearSiteData) {
+    // Check that the size label in about:preferences updates after we cleared data.
+    await ContentTask.spawn(gBrowser.selectedBrowser, {initialSizeLabelValue}, async function(opts) {
+      let sizeLabel = content.document.getElementById("totalSiteDataSize");
+      await ContentTaskUtils.waitForCondition(
+        () => sizeLabel.textContent != opts.initialSizeLabelValue, "Site data size label should have updated.");
+    });
+  }
+
   let desiredPermissionState = clearSiteData ? SitePermissions.UNKNOWN : SitePermissions.ALLOW;
   let permission = SitePermissions.get(quotaURI, "persistent-storage");
   is(permission.state, desiredPermissionState, "Should have the correct permission state.");
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
   await SiteDataManager.removeAll();
 }
 
--- a/browser/components/preferences/in-content/tests/browser_extension_controlled.js
+++ b/browser/components/preferences/in-content/tests/browser_extension_controlled.js
@@ -439,16 +439,19 @@ add_task(async function testExtensionCon
 
   await ExtensionSettingsStore.initialize();
 
   // Verify the setting isn't reported as controlled and the inputs are enabled.
   is(ExtensionSettingsStore.getSetting("prefs", "homepage_override"), null,
      "The homepage_override is not set");
   await checkHomepageEnabled();
 
+  // Disarm any pending writes before we modify the JSONFile directly.
+  await ExtensionSettingsStore._reloadFile(false);
+
   // Write out a bad store file.
   let storeData = {
     prefs: {
       homepage_override: {
         initialValue: "",
         precedenceList: [{
           id: "bad@mochi.test",
           installDate: 1508802672,
--- a/browser/components/preferences/in-content/tests/browser_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData.js
@@ -67,49 +67,51 @@ add_task(async function() {
 });
 
 // Test buttons are disabled and loading message shown while updating sites
 add_task(async function() {
   await SpecialPowers.pushPrefEnv({set: [["browser.storageManager.enabled", true]]});
   let updatedPromise = promiseSiteDataManagerSitesUpdated();
   await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
   await updatedPromise;
+  let cacheSize = await SiteDataManager.getCacheSize();
 
   let actual = null;
   let expected = null;
   let doc = gBrowser.selectedBrowser.contentDocument;
   let clearBtn = doc.getElementById("clearSiteDataButton");
   let settingsButton = doc.getElementById("siteDataSettings");
   let prefStrBundle = doc.getElementById("bundlePreferences");
   let totalSiteDataSizeLabel = doc.getElementById("totalSiteDataSize");
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
   await SiteDataManager.getTotalUsage()
                        .then(usage => {
                          actual = totalSiteDataSizeLabel.textContent;
                          expected = prefStrBundle.getFormattedString(
-                           "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
+                           "totalSiteDataSize1", DownloadUtils.convertByteUnits(usage + cacheSize));
                           is(actual, expected, "Should show the right total site data size");
                        });
 
   Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
   is(clearBtn.disabled, true, "Should disable clear button while updating sites");
   is(settingsButton.disabled, true, "Should disable settings button while updating sites");
   actual = totalSiteDataSizeLabel.textContent;
-  expected = prefStrBundle.getString("loadingSiteDataSize");
+  expected = prefStrBundle.getString("loadingSiteDataSize1");
   is(actual, expected, "Should show the loading message while updating");
 
   Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
+  cacheSize = await SiteDataManager.getCacheSize();
   await SiteDataManager.getTotalUsage()
                        .then(usage => {
                          actual = totalSiteDataSizeLabel.textContent;
                          expected = prefStrBundle.getFormattedString(
-                           "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
+                           "totalSiteDataSize1", DownloadUtils.convertByteUnits(usage + cacheSize));
                           is(actual, expected, "Should show the right total site data size");
                        });
 
   await BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
 
 // Test clearing service wroker through the settings panel
 add_task(async function() {
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -738,17 +738,17 @@ you can use these alternative items. Oth
 <!ENTITY editBookmark.done.label                     "Done">
 <!ENTITY editBookmark.removeBookmark.accessKey       "R">
 
 <!-- LOCALIZATION NOTE (identity.securityView.label)
      This is the header of the security subview in the Site Identity panel. -->
 <!ENTITY identity.securityView.label "Site Security">
 
 <!ENTITY identity.connectionSecure "Secure Connection">
-<!ENTITY identity.connectionNotSecure "Connection is Not Secure">
+<!ENTITY identity.connectionNotSecure "Connection Is Not Secure">
 <!ENTITY identity.connectionFile "This page is stored on your computer.">
 <!ENTITY identity.connectionVerified2 "You are securely connected to this site, owned by:">
 <!ENTITY identity.connectionInternal "This is a secure &brandShortName; page.">
 <!ENTITY identity.extensionPage "This page is loaded from an extension.">
 <!ENTITY identity.insecureLoginForms2 "Logins entered on this page could be compromised.">
 
 <!-- Strings for connection state warnings. -->
 <!ENTITY identity.activeBlocked "&brandShortName; has blocked parts of this page that are not secure.">
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -48,40 +48,24 @@ available. -->
 <!ENTITY networkTab.label                "Network">
 
 <!ENTITY networkProxy.label              "Network Proxy">
 
 <!ENTITY connectionSettingsLearnMore.label "Learn more">
 <!ENTITY connectionSettings.label        "Settings…">
 <!ENTITY connectionSettings.accesskey    "e">
 
-<!ENTITY httpCache.label                 "Cached Web Content">
-
 <!--  Site Data section manages sites using Storage API and is under Network -->
 <!ENTITY siteData.label                  "Site Data">
 <!ENTITY clearSiteData.label             "Clear All Data">
 <!ENTITY clearSiteData.accesskey         "l">
 <!ENTITY siteDataSettings.label          "Settings…">
 <!ENTITY siteDataSettings.accesskey      "i">
 <!ENTITY siteDataLearnMoreLink.label     "Learn more">
 
-<!-- LOCALIZATION NOTE:
-  The entities limitCacheSizeBefore.label and limitCacheSizeAfter.label appear on a single
-  line in preferences as follows:
-
-  &limitCacheSizeBefore.label [textbox for cache size in MB] &limitCacheSizeAfter.label;
--->
-<!ENTITY limitCacheSizeBefore.label      "Limit cache to">
-<!ENTITY limitCacheSizeBefore.accesskey  "L">
-<!ENTITY limitCacheSizeAfter.label       "MB of space">
-<!ENTITY clearCacheNow.label             "Clear Now">
-<!ENTITY clearCacheNow.accesskey         "C">
-<!ENTITY overrideSmartCacheSize.label    "Override automatic cache management">
-<!ENTITY overrideSmartCacheSize.accesskey "O">
-
 <!ENTITY updateTab.label                 "Update">
 
 <!-- LOCALIZATION NOTE (updateApplication.label):
   Strings from aboutDialog.dtd are displayed in this section of the preferences.
   Please check for possible accesskey conflicts.
 -->
 <!ENTITY updateApplication.label         "&brandShortName; Updates">
 <!-- LOCALIZATION NOTE (updateApplication.version.*): updateApplication.version.pre
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -161,38 +161,22 @@ removeAllShownCookies.accesskey=A
 # you can use #1 in your localization as a placeholder for the number.
 # For example this is the English string with numbers:
 # removeSelectedCookied=Remove #1 Selected;Remove #1 Selected
 removeSelectedCookies.label=Remove Selected;Remove Selected
 removeSelectedCookies.accesskey=R
 
 defaultUserContextLabel=None
 
-####Preferences::Advanced::Network
-#LOCALIZATION NOTE: The next string is for the disk usage of the web content cache.
-#   e.g., "Your web content cache is currently using 200 MB"
-#   %1$S = size
-#   %2$S = unit (MB, KB, etc.)
-actualDiskCacheSize=Your web content cache is currently using %1$S %2$S of disk space
-actualDiskCacheSizeCalculated=Calculating web content cache size…
-
-####Preferences::Advanced::Network
-#LOCALIZATION NOTE: The next string is for the disk usage of the application cache.
-#   e.g., "Your application cache is currently using 200 MB"
-#   %1$S = size
-#   %2$S = unit (MB, KB, etc.)
-actualAppCacheSize=Your application cache is currently using %1$S %2$S of disk space
-
-####Preferences::Advanced::Network
 #LOCALIZATION NOTE: The next string is for the total usage of site data.
 #   e.g., "The total usage is currently using 200 MB"
 #   %1$S = size
 #   %2$S = unit (MB, KB, etc.)
-totalSiteDataSize=Your stored site data is currently using %1$S %2$S of disk space
-loadingSiteDataSize=Calculating site data size…
+totalSiteDataSize1=Your stored site data and cache are currently using %1$S %2$S of disk space
+loadingSiteDataSize1=Calculating site data and cache size…
 persistent=Persistent
 siteUsage=%1$S %2$S
 acceptRemove=Remove
 # LOCALIZATION NOTE (siteDataSettings2.description): %S = brandShortName
 siteDataSettings2.description=The following websites store site data on your computer. %S keeps data from websites with persistent storage until you delete it, and deletes data from websites with non-persistent storage as space is needed.
 # LOCALIZATION NOTE (removeAllSiteData, removeAllSiteDataShown):
 # removeAllSiteData and removeAllSiteDataShown are both used on the same one button,
 # never displayed together and can share the same accesskey.
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -465,18 +465,18 @@ notification[value="translation"] menuli
   color: -moz-menubartext;
 }
 
 #nav-bar {
   -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
 }
 
 @media (-moz-menubar-drag) {
-  #toolbar-menubar:not([autohide="true"]):not(:-moz-lwtheme),
-  #TabsToolbar:not(:-moz-lwtheme) {
+  #toolbar-menubar:not([autohide="true"]),
+  #TabsToolbar {
     -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
   }
 }
 
 .tabbrowser-tab:focus > .tab-stack > .tab-content {
   outline: 1px dotted;
   outline-offset: -6px;
 }
--- a/browser/themes/shared/compacttheme.inc.css
+++ b/browser/themes/shared/compacttheme.inc.css
@@ -2,18 +2,16 @@
 % 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/.
 
 /* compacttheme.css is loaded in browser.xul after browser.css when it is
    preffed on.  The bulk of the styling is here in the shared file, but
    there are overrides for each platform in their compacttheme.css files. */
 
 :root:-moz-lwtheme {
-  text-shadow: none;
-
   --toolbar-bgcolor: var(--chrome-secondary-background-color);
   --toolbar-gbimage: none;
   --toolbar-non-lwt-bgcolor: var(--toolbar-bgcolor);
   --toolbar-non-lwt-textcolor: var(--chrome-color);
   --toolbar-non-lwt-bgimage: none;
 
   --toolbarbutton-icon-fill-opacity: .7;
 }
@@ -104,14 +102,8 @@ toolbar[brighttext] .toolbarbutton-1 {
 
 #urlbar-zoom-button:-moz-lwtheme-brighttext:hover {
   background-color: rgba(255,255,255,.2);
 }
 
 #urlbar-zoom-button:-moz-lwtheme-brighttext:hover:active {
   background-color: rgba(255,255,255,.3);
 }
-
-.tab-icon-sound[soundplaying],
-.tab-icon-sound[muted] {
-  filter: none !important; /* removes drop-shadow filter */
-}
-
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -14,32 +14,32 @@
 
 #customization-container {
   background-color: var(--toolbar-non-lwt-bgcolor);
   background-image: var(--toolbar-non-lwt-bgimage);
   color: var(--toolbar-non-lwt-textcolor);
   text-shadow: none;
 }
 
-#customization-container:-moz-lwtheme {
+:root[lwtheme-image] #customization-container {
   background-color: transparent;
   background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-non-lwt-bgcolor) 45px);
 }
 
 #customization-palette {
   padding: 5px 20px 20px;
 }
 
 #customization-header {
   font-weight: 500;
   font-size: 1.2em;
   margin: 20px 20px 15px;
 }
 
-#customization-header:-moz-lwtheme {
+:root[lwtheme-image] #customization-header {
   text-shadow: 0 0 1em var(--toolbar-non-lwt-bgcolor),
                0 0 1em var(--toolbar-non-lwt-bgcolor),
                0 0 .5em var(--toolbar-non-lwt-bgcolor);
 }
 
 #customization-panel-container {
   padding: 0 20px 25px;
 }
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -406,25 +406,25 @@ tabbrowser {
 .tab-icon-sound[muted] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-muted.svg);
 }
 
 .tab-icon-sound[activemedia-blocked] {
   list-style-image: url(chrome://browser/skin/tabbrowser/tab-audio-blocked.svg);
 }
 
-.tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-darktext[muted],
-.tab-icon-sound:-moz-lwtheme-darktext[activemedia-blocked] {
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[soundplaying],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[muted],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-darktext[activemedia-blocked] {
   filter: drop-shadow(1px 1px 1px white);
 }
 
-.tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
-.tab-icon-sound:-moz-lwtheme-brighttext[muted],
-.tab-icon-sound:-moz-lwtheme-brighttext[activemedia-blocked] {
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[soundplaying],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[muted],
+:root[lwtheme-image] .tab-icon-sound:-moz-lwtheme-brighttext[activemedia-blocked] {
   filter: drop-shadow(1px 1px 1px black);
 }
 
 .tab-icon-sound[soundplaying]:not(:hover),
 .tab-icon-sound[muted]:not(:hover),
 .tab-icon-sound[activemedia-blocked]:not(:hover) {
   opacity: .8;
 }
@@ -525,17 +525,17 @@ tabbrowser {
 }
 
 /*
  * LightweightThemeConsumer will set the current lightweight theme's header
  * image to the lwt-header-image variable, used in each of the following rulesets.
  */
 
 /* Lightweight theme on tabs */
-#tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background[selected=true]:-moz-lwtheme {
+:root[lwtheme-image] #tabbrowser-tabs:not([movingtab]) > .tabbrowser-tab > .tab-stack > .tab-background[selected=true] {
   background-attachment: scroll, fixed;
   background-color: transparent;
   background-image: linear-gradient(var(--toolbar-bgcolor), var(--toolbar-bgcolor)),
                     var(--lwt-header-image);
   background-position: 0 0, right top;
   background-repeat: repeat-x, no-repeat;
   background-size: auto 100%, auto auto;
 }
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -101,29 +101,29 @@
       :root[sizemode="maximized"] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
       }
 
       #titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close.svg);
       }
 
-      .titlebar-button:-moz-lwtheme {
+      :root[lwtheme-image] .titlebar-button {
         -moz-context-properties: unset;
       }
-      #titlebar-min:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-min {
         list-style-image: url(chrome://browser/skin/window-controls/minimize-themes.svg);
       }
-      #titlebar-max:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/maximize-themes.svg);
       }
-      :root[sizemode="maximized"] #titlebar-max:-moz-lwtheme {
+      :root[lwtheme-image][sizemode="maximized"] #titlebar-max {
         list-style-image: url(chrome://browser/skin/window-controls/restore-themes.svg);
       }
-      #titlebar-close:-moz-lwtheme {
+      :root[lwtheme-image] #titlebar-close {
         list-style-image: url(chrome://browser/skin/window-controls/close-themes.svg);
       }
 
       /* the 12px image renders a 10px icon, and the 10px upscaled gets rounded to 12.5, which
        * rounds up to 13px, which makes the icon one pixel too big on 1.25dppx. Fix: */
       @media (min-resolution: 1.20dppx) and (max-resolution: 1.45dppx) {
         .titlebar-button > .toolbarbutton-icon {
           width: 11.5px;
--- a/browser/themes/windows/compacttheme.css
+++ b/browser/themes/windows/compacttheme.css
@@ -26,20 +26,16 @@
       background-color: rgb(185,209,234) !important;
     }
     #main-window:-moz-window-inactive {
       background-color: rgb(215,228,242) !important;
     }
   }
 }
 
-#toolbar-menubar {
-  text-shadow: none !important;
-}
-
 @media (-moz-os-version: windows-win7) {
   @media (-moz-windows-default-theme) {
     /* Always show light toolbar elements on aero surface. */
     #TabsToolbar {
       color: hsl(240,9%,98%);
     }
 
     /* Keep showing the correct color inside the tabs. */
@@ -60,21 +56,16 @@
 }
 
 @media (-moz-windows-glass) {
   /* Set to full fill-opacity to improve visibility of toolbar buttons on aero glass. */
   #TabsToolbar {
     --toolbarbutton-icon-fill-opacity: 1;
   }
 
-  /* Make the menubar text readable on aero glass (copied from browser-aero.css). */
-  #toolbar-menubar {
-    text-shadow: 0 0 .5em white, 0 0 .5em white, 0 1px 0 rgba(255,255,255,.4);
-  }
-
   #main-menubar:not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
     color: black;
     border-radius: 4px;
   }
 }
 
 @media (-moz-os-version: windows-win7),
@@ -150,28 +141,8 @@
  * over the native border with our custom borders: */
 #navigator-toolbox {
   /* These are !important to avoid specificity-wars with the selectors that add borders here. */
   background-image: none !important;
   border-top: none !important;
   box-shadow: none !important;
   padding-top: 0 !important;
 }
-
-@media (-moz-os-version: windows-win10) {
-  .titlebar-button:-moz-lwtheme {
-    -moz-context-properties: stroke;
-    stroke: currentColor;
-  }
-  #titlebar-min:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/minimize.svg);
-  }
-  #titlebar-max:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/maximize.svg);
-  }
-  :root[sizemode="maximized"] #titlebar-max:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/restore.svg);
-  }
-  #titlebar-close:-moz-lwtheme {
-    list-style-image: url(chrome://browser/skin/window-controls/close.svg);
-  }
-}
-
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -22,16 +22,17 @@ const {
 const { isAllAnimationEqual } = require("./utils/utils");
 
 class AnimationInspector {
   constructor(inspector, win) {
     this.inspector = inspector;
     this.win = win;
 
     this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this);
+    this.getComputedStyle = this.getComputedStyle.bind(this);
     this.getNodeFromActor = this.getNodeFromActor.bind(this);
     this.selectAnimation = this.selectAnimation.bind(this);
     this.setDetailVisibility = this.setDetailVisibility.bind(this);
     this.simulateAnimation = this.simulateAnimation.bind(this);
     this.toggleElementPicker = this.toggleElementPicker.bind(this);
     this.update = this.update.bind(this);
     this.onElementPickerStarted = this.onElementPickerStarted.bind(this);
     this.onElementPickerStopped = this.onElementPickerStopped.bind(this);
@@ -52,16 +53,17 @@ class AnimationInspector {
 
     const {
       onHideBoxModelHighlighter,
     } = this.inspector.getPanel("boxmodel").getComponentProps();
 
     const {
       emit: emitEventForTest,
       getAnimatedPropertyMap,
+      getComputedStyle,
       getNodeFromActor,
       selectAnimation,
       setDetailVisibility,
       simulateAnimation,
       toggleElementPicker,
     } = this;
 
     const target = this.inspector.target;
@@ -72,16 +74,17 @@ class AnimationInspector {
         id: "newanimationinspector",
         key: "newanimationinspector",
         store: this.inspector.store
       },
       App(
         {
           emitEventForTest,
           getAnimatedPropertyMap,
+          getComputedStyle,
           getNodeFromActor,
           onHideBoxModelHighlighter,
           onShowBoxModelHighlighterForNode,
           selectAnimation,
           setDetailVisibility,
           setSelectedNode,
           simulateAnimation,
           toggleElementPicker,
@@ -152,16 +155,37 @@ class AnimationInspector {
       });
 
       animatedPropertyMap.set(name, keyframes);
     }
 
     return animatedPropertyMap;
   }
 
+  /**
+   * Return the computed style of the specified property after setting the given styles
+   * to the simulated element.
+   *
+   * @param {String} property
+   *        CSS property name (e.g. text-align).
+   * @param {Object} styles
+   *        Map of CSS property name and value.
+   * @return {String}
+   *         Computed style of property.
+   */
+  getComputedStyle(property, styles) {
+    this.simulatedElement.style.cssText = "";
+
+    for (let propertyName in styles) {
+      this.simulatedElement.style.setProperty(propertyName, styles[propertyName]);
+    }
+
+    return this.win.getComputedStyle(this.simulatedElement).getPropertyValue(property);
+  }
+
   getNodeFromActor(actorID) {
     return this.inspector.walker.getNodeFromActor(actorID, ["node"]);
   }
 
   isPanelVisible() {
     return this.inspector && this.inspector.toolbox && this.inspector.sidebar &&
            this.inspector.toolbox.currentToolId === "inspector" &&
            this.inspector.sidebar.getCurrentTabID() === "newanimationinspector";
--- a/devtools/client/inspector/animation/components/AnimatedPropertyItem.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyItem.js
@@ -1,28 +1,59 @@
 /* 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/. */
 
 "use strict";
 
-const { PureComponent } = require("devtools/client/shared/vendor/react");
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
 
+const AnimatedPropertyName = createFactory(require("./AnimatedPropertyName"));
+const KeyframesGraph = createFactory(require("./keyframes-graph/KeyframesGraph"));
+
 class AnimatedPropertyItem extends PureComponent {
   static get propTypes() {
     return {
+      getComputedStyle: PropTypes.func.isRequired,
       property: PropTypes.string.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      state: PropTypes.object.isRequired,
+      type: PropTypes.string.isRequired,
       values: PropTypes.array.isRequired,
     };
   }
 
   render() {
+    const {
+      getComputedStyle,
+      property,
+      simulateAnimation,
+      state,
+      type,
+      values,
+    } = this.props;
+
     return dom.li(
       {
         className: "animated-property-item"
-      }
+      },
+      AnimatedPropertyName(
+        {
+          property,
+          state,
+        }
+      ),
+      KeyframesGraph(
+        {
+          getComputedStyle,
+          property,
+          simulateAnimation,
+          type,
+          values,
+        }
+      )
     );
   }
 }
 
 module.exports = AnimatedPropertyItem;
--- a/devtools/client/inspector/animation/components/AnimatedPropertyList.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyList.js
@@ -11,16 +11,18 @@ const PropTypes = require("devtools/clie
 const AnimatedPropertyItem = createFactory(require("./AnimatedPropertyItem"));
 
 class AnimatedPropertyList extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
+      getComputedStyle: PropTypes.func.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
     };
   }
 
   constructor(props) {
     super(props);
 
     this.state = {
       animatedPropertyMap: null
@@ -30,43 +32,69 @@ class AnimatedPropertyList extends PureC
   componentDidMount() {
     this.updateKeyframesList(this.props.animation);
   }
 
   componentWillReceiveProps(nextProps) {
     this.updateKeyframesList(nextProps.animation);
   }
 
+  getPropertyState(property) {
+    const { animation } = this.props;
+
+    for (const propState of animation.state.propertyState) {
+      if (propState.property === property) {
+        return propState;
+      }
+    }
+
+    return null;
+  }
+
   async updateKeyframesList(animation) {
     const {
       getAnimatedPropertyMap,
       emitEventForTest,
     } = this.props;
     const animatedPropertyMap = await getAnimatedPropertyMap(animation);
+    const animationTypes = await animation.getAnimationTypes(animatedPropertyMap.keys());
 
-    this.setState({ animatedPropertyMap });
+    this.setState({ animatedPropertyMap, animationTypes });
 
     emitEventForTest("animation-keyframes-rendered");
   }
 
   render() {
-    const { animatedPropertyMap } = this.state;
+    const {
+      getComputedStyle,
+      simulateAnimation,
+    } = this.props;
+    const {
+      animatedPropertyMap,
+      animationTypes,
+    } = this.state;
 
     if (!animatedPropertyMap) {
       return null;
     }
 
     return dom.ul(
       {
         className: "animated-property-list"
       },
       [...animatedPropertyMap.entries()].map(([property, values]) => {
+        const state = this.getPropertyState(property);
+        const type = animationTypes[property];
         return AnimatedPropertyItem(
           {
+            getComputedStyle,
             property,
+            simulateAnimation,
+            state,
+            type,
             values,
           }
         );
       })
     );
   }
 }
 
--- a/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyListContainer.js
@@ -12,35 +12,41 @@ const AnimatedPropertyList = createFacto
 const AnimatedPropertyListHeader = createFactory(require("./AnimatedPropertyListHeader"));
 
 class AnimatedPropertyListContainer extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
+      getComputedStyle: PropTypes.func.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       animation,
       emitEventForTest,
       getAnimatedPropertyMap,
+      getComputedStyle,
+      simulateAnimation,
     } = this.props;
 
     return dom.div(
       {
-        className: "animated-property-list-container"
+        className: `animated-property-list-container ${ animation.state.type }`
       },
       AnimatedPropertyListHeader(),
       AnimatedPropertyList(
         {
           animation,
           emitEventForTest,
           getAnimatedPropertyMap,
+          getComputedStyle,
+          simulateAnimation,
         }
       )
     );
   }
 }
 
 module.exports = AnimatedPropertyListContainer;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/AnimatedPropertyName.js
@@ -0,0 +1,40 @@
+/* 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/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+class AnimatedPropertyName extends PureComponent {
+  static get propTypes() {
+    return {
+      property: PropTypes.string.isRequired,
+      state: PropTypes.oneOfType([null, PropTypes.object]).isRequired,
+    };
+  }
+
+  render() {
+    const {
+      property,
+      state,
+    } = this.props;
+
+    return dom.div(
+      {
+        className: "animated-property-name" +
+                   (state && state.runningOnCompositor ? " compositor" : "") +
+                   (state && state.warning ? " warning" : ""),
+        title: state ? state.warning : "",
+      },
+      dom.span(
+        {},
+        property
+      )
+    );
+  }
+}
+
+module.exports = AnimatedPropertyName;
--- a/devtools/client/inspector/animation/components/AnimationDetailContainer.js
+++ b/devtools/client/inspector/animation/components/AnimationDetailContainer.js
@@ -14,26 +14,30 @@ const AnimatedPropertyListContainer =
   createFactory(require("./AnimatedPropertyListContainer"));
 
 class AnimationDetailContainer extends PureComponent {
   static get propTypes() {
     return {
       animation: PropTypes.object.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
+      getComputedStyle: PropTypes.func.isRequired,
       setDetailVisibility: PropTypes.func.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
     };
   }
 
   render() {
     const {
       animation,
       emitEventForTest,
       getAnimatedPropertyMap,
+      getComputedStyle,
       setDetailVisibility,
+      simulateAnimation,
     } = this.props;
 
     return dom.div(
       {
         className: "animation-detail-container"
       },
       animation ?
         AnimationDetailHeader(
@@ -45,16 +49,18 @@ class AnimationDetailContainer extends P
       :
         null,
       animation ?
         AnimatedPropertyListContainer(
           {
             animation,
             emitEventForTest,
             getAnimatedPropertyMap,
+            getComputedStyle,
+            simulateAnimation,
           }
         )
       :
         null
     );
   }
 }
 
--- a/devtools/client/inspector/animation/components/App.js
+++ b/devtools/client/inspector/animation/components/App.js
@@ -16,16 +16,17 @@ const SplitBox = createFactory(require("
 
 class App extends PureComponent {
   static get propTypes() {
     return {
       animations: PropTypes.arrayOf(PropTypes.object).isRequired,
       detailVisibility: PropTypes.bool.isRequired,
       emitEventForTest: PropTypes.func.isRequired,
       getAnimatedPropertyMap: PropTypes.func.isRequired,
+      getComputedStyle: PropTypes.func.isRequired,
       getNodeFromActor: PropTypes.func.isRequired,
       onHideBoxModelHighlighter: PropTypes.func.isRequired,
       onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
       selectAnimation: PropTypes.func.isRequired,
       setDetailVisibility: PropTypes.func.isRequired,
       setSelectedNode: PropTypes.func.isRequired,
       simulateAnimation: PropTypes.func.isRequired,
       toggleElementPicker: PropTypes.func.isRequired,
@@ -37,16 +38,17 @@ class App extends PureComponent {
   }
 
   render() {
     const {
       animations,
       detailVisibility,
       emitEventForTest,
       getAnimatedPropertyMap,
+      getComputedStyle,
       getNodeFromActor,
       onHideBoxModelHighlighter,
       onShowBoxModelHighlighterForNode,
       selectAnimation,
       setDetailVisibility,
       setSelectedNode,
       simulateAnimation,
       toggleElementPicker,
@@ -59,17 +61,19 @@ class App extends PureComponent {
       },
       animations.length ?
       SplitBox({
         className: "animation-container-splitter",
         endPanel: AnimationDetailContainer(
           {
             emitEventForTest,
             getAnimatedPropertyMap,
+            getComputedStyle,
             setDetailVisibility,
+            simulateAnimation,
           }
         ),
         endPanelControl: true,
         initialHeight: "50%",
         splitterSize: 1,
         startPanel: AnimationListContainer(
           {
             animations,
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/ColorPath.js
@@ -0,0 +1,184 @@
+/* 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/. */
+
+"use strict";
+
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const {colorUtils} = require("devtools/shared/css/color.js");
+
+const ComputedStylePath = require("./ComputedStylePath");
+
+/* Count for linearGradient ID */
+let LINEAR_GRADIENT_ID_COUNT = 0;
+
+class ColorPath extends ComputedStylePath {
+  constructor(props) {
+    super(props);
+
+    this.state = this.propToState(props);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    this.setState(this.propToState(nextProps));
+  }
+
+  getPropertyName() {
+    return "color";
+  }
+
+  getPropertyValue(keyframe) {
+    return keyframe.value;
+  }
+
+  propToState({ values }) {
+    const maxObject = { distance: 0 };
+
+    for (let i = 0; i < values.length - 1; i++) {
+      const value1 = getRGBA(values[i].value);
+      for (let j = i + 1; j < values.length; j++) {
+        const value2 = getRGBA(values[j].value);
+        const distance = getRGBADistance(value1, value2);
+
+        if (maxObject.distance >= distance) {
+          continue;
+        }
+
+        maxObject.distance = distance;
+        maxObject.value1 = value1;
+        maxObject.value2 = value2;
+      }
+    }
+
+    const maxDistance = maxObject.distance;
+    const baseValue =
+      maxObject.value1 < maxObject.value2 ? maxObject.value1 : maxObject.value2;
+
+    return { baseValue, maxDistance };
+  }
+
+  toSegmentValue(computedStyle) {
+    const { baseValue, maxDistance } = this.state;
+    const value = getRGBA(computedStyle);
+    return getRGBADistance(baseValue, value) / maxDistance;
+  }
+
+  /**
+   * Overide parent's method.
+   */
+  renderEasingHint() {
+    const {
+      easingHintStrokeWidth,
+      graphHeight,
+      totalDuration,
+      values,
+    } = this.props;
+
+    const hints = [];
+
+    for (let i = 0; i < values.length - 1; i++) {
+      const startKeyframe = values[i];
+      const endKeyframe = values[i + 1];
+      const startTime = startKeyframe.offset * totalDuration;
+      const endTime = endKeyframe.offset * totalDuration;
+
+      const g = dom.g(
+        {
+          className: "hint"
+        },
+        dom.title({}, startKeyframe.easing),
+        dom.rect(
+          {
+            x: startTime,
+            y: -graphHeight,
+            height: graphHeight,
+            width: endTime - startTime,
+            style: {
+              "stroke-width": easingHintStrokeWidth,
+            },
+          }
+        )
+      );
+      hints.push(g);
+    }
+
+    return hints;
+  }
+
+  /**
+   * Overide parent's method.
+   */
+  renderPathSegments(segments) {
+    for (const segment of segments) {
+      segment.y = 1;
+    }
+
+    const lastSegment = segments[segments.length - 1];
+    const id = `color-property-${ LINEAR_GRADIENT_ID_COUNT++ }`;
+    const path = super.renderPathSegments(segments, { fill: `url(#${ id })` });
+    const linearGradient = dom.linearGradient(
+      { id },
+      segments.map(segment => {
+        return dom.stop(
+          {
+            "stopColor": segment.computedStyle,
+            "offset": segment.x / lastSegment.x,
+          }
+        );
+      })
+    );
+
+    return [path, linearGradient];
+  }
+
+  render() {
+    return dom.g(
+      {
+        className: "color-path",
+      },
+      super.renderGraph()
+    );
+  }
+}
+
+/**
+ * Parse given RGBA string.
+ *
+ * @param {String} colorString
+ *        e.g. rgb(0, 0, 0) or rgba(0, 0, 0, 0.5) and so on.
+ * @return {Object}
+ *         RGBA {r: r, g: g, b: b, a: a}.
+ */
+function getRGBA(colorString) {
+  const color = new colorUtils.CssColor(colorString);
+  return color.getRGBATuple();
+}
+
+/**
+ * Return the distance from give two RGBA.
+ *
+ * @param {Object} rgba1
+ *        RGBA (format is same to getRGBA)
+ * @param {Object} rgba2
+ *        RGBA (format is same to getRGBA)
+ * @return {Number}
+ *         The range is 0 - 1.0.
+ */
+function getRGBADistance(rgba1, rgba2) {
+  const startA = rgba1.a;
+  const startR = rgba1.r * startA;
+  const startG = rgba1.g * startA;
+  const startB = rgba1.b * startA;
+  const endA = rgba2.a;
+  const endR = rgba2.r * endA;
+  const endG = rgba2.g * endA;
+  const endB = rgba2.b * endA;
+  const diffA = startA - endA;
+  const diffR = startR - endR;
+  const diffG = startG - endG;
+  const diffB = startB - endB;
+  return Math.sqrt(diffA * diffA + diffR * diffR + diffG * diffG + diffB * diffB);
+}
+
+module.exports = ColorPath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/ComputedStylePath.js
@@ -0,0 +1,233 @@
+/* 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/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const {
+  createPathSegments,
+  DEFAULT_DURATION_RESOLUTION,
+  getPreferredProgressThresholdByKeyframes,
+  toPathString,
+} = require("../../utils/graph-helper");
+
+/*
+ * This class is an abstraction for computed style path of keyframes.
+ * Subclass of this should implement the following methods:
+ *
+ * getPropertyName()
+ *   Returns property name which will be animated.
+ *   @return {String}
+ *           e.g. opacity
+ *
+ * getPropertyValue(keyframe)
+ *   Returns value which uses as animated keyframe value from given parameter.
+ *   @param {Object} keyframe
+ *   @return {String||Number}
+ *           e.g. 0
+ *
+ * toSegmentValue(computedStyle)
+ *   Convert computed style to segment value of graph.
+ *   @param {String||Number}
+ *          e.g. 0
+ *   @return {Number}
+ *          e.g. 0 (should be 0 - 1.0)
+ */
+class ComputedStylePath extends PureComponent {
+  static get propTypes() {
+    return {
+      componentWidth: PropTypes.number.isRequired,
+      easingHintStrokeWidth: PropTypes.number.isRequired,
+      graphHeight: PropTypes.number.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      totalDuration: PropTypes.number.isRequired,
+      values: PropTypes.array.isRequired,
+    };
+  }
+
+  /**
+   * Return an array containing the path segments between the given start and
+   * end keyframe values.
+   *
+   * @param {Object} startValue
+   *        Starting keyframe.
+   * @param {Object} startValue
+   *        Ending keyframe.
+   * @return {Array}
+   *         Array of path segment.
+   *         [{x: {Number} time, y: {Number} segment value}, ...]
+   */
+  getPathSegments(startValue, endValue) {
+    const {
+      componentWidth,
+      simulateAnimation,
+      totalDuration,
+    } = this.props;
+
+    const propertyName = this.getPropertyName();
+    const offsetDistance = endValue.offset - startValue.offset;
+    const duration = offsetDistance * totalDuration;
+
+    const keyframes = [startValue, endValue].map((keyframe, index) => {
+      return {
+        offset: index,
+        easing: keyframe.easing,
+        [getJsPropertyName(propertyName)]: this.getPropertyValue(keyframe),
+      };
+    });
+    const effect = {
+      duration,
+      fill: "forwards",
+    };
+    const simulatedAnimation = simulateAnimation(keyframes, effect, true);
+    const simulatedElement = simulatedAnimation.effect.target;
+    const win = simulatedElement.ownerGlobal;
+    const threshold = getPreferredProgressThresholdByKeyframes(keyframes);
+
+    const getSegment = time => {
+      simulatedAnimation.currentTime = time;
+      const computedStyle =
+        win.getComputedStyle(simulatedElement).getPropertyValue(propertyName);
+
+      return {
+        computedStyle,
+        x: time,
+        y: this.toSegmentValue(computedStyle),
+      };
+    };
+
+    const segments = createPathSegments(0, duration, duration / componentWidth, threshold,
+                                        DEFAULT_DURATION_RESOLUTION, getSegment);
+    const offset = startValue.offset * totalDuration;
+
+    for (const segment of segments) {
+      segment.x += offset;
+    }
+
+    return segments;
+  }
+
+  /**
+   * Render easing hint from given path segments.
+   *
+   * @param {Array} segments
+   *        Path segments.
+   * @return {Element}
+   *         Element which represents easing hint.
+   */
+  renderEasingHint(segments) {
+    const {
+      easingHintStrokeWidth,
+      totalDuration,
+      values,
+    } = this.props;
+
+    const hints = [];
+
+    for (let i = 0, indexOfSegments = 0; i < values.length - 1; i++) {
+      const startKeyframe = values[i];
+      const endKeyframe = values[i + 1];
+      const endTime = endKeyframe.offset * totalDuration;
+      const hintSegments = [];
+
+      for (; indexOfSegments < segments.length; indexOfSegments++) {
+        const segment = segments[indexOfSegments];
+        hintSegments.push(segment);
+
+        if (startKeyframe.offset === endKeyframe.offset) {
+          hintSegments.push(segments[++indexOfSegments]);
+          break;
+        } else if (segment.x === endTime) {
+          break;
+        }
+      }
+
+      const g = dom.g(
+        {
+          className: "hint"
+        },
+        dom.title({}, startKeyframe.easing),
+        dom.path(
+          {
+            d: `M${ hintSegments[0].x },${ hintSegments[0].y } ` +
+               toPathString(hintSegments),
+            style: {
+              "stroke-width": easingHintStrokeWidth,
+            }
+          }
+        )
+      );
+
+      hints.push(g);
+    }
+
+    return hints;
+  }
+
+  /**
+   * Render graph. This method returns React dom.
+   *
+   * @return {Element}
+   */
+  renderGraph() {
+    const { values } = this.props;
+
+    const segments = [];
+
+    for (let i = 0; i < values.length - 1; i++) {
+      const startValue = values[i];
+      const endValue = values[i + 1];
+      segments.push(...this.getPathSegments(startValue, endValue));
+    }
+
+    return [
+      this.renderPathSegments(segments),
+      this.renderEasingHint(segments)
+    ];
+  }
+
+  /**
+   * Return react dom fron given path segments.
+   *
+   * @param {Array} segments
+   * @param {Object} style
+   * @return {Element}
+   */
+  renderPathSegments(segments, style) {
+    const { graphHeight } = this.props;
+
+    for (const segment of segments) {
+      segment.y *= graphHeight;
+    }
+
+    let d = `M${ segments[0].x },0 `;
+    d += toPathString(segments);
+    d += `L${ segments[segments.length - 1].x },0 Z`;
+
+    return dom.path({ d, style });
+  }
+}
+
+/**
+ * Convert given CSS property name to JavaScript CSS name.
+ *
+ * @param {String} cssPropertyName
+ *        CSS property name (e.g. background-color).
+ * @return {String}
+ *         JavaScript CSS property name (e.g. backgroundColor).
+ */
+function getJsPropertyName(cssPropertyName) {
+  if (cssPropertyName == "float") {
+    return "cssFloat";
+  }
+  // https://drafts.csswg.org/cssom/#css-property-to-idl-attribute
+  return cssPropertyName.replace(/-([a-z])/gi, (str, group) => {
+    return group.toUpperCase();
+  });
+}
+
+module.exports = ComputedStylePath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/DiscretePath.js
@@ -0,0 +1,66 @@
+/* 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/. */
+
+"use strict";
+
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const ComputedStylePath = require("./ComputedStylePath");
+
+class DiscretePath extends ComputedStylePath {
+  static get propTypes() {
+    return {
+      property: PropTypes.string.isRequired,
+    };
+  }
+
+  constructor(props) {
+    super(props);
+
+    this.state = this.propToState(props);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    this.setState(this.propToState(nextProps));
+  }
+
+  getPropertyName() {
+    return this.props.property;
+  }
+
+  getPropertyValue(keyframe) {
+    return keyframe.value;
+  }
+
+  propToState({ property, getComputedStyle, values }) {
+    const discreteValues = [];
+
+    for (const keyframe of values) {
+      const style = getComputedStyle(property, { [property]: keyframe.value });
+
+      if (!discreteValues.includes(style)) {
+        discreteValues.push(style);
+      }
+    }
+
+    return { discreteValues };
+  }
+
+  toSegmentValue(computedStyle) {
+    const { discreteValues } = this.state;
+    return discreteValues.indexOf(computedStyle) / (discreteValues.length - 1);
+  }
+
+  render() {
+    return dom.g(
+      {
+        className: "discrete-path",
+      },
+      super.renderGraph()
+    );
+  }
+}
+
+module.exports = DiscretePath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/DistancePath.js
@@ -0,0 +1,34 @@
+/* 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/. */
+
+"use strict";
+
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+
+const ComputedStylePath = require("./ComputedStylePath");
+
+class DistancePath extends ComputedStylePath {
+  getPropertyName() {
+    return "opacity";
+  }
+
+  getPropertyValue(keyframe) {
+    return keyframe.distance;
+  }
+
+  toSegmentValue(computedStyle) {
+    return computedStyle;
+  }
+
+  render() {
+    return dom.g(
+      {
+        className: "distance-path",
+      },
+      super.renderGraph()
+    );
+  }
+}
+
+module.exports = DistancePath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/KeyframeMarkerItem.js
@@ -0,0 +1,33 @@
+/* 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/. */
+
+"use strict";
+
+const { PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+class KeyframeMarkerItem extends PureComponent {
+  static get propTypes() {
+    return {
+      keyframe: PropTypes.object.isRequired,
+    };
+  }
+
+  render() {
+    const { keyframe } = this.props;
+
+    return dom.li(
+      {
+        className: "keyframe-marker-item",
+        title: keyframe.value,
+        style: {
+          left: `${ keyframe.offset * 100 }%`,
+        },
+      }
+    );
+  }
+}
+
+module.exports = KeyframeMarkerItem;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/KeyframeMarkerList.js
@@ -0,0 +1,32 @@
+/* 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/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const KeyframeMarkerItem = createFactory(require("./KeyframeMarkerItem"));
+
+class KeyframeMarkerList extends PureComponent {
+  static get propTypes() {
+    return {
+      values: PropTypes.array.isRequired,
+    };
+  }
+
+  render() {
+    const { values } = this.props;
+
+    return dom.ul(
+      {
+        className: "keyframe-marker-list"
+      },
+      values.map(value => KeyframeMarkerItem({ keyframe: value }))
+    );
+  }
+}
+
+module.exports = KeyframeMarkerList;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/KeyframesGraph.js
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+
+const KeyframeMarkerList = createFactory(require("./KeyframeMarkerList"));
+const KeyframesGraphPath = createFactory(require("./KeyframesGraphPath"));
+
+class KeyframesGraph extends PureComponent {
+  static get propTypes() {
+    return {
+      getComputedStyle: PropTypes.func.isRequired,
+      property: PropTypes.string.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      type: PropTypes.string.isRequired,
+      values: PropTypes.array.isRequired,
+    };
+  }
+
+  render() {
+    const {
+      getComputedStyle,
+      property,
+      simulateAnimation,
+      type,
+      values,
+    } = this.props;
+
+    return dom.div(
+      {
+        className: `keyframes-graph ${ property }`
+      },
+      KeyframesGraphPath(
+        {
+          getComputedStyle,
+          property,
+          simulateAnimation,
+          type,
+          values,
+        }
+      ),
+      KeyframeMarkerList({ values })
+    );
+  }
+}
+
+module.exports = KeyframesGraph;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/KeyframesGraphPath.js
@@ -0,0 +1,110 @@
+/* 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/. */
+
+"use strict";
+
+const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
+const ReactDOM = require("devtools/client/shared/vendor/react-dom");
+
+const ColorPath = createFactory(require("./ColorPath"));
+const DiscretePath = createFactory(require("./DiscretePath"));
+const DistancePath = createFactory(require("./DistancePath"));
+
+const {
+  DEFAULT_EASING_HINT_STROKE_WIDTH,
+  DEFAULT_GRAPH_HEIGHT,
+  DEFAULT_KEYFRAMES_GRAPH_DURATION,
+} = require("../../utils/graph-helper");
+
+class KeyframesGraphPath extends PureComponent {
+  static get propTypes() {
+    return {
+      getComputedStyle: PropTypes.func.isRequired,
+      property: PropTypes.string.isRequired,
+      simulateAnimation: PropTypes.func.isRequired,
+      type: PropTypes.string.isRequired,
+      values: PropTypes.array.isRequired,
+    };
+  }
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      componentHeight: 0,
+      componentWidth: 0,
+    };
+  }
+
+  componentDidMount() {
+    this.updateState();
+  }
+
+  getPathComponent(type) {
+    switch (type) {
+      case "color" :
+        return ColorPath;
+      case "discrete" :
+        return DiscretePath;
+      default :
+        return DistancePath;
+    }
+  }
+
+  updateState() {
+    const thisEl = ReactDOM.findDOMNode(this);
+    this.setState({
+      componentHeight: thisEl.parentNode.clientHeight,
+      componentWidth: thisEl.parentNode.clientWidth,
+    });
+  }
+
+  render() {
+    const {
+      getComputedStyle,
+      property,
+      simulateAnimation,
+      type,
+      values,
+    } = this.props;
+    const {
+      componentHeight,
+      componentWidth,
+    } = this.state;
+
+    if (!componentWidth) {
+      return dom.svg();
+    }
+
+    const pathComponent = this.getPathComponent(type);
+    const strokeWidthInViewBox =
+      DEFAULT_EASING_HINT_STROKE_WIDTH / 2 / componentHeight * DEFAULT_GRAPH_HEIGHT;
+
+    return dom.svg(
+      {
+        className: "keyframes-graph-path",
+        preserveAspectRatio: "none",
+        viewBox: `0 -${ DEFAULT_GRAPH_HEIGHT + strokeWidthInViewBox } ` +
+                 `${ DEFAULT_KEYFRAMES_GRAPH_DURATION } ` +
+                 `${ DEFAULT_GRAPH_HEIGHT + strokeWidthInViewBox * 2 }`,
+      },
+      pathComponent(
+        {
+          componentWidth,
+          easingHintStrokeWidth: DEFAULT_EASING_HINT_STROKE_WIDTH,
+          getComputedStyle,
+          graphHeight: DEFAULT_GRAPH_HEIGHT,
+          property,
+          simulateAnimation,
+          totalDuration: DEFAULT_KEYFRAMES_GRAPH_DURATION,
+          values,
+        }
+      )
+    );
+  }
+}
+
+module.exports = KeyframesGraphPath;
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/components/keyframes-graph/moz.build
@@ -0,0 +1,14 @@
+# 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/.
+
+DevToolsModules(
+    'ColorPath.js',
+    'ComputedStylePath.js',
+    'DiscretePath.js',
+    'DistancePath.js',
+    'KeyframeMarkerItem.js',
+    'KeyframeMarkerList.js',
+    'KeyframesGraph.js',
+    'KeyframesGraphPath.js',
+)
--- a/devtools/client/inspector/animation/components/moz.build
+++ b/devtools/client/inspector/animation/components/moz.build
@@ -1,21 +1,23 @@
 # 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/.
 
 DIRS += [
-    'graph'
+    'graph',
+    'keyframes-graph'
 ]
 
 DevToolsModules(
     'AnimatedPropertyItem.js',
     'AnimatedPropertyList.js',
     'AnimatedPropertyListContainer.js',
     'AnimatedPropertyListHeader.js',
+    'AnimatedPropertyName.js',
     'AnimationDetailContainer.js',
     'AnimationDetailHeader.js',
     'AnimationItem.js',
     'AnimationList.js',
     'AnimationListContainer.js',
     'AnimationListHeader.js',
     'AnimationTarget.js',
     'AnimationTimelineTickItem.js',
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -1,30 +1,36 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
+  doc_multi_easings.html
+  doc_multi_keyframes.html
   doc_multi_timings.html
   doc_simple_animation.html
   head.js
   !/devtools/client/framework/test/shared-head.js
   !/devtools/client/inspector/test/head.js
   !/devtools/client/inspector/test/shared-head.js
   !/devtools/client/shared/test/test-actor-registry.js
   !/devtools/client/shared/test/test-actor.js
 
 [browser_animation_animated-property-list.js]
+[browser_animation_animated-property-name.js]
 [browser_animation_animation-detail_close-button.js]
 [browser_animation_animation-detail_title.js]
 [browser_animation_animation-detail_visibility.js]
 [browser_animation_animation-list.js]
 [browser_animation_animation-target.js]
 [browser_animation_animation-timeline-tick.js]
 [browser_animation_empty_on_invalid_nodes.js]
 [browser_animation_inspector_exists.js]
+[browser_animation_keyframes-graph_computed-value-path.js]
+[browser_animation_keyframes-graph_computed-value-path_easing-hint.js]
+[browser_animation_keyframes-graph_keyframe-marker.js]
 [browser_animation_summary-graph_animation-name.js]
 [browser_animation_summary-graph_compositor.js]
 [browser_animation_summary-graph_computed-timing-path.js]
 [browser_animation_summary-graph_delay-sign.js]
 [browser_animation_summary-graph_end-delay-sign.js]
 [browser_animation_summary-graph_effect-timing-path.js]
 [browser_animation_summary-graph_negative-delay-path.js]
 [browser_animation_summary-graph_negative-end-delay-path.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_animated-property-name.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test the following animated property name component features:
+// * name of property
+// * display compositor sign when the property was running on compositor.
+// * display warning when the property is runnable on compositor but was not.
+
+const TEST_DATA = [
+  {
+    property: "opacity",
+    isOnCompositor: true,
+  },
+  {
+    property: "transform",
+    isWarning: true,
+  },
+  {
+    property: "width",
+  },
+];
+
+add_task(async function () {
+  await addTab(URL_ROOT + "doc_simple_animation.html");
+  const { inspector, panel } = await openAnimationInspector();
+
+  info("Checking animated property name component");
+  await selectNodeAndWaitForAnimations(".compositor-notall", inspector);
+
+  const animatedPropertyNameEls = panel.querySelectorAll(".animated-property-name");
+  is(animatedPropertyNameEls.length, TEST_DATA.length,
+    `Number of animated property name elements should be ${ TEST_DATA.length }`);
+
+  for (const [index, animatedPropertyNameEl] of animatedPropertyNameEls.entries()) {
+    const testData = TEST_DATA[index];
+
+    info(`Checking text content for ${ testData.property }`);
+
+    const spanEl = animatedPropertyNameEl.querySelector("span");
+    ok(spanEl,
+      `<span> element should be in animated-property-name of ${ testData.property }`);
+    is(spanEl.textContent, testData.property,
+      `textContent should be ${ testData.property }`);
+
+    info(`Checking compositor sign for ${ testData.property }`);
+
+    if (testData.isOnCompositor) {
+      ok(animatedPropertyNameEl.classList.contains("compositor"),
+        "animatedPropertyNameEl should has .compositor class");
+      isnot(getComputedStyle(spanEl, "::before").width, "auto",
+        "width of ::before pseud should not be auto");
+    } else {
+      ok(!animatedPropertyNameEl.classList.contains("compositor"),
+        "animatedPropertyNameEl should not have .compositor class");
+      is(getComputedStyle(spanEl, "::before").width, "auto",
+        "width of ::before pseud should be auto");
+    }
+
+    info(`Checking warning for ${ testData.property }`);
+
+    if (testData.isWarning) {
+      ok(animatedPropertyNameEl.classList.contains("warning"),
+        "animatedPropertyNameEl should has .warning class");
+      is(getComputedStyle(spanEl).textDecorationStyle, "dotted",
+        "text-decoration-style of spanEl should be 'dotted'");
+      is(getComputedStyle(spanEl).textDecorationLine, "underline",
+        "text-decoration-line of spanEl should be 'underline'");
+    } else {
+      ok(!animatedPropertyNameEl.classList.contains("warning"),
+        "animatedPropertyNameEl should not have .warning class");
+      is(getComputedStyle(spanEl).textDecorationStyle, "solid",
+        "text-decoration-style of spanEl should be 'solid'");
+      is(getComputedStyle(spanEl).textDecorationLine, "none",
+        "text-decoration-line of spanEl should be 'none'");
+    }
+  }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path.js
@@ -0,0 +1,461 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following ComputedValuePath component:
+// * element existence
+// * path segments
+// * fill color by animation type
+// * stop color if the animation type is color
+
+const TEST_DATA = [
+  {
+    targetName: "multi-types",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "multi-types-reverse",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(0, 255, 0)" },
+          { offset: 1, color: "rgb(255, 0, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "middle-keyframe",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 0.5, color: "rgb(0, 0, 255)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 249.999, y: 0 },
+          { x: 250, y: 100 },
+          { x: 749.999, y: 100 },
+          { x: 750, y: 0 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 249.999, y: 0 },
+          { x: 250, y: 100 },
+          { x: 749.999, y: 100 },
+          { x: 750, y: 0 },
+          { x: 1000, y: 0 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 50 },
+          { x: 500, y: 100 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 0 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "steps-keyframe",
+    properties: [
+      {
+        name: "background-color",
+        computedValuePathClass: "color-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 0, y: 100 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+        expectedStopColors: [
+          { offset: 0, color: "rgb(255, 0, 0)" },
+          { offset: 0.499, color: "rgb(255, 0, 0)" },
+          { offset: 0.5, color: "rgb(128, 128, 0)" },
+          { offset: 0.999, color: "rgb(128, 128, 0)" },
+          { offset: 1, color: "rgb(0, 255, 0)" },
+        ]
+      },
+      {
+        name: "background-repeat",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "font-size",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "margin-left",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 50 },
+          { x: 999.999, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 50 },
+          { x: 999.999, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "text-align",
+        computedValuePathClass: "discrete-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 499.999, y: 0 },
+          { x: 500, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+      {
+        name: "transform",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 500, y: 0 },
+          { x: 500, y: 50 },
+          { x: 1000, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "steps-effect",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 250, y: 25 },
+          { x: 500, y: 50 },
+          { x: 750, y: 75 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "frames-keyframe",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 199, y: 0 },
+          { x: 200, y: 25 },
+          { x: 399, y: 25 },
+          { x: 400, y: 50 },
+          { x: 599, y: 50 },
+          { x: 600, y: 75 },
+          { x: 799, y: 75 },
+          { x: 800, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "narrow-offsets",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 100, y: 100 },
+          { x: 110, y: 100 },
+          { x: 114.9, y: 100 },
+          { x: 115, y: 50 },
+          { x: 129.9, y: 50 },
+          { x: 130, y: 0 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "duplicate-offsets",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 100 },
+          { x: 250, y: 100 },
+          { x: 499, y: 100 },
+          { x: 500, y: 100 },
+          { x: 500, y: 0 },
+          { x: 750, y: 50 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+];
+
+add_task(async function () {
+  await addTab(URL_ROOT + "doc_multi_keyframes.html");
+
+  const { inspector, panel } = await openAnimationInspector();
+
+  for (const { properties, targetName } of TEST_DATA) {
+    info(`Checking keyframes graph for ${ targetName }`);
+    await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
+
+    for (const property of properties) {
+      const {
+        name,
+        computedValuePathClass,
+        expectedPathSegments,
+        expectedStopColors,
+      } = property;
+
+      const testTarget = `${ name } in ${ targetName }`;
+      info(`Checking keyframes graph for ${ testTarget }`);
+      info(`Checking keyframes graph path existence for ${ testTarget }`);
+      const keyframesGraphPathEl = panel.querySelector(`.${ name }`);
+      ok(keyframesGraphPathEl,
+        `The keyframes graph path element of ${ testTarget } should be existence`);
+
+      info(`Checking computed value path existence for ${ testTarget }`);
+      const computedValuePathEl =
+        keyframesGraphPathEl.querySelector(`.${ computedValuePathClass }`);
+      ok(computedValuePathEl,
+        `The computed value path element of ${ testTarget } should be existence`);
+
+      info(`Checking path segments for ${ testTarget }`);
+      const pathEl = computedValuePathEl.querySelector("path");
+      ok(pathEl, `The <path> element of ${ testTarget } should be existence`);
+      assertPathSegments(pathEl, true, expectedPathSegments);
+
+      if (!expectedStopColors) {
+        continue;
+      }
+
+      info(`Checking linearGradient for ${ testTarget }`);
+      const linearGradientEl = computedValuePathEl.querySelector("linearGradient");
+      ok(linearGradientEl,
+        `The <linearGradientEl> element of ${ testTarget } should be existence`);
+
+      for (const expectedStopColor of expectedStopColors) {
+        const { offset, color } = expectedStopColor;
+        assertLinearGradient(linearGradientEl, offset, color);
+      }
+    }
+  }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path_easing-hint.js
@@ -0,0 +1,275 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following easing hint in ComputedValuePath.
+// * element existence
+// * path segments
+// * hint text
+
+const TEST_DATA = [
+  {
+    targetName: "no-easing",
+    properties: [
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "linear",
+            path: [
+              { x: 0, y: 100 },
+              { x: 500, y: 50 },
+              { x: 1000, y: 0 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "effect-easing",
+    properties: [
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "linear",
+            path: [
+              { x: 0, y: 100 },
+              { x: 500, y: 50 },
+              { x: 1000, y: 0 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "keyframe-easing",
+    properties: [
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "steps(2)",
+            path: [
+              { x: 0, y: 100 },
+              { x: 499, y: 100 },
+              { x: 500, y: 50 },
+              { x: 999, y: 50 },
+              { x: 1000, y: 0 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "both-easing",
+    properties: [
+      {
+        name: "margin-left",
+        expectedHints: [
+          {
+            hint: "steps(1)",
+            path: [
+              { x: 0, y: 0 },
+              { x: 999, y: 0 },
+              { x: 1000, y: 100 },
+            ],
+          },
+        ],
+      },
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "steps(2)",
+            path: [
+              { x: 0, y: 100 },
+              { x: 499, y: 100 },
+              { x: 500, y: 50 },
+              { x: 999, y: 50 },
+              { x: 1000, y: 0 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "narrow-keyframes",
+    properties: [
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "linear",
+            path: [
+              { x: 0, y: 0 },
+              { x: 100, y: 100 },
+            ],
+          },
+          {
+            hint: "steps(1)",
+            path: [
+              { x: 129, y: 100 },
+              { x: 130, y: 0 },
+            ],
+          },
+          {
+            hint: "linear",
+            path: [
+              { x: 130, y: 0 },
+              { x: 1000, y: 100 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "duplicate-keyframes",
+    properties: [
+      {
+        name: "opacity",
+        expectedHints: [
+          {
+            hint: "linear",
+            path: [
+              { x: 0, y: 0 },
+              { x: 500, y: 100 },
+            ],
+          },
+          {
+            hint: "",
+            path: [
+              { x: 500, y: 100 },
+              { x: 500, y: 0 },
+            ],
+          },
+          {
+            hint: "steps(1)",
+            path: [
+              { x: 500, y: 0 },
+              { x: 999, y: 0 },
+              { x: 1000, y: 100 },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "color-keyframes",
+    properties: [
+      {
+        name: "color",
+        expectedHints: [
+          {
+            hint: "ease-in",
+            rect: {
+              x: 0,
+              height: 100,
+              width: 400,
+            },
+          },
+          {
+            hint: "ease-out",
+            rect: {
+              x: 400,
+              height: 100,
+              width: 600,
+            },
+          },
+        ],
+      },
+    ],
+  },
+];
+
+add_task(async function () {
+  await addTab(URL_ROOT + "doc_multi_easings.html");
+
+  const { inspector, panel } = await openAnimationInspector();
+
+  for (const { properties, targetName } of TEST_DATA) {
+    info(`Checking keyframes graph for ${ targetName }`);
+    await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
+
+    for (const property of properties) {
+      const {
+        name,
+        expectedHints,
+      } = property;
+
+      const testTarget = `${ name } in ${ targetName }`;
+      info(`Checking easing hint for ${ testTarget }`);
+      info(`Checking easing hint existence for ${ testTarget }`);
+      const hintEls = panel.querySelectorAll(`.${ name } .hint`);
+      is(hintEls.length, expectedHints.length,
+        `Count of easing hint elements of ${ testTarget } `
+        + `should be ${ expectedHints.length }`);
+
+      for (let i = 0; i < expectedHints.length; i++) {
+        const hintTarget = `hint[${ i }] of ${ testTarget }`;
+
+        info(`Checking ${ hintTarget }`);
+        const hintEl = hintEls[i];
+        const expectedHint = expectedHints[i];
+
+        info(`Checking <title> in ${ hintTarget }`);
+        const titleEl = hintEl.querySelector("title");
+        ok(titleEl,
+          `<title> element in ${ hintTarget } should be existence`);
+        is(titleEl.textContent, expectedHint.hint,
+          `Content of <title> in ${ hintTarget } should be ${ expectedHint.hint }`);
+
+        let interactionEl = null;
+        if (expectedHint.path) {
+          info(`Checking <path> in ${ hintTarget }`);
+          interactionEl = hintEl.querySelector("path");
+          ok(interactionEl, `The <path> element  in ${ hintTarget } should be existence`);
+          assertPathSegments(interactionEl, false, expectedHint.path);
+        } else {
+          info(`Checking <rect> in ${ hintTarget }`);
+          interactionEl = hintEl.querySelector("rect");
+          ok(interactionEl, `The <rect> element  in ${ hintTarget } should be existence`);
+          is(interactionEl.getAttribute("x"), expectedHint.rect.x,
+            `x of <rect> in ${ hintTarget } should be ${ expectedHint.rect.x }`);
+          is(interactionEl.getAttribute("width"), expectedHint.rect.width,
+            `width of <rect> in ${ hintTarget } should be ${ expectedHint.rect.width }`);
+        }
+
+        info(`Checking interaction for ${ hintTarget }`);
+        interactionEl.scrollIntoView(false);
+        const win = hintEl.ownerGlobal;
+        // Mouse out once from pathEl.
+        EventUtils.synthesizeMouse(interactionEl, -1, -1, { type: "mouseout" }, win);
+        is(win.getComputedStyle(interactionEl).strokeOpacity, 0,
+          `stroke-opacity of hintEl for ${ hintTarget } should be 0`
+          + " while mouse is out from the element");
+        // Mouse over the pathEl.
+        ok(isStrokeChangedByMouseOver(interactionEl, win),
+          `stroke-opacity of hintEl for ${ hintTarget } should be 1`
+          + " while mouse is over the element");
+      }
+    }
+  }
+});
+
+function isStrokeChangedByMouseOver(pathEl, win) {
+  const boundingBox = pathEl.getBoundingClientRect();
+  const x = boundingBox.width / 2;
+
+  for (let y = 0; y < boundingBox.height; y++) {
+    EventUtils.synthesizeMouse(pathEl, x, y, { type: "mouseover" }, win);
+
+    if (win.getComputedStyle(pathEl).strokeOpacity == 1) {
+      return true;
+    }
+  }
+
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_keyframe-marker.js
@@ -0,0 +1,176 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for following keyframe marker.
+// * element existence
+// * title
+// * and left style
+
+const TEST_DATA = [
+  {
+    targetName: "multi-types",
+    properties: [
+      {
+        name: "background-color",
+        expectedValues: [
+          {
+            title: "rgb(255, 0, 0)",
+            left: "0%",
+          },
+          {
+            title: "rgb(0, 255, 0)",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "background-repeat",
+        expectedValues: [
+          {
+            title: "space round",
+            left: "0%",
+          },
+          {
+            title: "round space",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "font-size",
+        expectedValues: [
+          {
+            title: "10px",
+            left: "0%",
+          },
+          {
+            title: "20px",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "margin-left",
+        expectedValues: [
+          {
+            title: "0px",
+            left: "0%",
+          },
+          {
+            title: "100px",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "opacity",
+        expectedValues: [
+          {
+            title: "0",
+            left: "0%",
+          },
+          {
+            title: "1",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "text-align",
+        expectedValues: [
+          {
+            title: "right",
+            left: "0%",
+          },
+          {
+            title: "center",
+            left: "100%",
+          }
+        ],
+      },
+      {
+        name: "transform",
+        expectedValues: [
+          {
+            title: "translate(0px)",
+            left: "0%",
+          },
+          {
+            title: "translate(100px)",
+            left: "100%",
+          }
+        ],
+      },
+    ],
+  },
+  {
+    targetName: "narrow-offsets",
+    properties: [
+      {
+        name: "opacity",
+        expectedValues: [
+          {
+            title: "0",
+            left: "0%",
+          },
+          {
+            title: "1",
+            left: "10%",
+          },
+          {
+            title: "0",
+            left: "13%",
+          },
+          {
+            title: "1",
+            left: "100%",
+          },
+        ],
+      },
+    ],
+  }
+];
+
+add_task(async function () {
+  await addTab(URL_ROOT + "doc_multi_keyframes.html");
+
+  const { inspector, panel } = await openAnimationInspector();
+
+  for (const { properties, targetName } of TEST_DATA) {
+    info(`Checking keyframe marker for ${ targetName }`);
+    await selectNodeAndWaitForAnimations(`#${ targetName }`, inspector);
+
+    for (const property of properties) {
+      const {
+        name,
+        expectedValues,
+      } = property;
+
+      const testTarget = `${ name } in ${ targetName }`;
+      info(`Checking keyframe marker for ${ testTarget }`);
+      info(`Checking keyframe marker existence for ${ testTarget }`);
+      const markerEls = panel.querySelectorAll(`.${ name } .keyframe-marker-item`);
+      is(markerEls.length, expectedValues.length,
+        `Count of keyframe marker elements of ${ testTarget } `
+        + `should be ${ expectedValues.length }`);
+
+      for (let i = 0; i < expectedValues.length; i++) {
+        const hintTarget = `.keyframe-marker-item[${ i }] of ${ testTarget }`;
+
+        info(`Checking ${ hintTarget }`);
+        const markerEl = markerEls[i];
+        const expectedValue = expectedValues[i];
+
+        info(`Checking title in ${ hintTarget }`);
+        is(markerEl.getAttribute("title"), expectedValue.title,
+          `title in ${ hintTarget } should be ${ expectedValue.title }`);
+
+        info(`Checking left style in ${ hintTarget }`);
+        is(markerEl.style.left, expectedValue.left,
+          `left in ${ hintTarget } should be ${ expectedValue.left }`);
+      }
+    }
+  }
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/doc_multi_easings.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <style>
+    div {
+      background-color: lime;
+      height: 50px;
+    }
+    </style>
+  </head>
+  <body>
+    <script>
+    "use strict";
+
+    function createAnimation(name, keyframes, effectEasing) {
+      const div = document.createElement("div");
+      div.id = name;
+      document.body.appendChild(div);
+
+      const effect = {
+        duration: 100000,
+        fill: "forwards"
+      };
+
+      if (effectEasing) {
+        effect.easing = effectEasing;
+      }
+
+      div.animate(keyframes, effect);
+    }
+
+    createAnimation(
+      "no-easing",
+      [
+        { opacity: 1 },
+        { opacity: 0 },
+      ]
+    );
+
+    createAnimation(
+      "effect-easing",
+      [
+        { opacity: 1 },
+        { opacity: 0 },
+      ],
+      "frames(5)"
+    );
+
+    createAnimation(
+      "keyframe-easing",
+      [
+        { opacity: 1, easing: "steps(2)", },
+        { opacity: 0 },
+      ]
+    );
+
+    createAnimation(
+      "both-easing",
+      [
+        { offset: 0, opacity: 1, easing: "steps(2)", },
+        { offset: 0, marginLeft: "0px", easing: "steps(1)", },
+        { marginLeft: "100px", opacity: 0 },
+      ],
+      "steps(10)"
+    );
+
+    createAnimation(
+      "narrow-keyframes",
+      [
+        { opacity: 0, },
+        { offset: 0.1, opacity: 1, easing: "steps(1)", },
+        { offset: 0.13, opacity: 0, },
+      ]
+    );
+
+    createAnimation(
+      "duplicate-keyframes",
+      [
+        { opacity: 0 },
+        { offset: 0.5, opacity: 1, },
+        { offset: 0.5, opacity: 0, easing: "steps(1)", },
+        { opacity: 1, },
+      ]
+    );
+
+    createAnimation(
+      "color-keyframes",
+      [
+        { color: "red", easing: "ease-in", },
+        { offset: 0.4, color: "blue", easing: "ease-out", },
+        { color: "lime", },
+      ]
+    );
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/doc_multi_keyframes.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <style>
+    div {
+      width: 50px;
+      height: 50px;
+    }
+    </style>
+  </head>
+  <body>
+    <script>
+    "use strict";
+
+    function createAnimation(name, keyframes, effectEasing) {
+      const div = document.createElement("div");
+      div.id = name;
+      document.body.appendChild(div);
+
+      const effect = {
+        duration: 100000,
+        fill: "forwards"
+      };
+
+      if (effectEasing) {
+        effect.easing = effectEasing;
+      }
+
+      div.animate(keyframes, effect);
+    }
+
+    createAnimation(
+      "multi-types",
+      [
+        {
+          backgroundColor: "red",
+          backgroundRepeat: "space round",
+          fontSize: "10px",
+          marginLeft: "0px",
+          opacity: 0,
+          textAlign: "right",
+          transform: "translate(0px)"
+        },
+        {
+          backgroundColor: "lime",
+          backgroundRepeat: "round space",
+          fontSize: "20px",
+          marginLeft: "100px",
+          opacity: 1,
+          textAlign: "center",
+          transform: "translate(100px)"
+        },
+      ]
+    );
+
+    createAnimation(
+      "multi-types-reverse",
+      [
+        {
+          backgroundColor: "lime",
+          backgroundRepeat: "space",
+          fontSize: "20px",
+          marginLeft: "100px",
+          opacity: 1,
+          textAlign: "center",
+          transform: "translate(100px)"
+        },
+        {
+          backgroundColor: "red",
+          backgroundRepeat: "round",
+          fontSize: "10px",
+          marginLeft: "0px",
+          opacity: 0,
+          textAlign: "right",
+          transform: "translate(0px)"
+        },
+      ]
+    );
+
+    createAnimation(
+      "middle-keyframe",
+      [
+        {
+          backgroundColor: "red",
+          backgroundRepeat: "space",
+          fontSize: "10px",
+          marginLeft: "0px",
+          opacity: 0,
+          textAlign: "right",
+          transform: "translate(0px)"
+        },
+        {
+          backgroundColor: "blue",
+          backgroundRepeat: "round",
+          fontSize: "20px",
+          marginLeft: "100px",
+          opacity: 1,
+          textAlign: "center",
+          transform: "translate(100px)"
+        },
+        {
+          backgroundColor: "lime",
+          backgroundRepeat: "space",
+          fontSize: "10px",
+          marginLeft: "0px",
+          opacity: 0,
+          textAlign: "right",
+          transform: "translate(0px)"
+        },
+      ]
+    );
+
+    createAnimation(
+      "steps-keyframe",
+      [
+        {
+          backgroundColor: "red",
+          backgroundRepeat: "space",
+          fontSize: "10px",
+          marginLeft: "0px",
+          opacity: 0,
+          textAlign: "right",
+          transform: "translate(0px)",
+          easing: "steps(2)"
+        },
+        {
+          backgroundColor: "lime",
+          backgroundRepeat: "round",
+          fontSize: "20px",
+          marginLeft: "100px",
+          opacity: 1,
+          textAlign: "center",
+          transform: "translate(100px)"
+        },
+      ]
+    );
+
+    createAnimation(
+      "steps-effect",
+      [
+        {
+          opacity: 0
+        },
+        {
+          opacity: 1
+        },
+      ],
+      "steps(2)"
+    );
+
+    createAnimation(
+      "frames-keyframe",
+      [
+        {
+          easing: "frames(5)",
+          opacity: 0,
+        },
+        {
+          opacity: 1
+        },
+      ]
+    );
+
+    createAnimation(
+      "narrow-offsets",
+      [
+        {
+          opacity: 0,
+        },
+        {
+          opacity: 1,
+          easing: "steps(2)",
+          offset: 0.1,
+        },
+        {
+          opacity: 0,
+          offset: 0.13,
+        },
+      ]
+    );
+
+    createAnimation(
+      "duplicate-offsets",
+      [
+        {
+          opacity: 1,
+        },
+        {
+          opacity: 1,
+          offset: 0.5,
+        },
+        {
+          opacity: 0,
+          offset: 0.5,
+        },
+        {
+          opacity: 1,
+          offset: 1,
+        },
+      ]
+    );
+    </script>
+  </body>
+</html>
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -204,16 +204,34 @@ const waitForAllAnimationTargets = async
  */
 const waitForAllSummaryGraph = async function (animationInspector) {
   for (let i = 0; i < animationInspector.animations.length; i++) {
     await animationInspector.once("animation-summary-graph-rendered");
   }
 };
 
 /**
+ * Check the <stop> element in the given linearGradientEl for the correct offset
+ * and color attributes.
+ *
+ * @param {Element} linearGradientEl
+          <linearGradient> element which has <stop> element.
+ * @param {Number} offset
+ *        float which represents the "offset" attribute of <stop>.
+ * @param {String} expectedColor
+ *        e.g. rgb(0, 0, 255)
+ */
+function assertLinearGradient(linearGradientEl, offset, expectedColor) {
+  const stopEl = findStopElement(linearGradientEl, offset);
+  ok(stopEl, `stop element at offset ${ offset } should exist`);
+  is(stopEl.getAttribute("stop-color"), expectedColor,
+    `stop-color of stop element at offset ${ offset } should be ${ expectedColor }`);
+}
+
+/**
  * SummaryGraph is constructed by <path> element.
  * This function checks the vertex of path segments.
  *
  * @param {Element} pathEl
  *        <path> element.
  * @param {boolean} hasClosePath
  *        Set true if the path shoud be closing.
  * @param {Object} expectedValues
@@ -289,8 +307,28 @@ function findAnimationItemElementsByTarg
 
     if (className === targetClassName) {
       return animationTargetEl.closest(".animation-item");
     }
   }
 
   return null;
 }
+
+/**
+ * Find the <stop> element which has the given offset in the given linearGradientEl.
+ *
+ * @param {Element} linearGradientEl
+ *        <linearGradient> element which has <stop> element.
+ * @param {Number} offset
+ *        Float which represents the "offset" attribute of <stop>.
+ * @return {Element}
+ *         If can't find suitable element, returns null.
+ */
+function findStopElement(linearGradientEl, offset) {
+  for (const stopEl of linearGradientEl.querySelectorAll("stop")) {
+    if (offset <= parseFloat(stopEl.getAttribute("offset"))) {
+      return stopEl;
+    }
+  }
+
+  return null;
+}
--- a/devtools/client/inspector/animation/utils/graph-helper.js
+++ b/devtools/client/inspector/animation/utils/graph-helper.js
@@ -1,31 +1,35 @@
 /* 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/. */
 
 "use strict";
 
 // BOUND_EXCLUDING_TIME should be less than 1ms and is used to exclude start
-// and end bounds when dividing  duration in createPathSegments.
+// and end bounds when dividing duration in createPathSegments.
 const BOUND_EXCLUDING_TIME = 0.001;
 // We define default graph height since if the height of viewport in SVG is
 // too small (e.g. 1), vector-effect may not be able to calculate correctly.
 const DEFAULT_GRAPH_HEIGHT = 100;
+// Default animation duration for keyframes graph.
+const DEFAULT_KEYFRAMES_GRAPH_DURATION = 1000;
 // DEFAULT_MIN_PROGRESS_THRESHOLD shoud be between more than 0 to 1.
 const DEFAULT_MIN_PROGRESS_THRESHOLD = 0.1;
 // In the createPathSegments function, an animation duration is divided by
-// DURATION_RESOLUTION in order to draw the way the animation progresses.
+// DEFAULT_DURATION_RESOLUTION in order to draw the way the animation progresses.
 // But depending on the timing-function, we may be not able to make the graph
 // smoothly progress if this resolution is not high enough.
 // So, if the difference of animation progress between 2 divisions is more than
 // DEFAULT_MIN_PROGRESS_THRESHOLD * DEFAULT_GRAPH_HEIGHT, then createPathSegments
-// re-divides by DURATION_RESOLUTION.
-// DURATION_RESOLUTION shoud be integer and more than 2.
-const DURATION_RESOLUTION = 4;
+// re-divides by DEFAULT_DURATION_RESOLUTION.
+// DEFAULT_DURATION_RESOLUTION shoud be integer and more than 2.
+const DEFAULT_DURATION_RESOLUTION = 4;
+// Stroke width for easing hint.
+const DEFAULT_EASING_HINT_STROKE_WIDTH = 5;
 
 /**
  * The helper class for creating summary graph.
  */
 class SummaryGraphHelper {
   /**
    * Constructor.
    *
@@ -117,34 +121,34 @@ function createPathSegments(startTime, e
   let pathSegments = [];
 
   // Append the segment for the startTime position.
   const startTimeSegment = getSegment(startTime);
   pathSegments.push(startTimeSegment);
   let previousSegment = startTimeSegment;
 
   // Split the duration in equal intervals, and iterate over them.
-  // See the definition of DURATION_RESOLUTION for more information about this.
+  // See the definition of DEFAULT_DURATION_RESOLUTION for more information about this.
   const interval = (endTime - startTime) / resolution;
   for (let index = 1; index <= resolution; index++) {
     // Create a segment for this interval.
     const currentSegment = getSegment(startTime + index * interval);
 
     // If the distance between the Y coordinate (the animation's progress) of
     // the previous segment and the Y coordinate of the current segment is too
     // large, then recurse with a smaller duration to get more details
     // in the graph.
     if (Math.abs(currentSegment.y - previousSegment.y) > minProgressThreshold) {
       // Divide the current interval (excluding start and end bounds
       // by adding/subtracting BOUND_EXCLUDING_TIME).
       const nextStartTime = previousSegment.x + BOUND_EXCLUDING_TIME;
       const nextEndTime = currentSegment.x - BOUND_EXCLUDING_TIME;
       const segments =
         createPathSegments(nextStartTime, nextEndTime, minSegmentDuration,
-                           minProgressThreshold, DURATION_RESOLUTION, getSegment);
+                           minProgressThreshold, DEFAULT_DURATION_RESOLUTION, getSegment);
       pathSegments = pathSegments.concat(segments);
     }
 
     pathSegments.push(currentSegment);
     previousSegment = currentSegment;
   }
 
   return pathSegments;
@@ -156,20 +160,20 @@ function createPathSegments(startTime, e
  *
  * @param {Array} keyframes
  *        Array of keyframe.
  * @return {Number}
  *         Preferred duration resolution.
  */
 function getPreferredDurationResolution(keyframes) {
   if (!keyframes) {
-    return DURATION_RESOLUTION;
+    return DEFAULT_DURATION_RESOLUTION;
   }
 
-  let durationResolution = DURATION_RESOLUTION;
+  let durationResolution = DEFAULT_DURATION_RESOLUTION;
   let previousOffset = 0;
   for (let keyframe of keyframes) {
     if (previousOffset && previousOffset != keyframe.offset) {
       const interval = keyframe.offset - previousOffset;
       durationResolution = Math.max(durationResolution, Math.ceil(1 / interval));
     }
     previousOffset = keyframe.offset;
   }
@@ -194,16 +198,33 @@ function getPreferredProgressThreshold(s
   if ((stepsOrFrames = getStepsOrFramesCount(state.easing))) {
     threshold = Math.min(threshold, (1 / (stepsOrFrames + 1)));
   }
 
   if (!keyframes) {
     return threshold;
   }
 
+  threshold = Math.min(threshold, getPreferredProgressThresholdByKeyframes(keyframes));
+
+  return threshold;
+}
+
+/**
+ * Return preferred progress threshold by keyframes.
+ *
+ * @param {Array} keyframes
+ *        Array of keyframe.
+ * @return {float}
+ *         Preferred threshold.
+ */
+function getPreferredProgressThresholdByKeyframes(keyframes) {
+  let threshold = DEFAULT_MIN_PROGRESS_THRESHOLD;
+  let stepsOrFrames;
+
   for (let i = 0; i < keyframes.length - 1; i++) {
     const keyframe = keyframes[i];
 
     if (!keyframe.easing) {
       continue;
     }
 
     if ((stepsOrFrames = getStepsOrFramesCount(keyframe.easing))) {
@@ -234,11 +255,17 @@ function getStepsOrFramesCount(easing) {
 function toPathString(segments) {
   let pathString = "";
   segments.forEach(segment => {
     pathString += `L${ segment.x },${ segment.y } `;
   });
   return pathString;
 }
 
-module.exports.DEFAULT_GRAPH_HEIGHT = DEFAULT_GRAPH_HEIGHT;
+exports.createPathSegments = createPathSegments;
+exports.DEFAULT_DURATION_RESOLUTION = DEFAULT_DURATION_RESOLUTION;
+exports.DEFAULT_EASING_HINT_STROKE_WIDTH = DEFAULT_EASING_HINT_STROKE_WIDTH;
+exports.DEFAULT_GRAPH_HEIGHT = DEFAULT_GRAPH_HEIGHT;
+exports.DEFAULT_KEYFRAMES_GRAPH_DURATION = DEFAULT_KEYFRAMES_GRAPH_DURATION;
+exports.getPreferredProgressThresholdByKeyframes =
+  getPreferredProgressThresholdByKeyframes;
 exports.SummaryGraphHelper = SummaryGraphHelper;
 exports.toPathString = toPathString;
--- a/devtools/client/netmonitor/src/components/RequestListColumnResponseHeader.js
+++ b/devtools/client/netmonitor/src/components/RequestListColumnResponseHeader.js
@@ -2,32 +2,46 @@
  * 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/. */
 
 "use strict";
 
 const { Component } = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
-const { getResponseHeader } = require("../utils/request-utils");
+const {
+  getResponseHeader,
+  fetchNetworkUpdatePacket
+} = require("../utils/request-utils");
 
 const { div } = dom;
 
 /**
  * Renders a response header column in the requests list.  The actual
  * header to show is passed as a prop.
  */
 class RequestListColumnResponseHeader extends Component {
   static get propTypes() {
     return {
+      connector: PropTypes.object.isRequired,
       item: PropTypes.object.isRequired,
       header: PropTypes.string.isRequired,
     };
   }
 
+  componentDidMount() {
+    let { item, connector } = this.props;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["responseHeaders"]);
+  }
+
+  componentWillReceiveProps(nextProps) {
+    let { item, connector } = nextProps;
+    fetchNetworkUpdatePacket(connector.requestData, item, ["responseHeaders"]);
+  }
+
   shouldComponentUpdate(nextProps) {
     const currHeader = getResponseHeader(this.props.item, this.props.header);
     const nextHeader = getResponseHeader(nextProps.item, nextProps.header);
     return currHeader !== nextHeader;
   }
 
   render() {
     let header = getResponseHeader(this.props.item, this.props.header);
--- a/devtools/client/netmonitor/src/components/RequestListContent.js
+++ b/devtools/client/netmonitor/src/components/RequestListContent.js
@@ -90,40 +90,33 @@ class RequestListContent extends Compone
   }
 
   componentDidMount() {
     // Install event handler for displaying a tooltip
     this.tooltip.startTogglingOnHover(this.refs.contentEl, this.onHover, {
       toggleDelay: REQUESTS_TOOLTIP_TOGGLE_DELAY,
       interactive: true
     });
-    // Everytime the list is created or pruned, re-enable scroll to bottom feature.
-    this.shouldScrollToBottom = true;
-
     // Install event handler to hide the tooltip on scroll
     this.refs.contentEl.addEventListener("scroll", this.onScroll, true);
     this.onResize();
   }
 
-  componentDidUpdate(prevProps) {
-    if (!this.shouldScrollToBottom) {
-      return;
-    }
+  componentWillUpdate(nextProps) {
     // Check if the list is scrolled to bottom before the UI update.
     // The scroll is ever needed only if new rows are added to the list.
-    const hasNewRequests = this.props.displayedRequests.size -
-      prevProps.displayedRequests.size > 0;
+    const delta = nextProps.displayedRequests.size - this.props.displayedRequests.size;
+    this.shouldScrollBottom = delta > 0 && this.isScrolledToBottom();
+  }
+
+  componentDidUpdate(prevProps) {
+    let node = this.refs.contentEl;
     // Keep the list scrolled to bottom if a new row was added
-    if (hasNewRequests) {
-      // Set a boolean flag to help `scroll` listener to know that the next event
-      // is related to the scroll to bottom and can be ignored.
-      this.ignoreNextScroll = true;
-
+    if (this.shouldScrollBottom && node.scrollTop !== MAX_SCROLL_HEIGHT) {
       // Using maximum scroll height rather than node.scrollHeight to avoid sync reflow.
-      let node = this.refs.contentEl;
       node.scrollTop = MAX_SCROLL_HEIGHT;
     }
   }
 
   componentWillUnmount() {
     this.refs.contentEl.removeEventListener("scroll", this.onScroll, true);
 
     // Uninstall the tooltip event handler
@@ -195,24 +188,16 @@ class RequestListContent extends Compone
     return itemEl.querySelector(".requests-list-file");
   }
 
   /**
    * Scroll listener for the requests menu view.
    */
   onScroll() {
     this.tooltip.hide();
-
-    // Ignore scroll related to new requests being displayed
-    // To prevent slow reflows done in isScrolledToBottom.
-    if (this.ignoreNextScroll) {
-      this.ignoreNextScroll = false;
-      return;
-    }
-    this.shouldScrollToBottom = this.isScrolledToBottom();
   }
 
   /**
    * Handler for keyboard events. For arrow up/down, page up/down, home/end,
    * move the selection up or down.
    */
   onKeyDown(evt) {
     let delta;
@@ -254,17 +239,17 @@ class RequestListContent extends Compone
     this.contextMenu.open(evt, selectedRequest, sortedRequests);
   }
 
   /**
    * If selection has just changed (by keyboard navigation), don't keep the list
    * scrolled to bottom, but allow scrolling up with the selection.
    */
   onFocusedNodeChange() {
-    this.shouldScrollToBottom = false;
+    this.shouldScrollBottom = false;
   }
 
   render() {
     const {
       connector,
       columns,
       displayedRequests,
       firstRequestStartedMillis,
@@ -280,19 +265,17 @@ class RequestListContent extends Compone
     return (
       div({ className: "requests-list-wrapper" },
         div({ className: "requests-list-table" },
           div({
             ref: "contentEl",
             className: "requests-list-contents",
             tabIndex: 0,
             onKeyDown: this.onKeyDown,
-            // scale is null until the waterfall is initialized
-            style: { "--timings-scale": scale ? scale : 0,
-                     "--timings-rev-scale": (scale ? 1 / scale : 1) }
+            style: { "--timings-scale": scale, "--timings-rev-scale": 1 / scale }
           },
             RequestListHeader(),
             displayedRequests.map((item, index) => RequestListItem({
               firstRequestStartedMillis,
               fromCache: item.status === "304" || item.fromCache,
               connector,
               columns,
               item,
--- a/devtools/client/netmonitor/src/components/RequestListItem.js
+++ b/devtools/client/netmonitor/src/components/RequestListItem.js
@@ -258,17 +258,21 @@ class RequestListItem extends Component 
         }),
         columns.latency && RequestListColumnTime({
           connector,
           item,
           firstRequestStartedMillis,
           type: "latency",
         }),
         ...RESPONSE_HEADERS.filter(header => columns[header]).map(
-          header => RequestListColumnResponseHeader({ item, header }),
+          header => RequestListColumnResponseHeader({
+            connector,
+            item,
+            header
+          }),
         ),
         columns.waterfall && RequestListColumnWaterfall({
           connector,
           firstRequestStartedMillis,
           item,
           onWaterfallMouseDown,
         }),
       )
--- a/devtools/client/netmonitor/test/browser_net_autoscroll.js
+++ b/devtools/client/netmonitor/test/browser_net_autoscroll.js
@@ -36,21 +36,16 @@ add_task(function* () {
   // save for comparison later
   let scrollTop = requestsContainer.scrollTop;
   yield waitForNetworkEvents(monitor, 8);
   yield waitSomeTime();
   is(requestsContainer.scrollTop, scrollTop, "Did not scroll.");
 
   // (3) Now set the scroll position back at the bottom and check that
   // additional requests *do* cause the container to scroll down.
-  // Wait for another request to be displayed in order to ensure that
-  // scrollTop is set just before next RequestListContent.componentWillUpdate fires.
-  // If scrollTop is set between componentWillUpdate and componentDidUpdate,
-  // the view won't be scrolled.
-  yield waitForNetworkEvents(monitor, 8);
   requestsContainer.scrollTop = requestsContainer.scrollHeight;
   ok(scrolledToBottom(requestsContainer), "Set scroll position to bottom.");
   yield waitForNetworkEvents(monitor, 8);
   yield waitForScroll();
   ok(true, "Still scrolled to bottom.");
 
   // (4) Now select the first item in the list
   // and check that additional requests do not change the scroll position
--- a/devtools/client/netmonitor/test/browser_net_columns_showhide.js
+++ b/devtools/client/netmonitor/test/browser_net_columns_showhide.js
@@ -1,27 +1,37 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Test showing/hiding columns.
  */
-
 add_task(async function () {
   let { monitor, tab } = await initNetMonitor(SIMPLE_URL);
   info("Starting test... ");
 
-  let { document, store, parent } = monitor.panelWin;
+  let { document, store, parent, connector, windowRequire } = monitor.panelWin;
+  let { requestData } = connector;
+  let {
+    getSortedRequests,
+  } = windowRequire("devtools/client/netmonitor/src/selectors/index");
 
   let wait = waitForNetworkEvents(monitor, 1);
   tab.linkedBrowser.loadURI(SIMPLE_URL);
   await wait;
 
+  let item = getSortedRequests(store.getState()).get(0);
+  ok(item.responseHeadersAvailable, "headers are available for lazily fetching");
+
+  if (item.responseHeadersAvailable && !item.responseHeaders) {
+    await requestData(item.id, "responseHeaders");
+  }
+
   let requestsContainer = document.querySelector(".requests-list-contents");
   ok(requestsContainer, "Container element exists as expected.");
   let headers = document.querySelector(".requests-list-headers");
 
   let columns = store.getState().ui.columns;
   for (let column in columns) {
     if (columns[column]) {
       await testVisibleColumnContextMenuItem(column, document, parent);
@@ -48,66 +58,73 @@ add_task(async function () {
 async function testWhiteSpaceContextMenuItem(column, document, parent) {
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 
   info(`Right clicking on white-space in the header to get the context menu`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector(".devtools-toolbar.requests-list-headers"));
 
+  // Wait for next tick to do stuff async and force repaint.
+  await waitForTick();
   await toggleAndCheckColumnVisibility(column, document, parent);
 }
 
 async function testVisibleColumnContextMenuItem(column, document, parent) {
   ok(document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be visible`);
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-status-button") ||
     document.querySelector("#requests-list-waterfall-button"));
 
+  await waitForTick();
+
   let menuItem = parent.document.querySelector(`#request-list-header-${column}-toggle`);
 
   is(menuItem.getAttribute("type"), "checkbox",
      `${column} menu item should have type="checkbox" attribute`);
   is(menuItem.getAttribute("checked"), "true",
      `checked state of ${column} menu item should be correct`);
   ok(!menuItem.disabled, `disabled state of ${column} menu item should be correct`);
 
   let onHeaderRemoved = waitForDOM(document, `#requests-list-${column}-button`, 0);
   menuItem.click();
 
   await onHeaderRemoved;
+  await waitForTick();
 
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 }
 
 async function testHiddenColumnContextMenuItem(column, document, parent) {
   ok(!document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be hidden`);
 
   info(`Clicking context-menu item for ${column}`);
   EventUtils.sendMouseEvent({ type: "contextmenu" },
     document.querySelector("#requests-list-status-button") ||
     document.querySelector("#requests-list-waterfall-button"));
 
+  await waitForTick();
   await toggleAndCheckColumnVisibility(column, document, parent);
 }
 
 async function toggleAndCheckColumnVisibility(column, document, parent) {
   let menuItem = parent.document.querySelector(`#request-list-header-${column}-toggle`);
 
   is(menuItem.getAttribute("type"), "checkbox",
      `${column} menu item should have type="checkbox" attribute`);
   ok(!menuItem.getAttribute("checked"),
      `checked state of ${column} menu item should be correct`);
   ok(!menuItem.disabled, `disabled state of ${column} menu item should be correct`);
 
   let onHeaderAdded = waitForDOM(document, `#requests-list-${column}-button`, 1);
   menuItem.click();
 
   await onHeaderAdded;
+  await waitForTick();
 
   ok(document.querySelector(`#requests-list-${column}-button`),
      `Column ${column} should be visible`);
 }
--- a/devtools/client/themes/animation.css
+++ b/devtools/client/themes/animation.css
@@ -2,23 +2,32 @@
  * 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/. */
 
 /* Animation-inspector specific theme variables */
 
 :root {
   --animation-even-background-color: rgba(0, 0, 0, 0.05);
   --command-pick-image: url(chrome://devtools/skin/images/command-pick.svg);
+  --fast-track-image: url("images/animation-fast-track.svg");
+  --fill-color-cssanimation: var(--theme-contrast-background);
+  --fill-color-csstransition: var(--theme-highlight-blue);
+  --fill-color-scriptanimation: var(--theme-graphs-green);
   --graph-right-offset: 10px;
+  --keyframe-marker-shadow-color: #c4c4c4;
   --sidebar-width: 200px;
+  --stroke-color-cssanimation: var(--theme-highlight-lightorange);
+  --stroke-color-csstransition: var(--theme-highlight-bluegrey);
+  --stroke-color-scriptanimation: var(--theme-highlight-green);
   --tick-line-style: 0.5px solid rgba(128, 136, 144, 0.5);
 }
 
 :root.theme-dark {
   --animation-even-background-color: rgba(255, 255, 255, 0.05);
+  --keyframe-marker-shadow-color: #818181;
 }
 
 :root.theme-firebug {
   --command-pick-image: url(chrome://devtools/skin/images/firebug/command-pick.svg);
 }
 
 /* Root element of animation inspector */
 #animation-container {
@@ -77,28 +86,28 @@
   height: 30px;
 }
 
 .animation-item:nth-child(2n+1) {
   background-color: var(--animation-even-background-color);
 }
 
 .animation-item.cssanimation {
-  --computed-timing-graph-color: var(--theme-contrast-background);
-  --effect-timing-graph-color: var(--theme-highlight-lightorange);
+  --computed-timing-graph-color: var(--fill-color-cssanimation);
+  --effect-timing-graph-color: var(--stroke-color-cssanimation);
 }
 
 .animation-item.csstransition {
-  --computed-timing-graph-color: var(--theme-highlight-blue);
-  --effect-timing-graph-color: var(--theme-highlight-bluegrey);
+  --computed-timing-graph-color: var(--fill-color-csstransition);
+  --effect-timing-graph-color: var(--stroke-color-csstransition);
 }
 
 .animation-item.scriptanimation {
-  --computed-timing-graph-color: var(--theme-graphs-green);
-  --effect-timing-graph-color: var(--theme-highlight-green);
+  --computed-timing-graph-color: var(--fill-color-scriptanimation);
+  --effect-timing-graph-color: var(--stroke-color-scriptanimation);
 }
 
 .animation-item.selected {
   background-color: var(--theme-selection-background-hover);
 }
 
 /* Animation Target */
 .animation-target {
@@ -117,17 +126,17 @@
 .animation-summary-graph {
   height: 100%;
   padding-top: 5px;
   position: relative;
   width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
 }
 
 .animation-summary-graph.compositor::after {
-  background-image: url("images/animation-fast-track.svg");
+  background-image: var(--fast-track-image);
   background-repeat: no-repeat;
   content: "";
   display: block;
   fill: var(--theme-content-color3);
   height: 100%;
   position: absolute;
   right: 0;
   top: 5px;
@@ -286,30 +295,163 @@
 .keyframes-progress-tick-item.right {
   border-right: var(--tick-line-style);
 }
 
 /* Animated Property List */
 .animated-property-list {
   flex: 1;
   list-style-type: none;
-  margin-top: 0;
+  margin: 0;
   overflow-y: auto;
   padding: 0;
 }
 
 /* Animated Property Item */
 .animated-property-item {
+  display: flex;
   height: 30px;
 }
 
 .animated-property-item:nth-child(2n+1) {
   background-color: var(--animation-even-background-color);
 }
 
+/* Animated Property Name */
+.animated-property-name {
+  align-items: center;
+  display: flex;
+  height: 100%;
+  justify-content: flex-end;
+  padding-right: 10px;
+  width: var(--sidebar-width);
+}
+
+.animated-property-name.compositor span {
+  padding-left: 15px;
+  position: relative;
+}
+
+.animated-property-list-container.cssanimation .animated-property-name.compositor {
+  --fast-track-color: var(--stroke-color-cssanimation);
+}
+
+.animated-property-list-container.csstransition .animated-property-name.compositor {
+  --fast-track-color: var(--stroke-color-csstransition);
+}
+
+.animated-property-list-container.scriptanimation .animated-property-name.compositor {
+  --fast-track-color: var(--stroke-color-scriptanimation);
+}
+
+.animated-property-name.compositor span::before {
+  background-image: var(--fast-track-image);
+  background-repeat: no-repeat;
+  background-size: contain;
+  content: "";
+  fill: var(--fast-track-color);
+  height: 100%;
+  position: absolute;
+  left: 0;
+  width: 15px;
+  -moz-context-properties: fill;
+}
+
+.animated-property-name.warning span {
+  text-decoration: underline dotted;
+}
+
+/* Keyframes Graph */
+.keyframes-graph {
+  height: 100%;
+  padding-top: 3px;
+  position: relative;
+  width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
+}
+
+.keyframes-graph-path {
+  height: 100%;
+  width: 100%;
+}
+
+.keyframes-graph-path path {
+  fill: #00b0bd88;
+  stroke: #00b0bd;
+  vector-effect: non-scaling-stroke;
+  transform: scale(1, -1);
+}
+
+.keyframes-graph.opacity .keyframes-graph-path path {
+  fill: #df00a988;
+  stroke: #df00a9;
+}
+
+.keyframes-graph.transform .keyframes-graph-path path {
+  fill: #ea800088;
+  stroke: #ea8000;
+}
+
+.keyframes-graph-path .color-path path {
+  stroke: none;
+}
+
+.keyframes-graph .keyframes-graph-path .hint path {
+  fill: none;
+  stroke-linecap: round;
+  stroke-opacity: 0;
+}
+
+.keyframes-graph-path .hint path:hover {
+  stroke-opacity: 1;
+}
+
+.keyframes-graph-path .hint rect {
+  fill-opacity: 0.1;
+  stroke: #00b0bd;
+  stroke-opacity: 0;
+  vector-effect: non-scaling-stroke;
+}
+
+.keyframes-graph-path .hint rect:hover {
+  stroke-opacity: 1;
+}
+
+/* Keyframe Marker List */
+.keyframe-marker-list {
+  pointer-events: none;
+  position: absolute;
+  height: 100%;
+  list-style-type: none;
+  top: 0%;
+  width: 100%;
+}
+
+.keyframe-marker-item {
+  box-shadow: 0 0 0 1px var(--keyframe-marker-shadow-color);
+  border-radius: 100%;
+  pointer-events: auto;
+  position: absolute;
+  top: 50%;
+  height: 10px;
+  transform: translate(-5px, -3px);
+  width: 10px;
+}
+
+.animated-property-list-container.cssanimation .keyframe-marker-item {
+  background-color: var(--fill-color-cssanimation);
+}
+
+.animated-property-list-container.csstransition .keyframe-marker-item {
+  background-color: var(--fill-color-csstransition);
+}
+
+.animated-property-list-container.scriptanimation .keyframe-marker-item {
+  background-color: var(--fill-color-scriptanimation);
+}
+
 /* No Animation Panel */
 .animation-error-message {
   overflow: auto;
 }
 
 .animation-error-message > p {
   white-space: pre;
 }
--- a/devtools/client/webconsole/new-console-output/components/message-types/PageError.js
+++ b/devtools/client/webconsole/new-console-output/components/message-types/PageError.js
@@ -24,27 +24,27 @@ PageError.defaultProps = {
   open: false,
 };
 
 function PageError(props) {
   const {
     dispatch,
     message,
     open,
+    repeat,
     serviceContainer,
     timestampsVisible,
   } = props;
   const {
     id: messageId,
     indent,
     source,
     type,
     level,
     messageText,
-    repeat,
     stacktrace,
     frame,
     exceptionDocURL,
     timeStamp,
     notes,
   } = message;
 
   let messageBody;
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser.ini
@@ -6,17 +6,16 @@ support-files =
   code_bundle_invalidmap.js.map
   code_bundle_nosource.js
   code_bundle_nosource.js.map
   head.js
   sjs_slow-response-test-server.sjs
   source-mapped.css
   source-mapped.css.map
   source-mapped.scss
-  test_bug_1247459_violation.html
   test_bug_770099_violation.html
   test_bug_770099_violation.html^headers^
   test_console_csp_ignore_reflected_xss_message.html
   test_console_csp_ignore_reflected_xss_message.html^headers^
   test_hpkp-invalid-headers.sjs
   test_hsts-invalid-headers.sjs
   test-autocomplete-in-stackframe.html
   test-batching.html
@@ -39,16 +38,17 @@ support-files =
   test-bug-782653-css-errors-2.css
   test-bug-782653-css-errors.html
   test-bug-837351-security-errors.html
   test-bug-859170-longstring-hang.html
   test-bug-952277-highlight-nodes-in-vview.html
   test-cd-iframe-child.html
   test-cd-iframe-parent.html
   test-console-api-iframe.html
+  test-csp-violation.html
   test-cspro.html
   test-cspro.html^headers^
   test-iframe-child.html
   test-iframe-parent.html
   test-certificate-messages.html
   test-click-function-to-source.html
   test-click-function-to-source.js
   test-closure-optimized-out.html
@@ -260,16 +260,17 @@ subsuite = clipboard
 skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
 [browser_webconsole_context_menu_copy_object.js]
 subsuite = clipboard
 [browser_webconsole_context_menu_object_in_sidebar.js]
 [browser_webconsole_context_menu_open_url.js]
 [browser_webconsole_context_menu_store_as_global.js]
 [browser_webconsole_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
+[browser_webconsole_csp_violation.js]
 [browser_webconsole_cspro.js]
 [browser_webconsole_document_focus.js]
 [browser_webconsole_duplicate_errors.js]
 [browser_webconsole_errors_after_page_reload.js]
 [browser_webconsole_eval_in_debugger_stackframe.js]
 [browser_webconsole_eval_in_debugger_stackframe2.js]
 [browser_webconsole_execution_scope.js]
 [browser_webconsole_external_script_errors.js]
@@ -339,29 +340,23 @@ subsuite = clipboard
 [browser_webconsole_show_subresource_security_errors.js]
 [browser_webconsole_shows_reqs_in_netmonitor.js]
 [browser_webconsole_sourcemap_css.js]
 [browser_webconsole_sourcemap_error.js]
 [browser_webconsole_sourcemap_invalid.js]
 [browser_webconsole_sourcemap_nosource.js]
 [browser_webconsole_split.js]
 [browser_webconsole_split_escape_key.js]
-skip-if = true #	Bug 1405647
 [browser_webconsole_split_focus.js]
-skip-if = true #	Bug 1405648
 [browser_webconsole_split_persist.js]
-skip-if = true #	Bug 1405649
 [browser_webconsole_stacktrace_location_debugger_link.js]
 [browser_webconsole_stacktrace_location_scratchpad_link.js]
 [browser_webconsole_strict_mode_errors.js]
 [browser_webconsole_string.js]
 [browser_webconsole_time_methods.js]
 skip-if = true #	Bug 1404877
 [browser_webconsole_timestamps.js]
 [browser_webconsole_trackingprotection_errors.js]
 tags = trackingprotection
 [browser_webconsole_view_source.js]
-[browser_webconsole_violation.js]
-skip-if = true #	Bug 1405245
-# old console skip-if = e10s && (os == 'win') # Bug 1264955
 [browser_webconsole_visibility_messages.js]
 [browser_webconsole_warn_about_replaced_api.js]
 [browser_webconsole_websocket.js]
rename from devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_violation.js
rename to devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_csp_violation.js
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_violation.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_csp_violation.js
@@ -4,37 +4,24 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the Web Console CSP messages for two META policies
 // are correctly displayed. See Bug 1247459.
 
 "use strict";
 
 const TEST_URI = "data:text/html;charset=utf8,Web Console CSP violation test";
-const TEST_VIOLATION = "https://example.com/browser/devtools/client/" +
-                       "webconsole/test/test_bug_1247459_violation.html";
+const TEST_VIOLATION = "https://example.com/browser/devtools/client/webconsole/" +
+                       "new-console-output/test/mochitest/test-csp-violation.html";
 const CSP_VIOLATION_MSG = "Content Security Policy: The page\u2019s settings " +
                           "blocked the loading of a resource at " +
-                          "http://some.example.com/test.png (\u201cimg-src " +
-                          "https://example.com\u201d).";
+                          "http://some.example.com/test.png (\u201cimg-src\u201d).";
 
-add_task(function* () {
-  let { browser } = yield loadTab(TEST_URI);
-
-  let hud = yield openConsole();
-
+add_task(async function () {
+  let hud = await openNewTabAndConsole(TEST_URI);
   hud.jsterm.clearOutput();
 
-  let loaded = loadBrowser(browser);
-  BrowserTestUtils.loadURI(browser, TEST_VIOLATION);
-  yield loaded;
+  let onRepeatedMessage = waitForRepeatedMessage(hud, CSP_VIOLATION_MSG, 2);
+  await loadDocument(TEST_VIOLATION);
+  await onRepeatedMessage;
 
-  yield waitForMessages({
-    webconsole: hud,
-    messages: [
-      {
-        name: "CSP policy URI warning displayed successfully",
-        text: CSP_VIOLATION_MSG,
-        repeats: 2
-      }
-    ]
-  });
+  ok(true, "Received expected messages");
 });
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_escape_key.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_escape_key.js
@@ -1,158 +1,49 @@
 /* -*- 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";
-
- function test() {
-   info("Test various cases where the escape key should hide the split console.");
+"use strict";
 
-   let toolbox;
-   let hud;
-   let jsterm;
-   let hudMessages;
-   let variablesView;
-
-   Task.spawn(runner).then(finish);
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting";
 
-   function* runner() {
-     let {tab} = yield loadTab("data:text/html;charset=utf-8,<p>Web Console " +
-                              "test for splitting");
-     let target = TargetFactory.forTab(tab);
-     toolbox = yield gDevTools.showToolbox(target, "inspector");
-
-     yield testCreateSplitConsoleAfterEscape();
-
-     yield showAutoCompletePopoup();
+add_task(async function () {
+  info("Test various cases where the escape key should hide the split console.");
 
-     yield testHideAutoCompletePopupAfterEscape();
-
-     yield executeJS();
-     yield clickMessageAndShowVariablesView();
-     jsterm.focus();
-
-     yield testHideVariablesViewAfterEscape();
-
-     yield clickMessageAndShowVariablesView();
-     yield startPropertyEditor();
+  let toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
 
-     yield testCancelPropertyEditorAfterEscape();
-     yield testHideVariablesViewAfterEscape();
-     yield testHideSplitConsoleAfterEscape();
-   }
-
-   function testCreateSplitConsoleAfterEscape() {
-     let result = toolbox.once("webconsole-ready", () => {
-       hud = toolbox.getPanel("webconsole").hud;
-       jsterm = hud.jsterm;
-       ok(toolbox.splitConsole, "Split console is created.");
-     });
-
-     let contentWindow = toolbox.win;
-     contentWindow.focus();
-     EventUtils.sendKey("ESCAPE", contentWindow);
-
-     return result;
-   }
+  info("Send ESCAPE key and wait for the split console to be displayed");
 
-   function testHideSplitConsoleAfterEscape() {
-     let result = toolbox.once("split-console", () => {
-       ok(!toolbox.splitConsole, "Split console is hidden.");
-     });
-     EventUtils.sendKey("ESCAPE", toolbox.win);
-
-     return result;
-   }
+  let onSplitConsoleReady = toolbox.once("webconsole-ready");
+  toolbox.win.focus();
+  EventUtils.sendKey("ESCAPE", toolbox.win);
+  await onSplitConsoleReady;
 
-   function testHideVariablesViewAfterEscape() {
-     let result = jsterm.once("sidebar-closed", () => {
-       ok(!hud.ui.jsterm.sidebar,
-        "Variables view is hidden.");
-       ok(toolbox.splitConsole,
-        "Split console is open after hiding the variables view.");
-     });
-     EventUtils.sendKey("ESCAPE", toolbox.win);
-
-     return result;
-   }
+  let hud = toolbox.getPanel("webconsole").hud;
+  let jsterm = hud.jsterm;
+  ok(toolbox.splitConsole, "Split console is created.");
 
-   function testHideAutoCompletePopupAfterEscape() {
-     let deferred = defer();
-     let popup = jsterm.autocompletePopup;
-
-     popup.once("popup-closed", () => {
-       ok(!popup.isOpen,
-        "Auto complete popup is hidden.");
-       ok(toolbox.splitConsole,
-        "Split console is open after hiding the autocomplete popup.");
-
-       deferred.resolve();
-     });
-
-     EventUtils.sendKey("ESCAPE", toolbox.win);
-
-     return deferred.promise;
-   }
+  info("Wait for the autocomplete to show suggestions for `document.location.`");
+  let popup = jsterm.autocompletePopup;
+  let onPopupShown = popup.once("popup-opened");
+  jsterm.focus();
+  jsterm.setInputValue("document.location.");
+  EventUtils.sendKey("TAB", hud.iframeWindow);
+  await onPopupShown;
 
-   function testCancelPropertyEditorAfterEscape() {
-     EventUtils.sendKey("ESCAPE", variablesView.window);
-     ok(hud.ui.jsterm.sidebar,
-      "Variables view is open after canceling property editor.");
-     ok(toolbox.splitConsole,
-      "Split console is open after editing.");
-   }
-
-   function* executeJS() {
-     jsterm.execute("var foo = { bar: \"baz\" }; foo;");
-     hudMessages = yield waitForMessages({
-       webconsole: hud,
-       messages: [{
-         text: "Object { bar: \"baz\" }",
-         category: CATEGORY_OUTPUT,
-         objects: true
-       }],
-     });
-   }
+  info("Send ESCAPE key and check that it only hides the autocomplete suggestions");
 
-   function clickMessageAndShowVariablesView() {
-     let result = jsterm.once("variablesview-fetched", (event, vview) => {
-       variablesView = vview;
-     });
-
-     let clickable = hudMessages[0].clickableElements[0];
-     EventUtils.synthesizeMouse(clickable, 2, 2, {}, hud.iframeWindow);
+  let onPopupClosed = popup.once("popup-closed");
+  EventUtils.sendKey("ESCAPE", toolbox.win);
+  await onPopupClosed;
 
-     return result;
-   }
-
-   function* startPropertyEditor() {
-     let results = yield findVariableViewProperties(variablesView, [
-      {name: "bar", value: "baz"}
-     ], {webconsole: hud});
-     results[0].matchedProp.focus();
-     EventUtils.synthesizeKey("VK_RETURN", variablesView.window);
-   }
+  ok(!popup.isOpen, "Auto complete popup is hidden.");
+  ok(toolbox.splitConsole, "Split console is open after hiding the autocomplete popup.");
 
-   function showAutoCompletePopoup() {
-     let onPopupShown = jsterm.autocompletePopup.once("popup-opened");
-
-     jsterm.focus();
-     jsterm.setInputValue("document.location.");
-     EventUtils.sendKey("TAB", hud.iframeWindow);
-
-     return onPopupShown;
-   }
+  info("Send ESCAPE key again and check that now closes the splitconsole");
+  let onSplitConsoleEvent = toolbox.once("split-console");
+  EventUtils.sendKey("ESCAPE", toolbox.win);
+  await onSplitConsoleEvent;
 
-   function finish() {
-     toolbox.destroy().then(() => {
-       toolbox = null;
-       hud = null;
-       jsterm = null;
-       hudMessages = null;
-       variablesView = null;
-
-       finishTest();
-     });
-   }
- }
+  ok(!toolbox.splitConsole, "Split console is hidden.");
+});
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_focus.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_focus.js
@@ -1,64 +1,44 @@
 /* -*- 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";
-
- function test() {
-  info("Test that the split console state is persisted");
+"use strict";
 
-  let toolbox;
-  let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for " +
-                 "splitting</p>";
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
 
-  Task.spawn(runner).then(finish);
+add_task(async function () {
+  info("Test that the split console input is focused and restores the focus properly.");
 
-  function* runner() {
-    info("Opening a tab while there is no user setting on split console pref");
-    let {tab} = yield loadTab(TEST_URI);
-    let target = TargetFactory.forTab(tab);
-    toolbox = yield gDevTools.showToolbox(target, "inspector");
-
-    ok(!toolbox.splitConsole, "Split console is hidden by default");
+  let toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
+  ok(!toolbox.splitConsole, "Split console is hidden by default");
 
-    info("Focusing the search box before opening the split console");
-    let inspector = toolbox.getPanel("inspector");
-    inspector.searchBox.focus();
+  info("Focusing the search box before opening the split console");
+  let inspector = toolbox.getPanel("inspector");
+  inspector.searchBox.focus();
 
-    let activeElement = getActiveElement(inspector.panelDoc);
-    is(activeElement, inspector.searchBox, "Search box is focused");
+  let activeElement = getActiveElement(inspector.panelDoc);
+  is(activeElement, inspector.searchBox, "Search box is focused");
 
-    yield toolbox.openSplitConsole();
-
-    ok(toolbox.splitConsole, "Split console is now visible");
+  await toolbox.openSplitConsole();
 
-    // Use the binding element since jsterm.inputNode is a XUL textarea element.
-    activeElement = getActiveElement(toolbox.doc);
-    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
-    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
-    is(activeElement, inputNode, "Split console input is focused by default");
+  ok(toolbox.splitConsole, "Split console is now visible");
+
+  activeElement = getActiveElement(toolbox.doc);
+  let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+  is(activeElement, inputNode, "Split console input is focused by default");
+
+  await toolbox.closeSplitConsole();
 
-    yield toolbox.closeSplitConsole();
+  info("Making sure that the search box is refocused after closing the split console");
+  activeElement = getActiveElement(inspector.panelDoc);
+  is(activeElement, inspector.searchBox, "Search box is focused");
+});
 
-    info("Making sure that the search box is refocused after closing the " +
-         "split console");
-    activeElement = getActiveElement(inspector.panelDoc);
-    is(activeElement, inspector.searchBox, "Search box is focused");
-
-    yield toolbox.destroy();
+function getActiveElement(doc) {
+  let activeElement = doc.activeElement;
+  while (activeElement && activeElement.contentDocument) {
+    activeElement = activeElement.contentDocument.activeElement;
   }
-
-  function getActiveElement(doc) {
-    let activeElement = doc.activeElement;
-    while (activeElement && activeElement.contentDocument) {
-      activeElement = activeElement.contentDocument.activeElement;
-    }
-    return activeElement;
-  }
-
-  function finish() {
-    toolbox = TEST_URI = null;
-    finishTest();
-  }
+  return activeElement;
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_persist.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/browser_webconsole_split_persist.js
@@ -1,117 +1,94 @@
 /* -*- 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";
-
- function test() {
-  info("Test that the split console state is persisted");
+"use strict";
 
-  let toolbox;
-  let TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for " +
-                 "splitting</p>";
+// Test that the split console state is persisted.
 
-  Task.spawn(runner).then(finish);
+const TEST_URI = "data:text/html;charset=utf-8,<p>Web Console test for splitting</p>";
 
-  function* runner() {
-    info("Opening a tab while there is no user setting on split console pref");
-    let {tab} = yield loadTab(TEST_URI);
-    let target = TargetFactory.forTab(tab);
-    toolbox = yield gDevTools.showToolbox(target, "inspector");
+add_task(async function () {
+  info("Opening a tab while there is no user setting on split console pref");
+  let toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
+  ok(!toolbox.splitConsole, "Split console is hidden by default");
+  ok(!isCommandButtonChecked(toolbox), "Split console button is unchecked by default.");
 
-    ok(!toolbox.splitConsole, "Split console is hidden by default.");
-    ok(!isCommandButtonChecked(), "Split console button is unchecked by " +
-                                  "default.");
-    yield toggleSplitConsoleWithEscape();
-    ok(toolbox.splitConsole, "Split console is now visible.");
-    ok(isCommandButtonChecked(), "Split console button is now checked.");
-    ok(getVisiblePrefValue(), "Visibility pref is true");
+  await toggleSplitConsoleWithEscape(toolbox);
+  ok(toolbox.splitConsole, "Split console is now visible.");
+  ok(isCommandButtonChecked(toolbox), "Split console button is now checked.");
+  ok(getVisiblePrefValue(), "Visibility pref is true");
+
+  is(getHeightPrefValue(), toolbox.webconsolePanel.height,
+     "Panel height matches the pref");
+  toolbox.webconsolePanel.height = 200;
 
-    is(getHeightPrefValue(), toolbox.webconsolePanel.height,
-       "Panel height matches the pref");
-    toolbox.webconsolePanel.height = 200;
-
-    yield toolbox.destroy();
+  await toolbox.destroy();
 
-    info("Opening a tab while there is a true user setting on split console " +
-         "pref");
-    ({tab} = yield loadTab(TEST_URI));
-    target = TargetFactory.forTab(tab);
-    toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("Opening a tab while there is a true user setting on split console pref");
+  toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
+  ok(toolbox.splitConsole, "Split console is visible by default.");
+
+  ok(isCommandButtonChecked(toolbox), "Split console button is checked by default.");
+  is(getHeightPrefValue(), 200, "Height is set based on panel height after closing");
 
-    ok(toolbox.splitConsole, "Split console is visible by default.");
-    ok(isCommandButtonChecked(), "Split console button is checked by default.");
-    is(getHeightPrefValue(), 200, "Height is set based on panel height after " +
-                                  "closing");
+  let activeElement = getActiveElement(toolbox.doc);
+  let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
+  is(activeElement, inputNode, "Split console input is focused by default");
 
-    // Use the binding element since jsterm.inputNode is a XUL textarea element.
-    let activeElement = getActiveElement(toolbox.doc);
-    activeElement = activeElement.ownerDocument.getBindingParent(activeElement);
-    let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode;
-    is(activeElement, inputNode, "Split console input is focused by default");
+  toolbox.webconsolePanel.height = 1;
+  ok(toolbox.webconsolePanel.clientHeight > 1,
+     "The actual height of the console is bound with a min height");
 
-    toolbox.webconsolePanel.height = 1;
-    ok(toolbox.webconsolePanel.clientHeight > 1,
-       "The actual height of the console is bound with a min height");
-
-    toolbox.webconsolePanel.height = 10000;
-    ok(toolbox.webconsolePanel.clientHeight < 10000,
-       "The actual height of the console is bound with a max height");
+  toolbox.webconsolePanel.height = 10000;
+  ok(toolbox.webconsolePanel.clientHeight < 10000,
+     "The actual height of the console is bound with a max height");
 
-    yield toggleSplitConsoleWithEscape();
-    ok(!toolbox.splitConsole, "Split console is now hidden.");
-    ok(!isCommandButtonChecked(), "Split console button is now unchecked.");
-    ok(!getVisiblePrefValue(), "Visibility pref is false");
+  await toggleSplitConsoleWithEscape(toolbox);
+  ok(!toolbox.splitConsole, "Split console is now hidden.");
+  ok(!isCommandButtonChecked(toolbox), "Split console button is now unchecked.");
+  ok(!getVisiblePrefValue(), "Visibility pref is false");
 
-    yield toolbox.destroy();
+  await toolbox.destroy();
 
-    is(getHeightPrefValue(), 10000,
-       "Height is set based on panel height after closing");
+  is(getHeightPrefValue(), 10000, "Height is set based on panel height after closing");
 
-    info("Opening a tab while there is a false user setting on split " +
-         "console pref");
-    ({tab} = yield loadTab(TEST_URI));
-    target = TargetFactory.forTab(tab);
-    toolbox = yield gDevTools.showToolbox(target, "inspector");
+  info("Opening a tab while there is a false user setting on split " +
+       "console pref");
+  toolbox = await openNewTabAndToolbox(TEST_URI, "inspector");
 
-    ok(!toolbox.splitConsole, "Split console is hidden by default.");
-    ok(!getVisiblePrefValue(), "Visibility pref is false");
+  ok(!toolbox.splitConsole, "Split console is hidden by default.");
+  ok(!getVisiblePrefValue(), "Visibility pref is false");
 
-    yield toolbox.destroy();
-  }
+  await toolbox.destroy();
+});
 
-  function getActiveElement(doc) {
-    let activeElement = doc.activeElement;
-    while (activeElement && activeElement.contentDocument) {
-      activeElement = activeElement.contentDocument.activeElement;
-    }
-    return activeElement;
+function getActiveElement(doc) {
+  let activeElement = doc.activeElement;
+  while (activeElement && activeElement.contentDocument) {
+    activeElement = activeElement.contentDocument.activeElement;
   }
+  return activeElement;
+}
 
-  function getVisiblePrefValue() {
-    return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
-  }
-
-  function getHeightPrefValue() {
-    return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
-  }
+function getVisiblePrefValue() {
+  return Services.prefs.getBoolPref("devtools.toolbox.splitconsoleEnabled");
+}
 
-  function isCommandButtonChecked() {
-    return toolbox.doc.querySelector("#command-button-splitconsole")
-      .classList.contains("checked");
-  }
+function getHeightPrefValue() {
+  return Services.prefs.getIntPref("devtools.toolbox.splitconsoleHeight");
+}
 
-  function toggleSplitConsoleWithEscape() {
-    let onceSplitConsole = toolbox.once("split-console");
-    let contentWindow = toolbox.win;
-    contentWindow.focus();
-    EventUtils.sendKey("ESCAPE", contentWindow);
-    return onceSplitConsole;
-  }
+function isCommandButtonChecked(toolbox) {
+  return toolbox.doc.querySelector("#command-button-splitconsole")
+    .classList.contains("checked");
+}
 
-  function finish() {
-    toolbox = TEST_URI = null;
-    finishTest();
-  }
+function toggleSplitConsoleWithEscape(toolbox) {
+  let onceSplitConsole = toolbox.once("split-console");
+  let toolboxWindow = toolbox.win;
+  toolboxWindow.focus();
+  EventUtils.sendKey("ESCAPE", toolboxWindow);
+  return onceSplitConsole;
 }
--- a/devtools/client/webconsole/new-console-output/test/mochitest/head.js
+++ b/devtools/client/webconsole/new-console-output/test/mochitest/head.js
@@ -134,16 +134,41 @@ function waitForMessages({ hud, messages
             return;
           }
         }
       });
   });
 }
 
 /**
+ * Wait for a message with the provided text and showing the provided repeat count.
+ *
+ * @param {Object} hud : the webconsole
+ * @param {String} text : text included in .message-body
+ * @param {Number} repeat : expected repeat count in .message-repeats
+ */
+function waitForRepeatedMessage(hud, text, repeat) {
+  return waitFor(() => {
+    // Wait for a message matching the provided text.
+    let node = findMessage(hud, text);
+    if (!node) {
+      return false;
+    }
+
+    // Check if there is a repeat node with the expected count.
+    let repeatNode = node.querySelector(".message-repeats");
+    if (repeatNode && parseInt(repeatNode.textContent, 10) === repeat) {
+      return node;
+    }
+
+    return false;
+  });
+}
+
+/**
  * Wait for a single message in the web console output, resolving once it is received.
  *
  * @param {Object} hud : the webconsole
  * @param {String} text : text included in .message-body
  */
 async function waitForMessage(hud, text) {
   const messages = await waitForMessages({hud, messages: [{text}]});
   return messages[0];
@@ -172,16 +197,17 @@ async function waitFor(condition, messag
  * Find a message in the output.
  *
  * @param object hud
  *        The web console.
  * @param string text
  *        A substring that can be found in the message.
  * @param selector [optional]
  *        The selector to use in finding the message.
+ * @return {Node} the node corresponding the found message
  */
 function findMessage(hud, text, selector = ".message") {
   const elements = findMessages(hud, text, selector);
   return elements.pop();
 }
 
 /**
  * Find multiple messages in the output.
rename from devtools/client/webconsole/new-console-output/test/mochitest/test_bug_1247459_violation.html
rename to devtools/client/webconsole/new-console-output/test/mochitest/test-csp-violation.html
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1577,16 +1577,17 @@ nsDocument::nsDocument(const char* aCont
   , mNeedsReleaseAfterStackRefCntRelease(false)
   , mMaybeServiceWorkerControlled(false)
 #ifdef DEBUG
   , mWillReparent(false)
 #endif
   , mDOMLoadingSet(false)
   , mDOMInteractiveSet(false)
   , mDOMCompleteSet(false)
+  , mAutoFocusFired(false)
 {
   SetContentTypeInternal(nsDependentCString(aContentType));
 
   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
 
   // Start out mLastStyleSheetSet as null, per spec
   SetDOMStringToNull(mLastStyleSheetSet);
 
@@ -9439,16 +9440,130 @@ nsDocument::GetTemplateContentsOwner()
     // |doc| is the template contents owner of template elements created
     // by |doc|.
     doc->mTemplateContentsOwner = doc;
   }
 
   return mTemplateContentsOwner;
 }
 
+static already_AddRefed<nsPIDOMWindowOuter>
+FindTopWindowForElement(Element* element)
+{
+  nsIDocument* document = element->OwnerDoc();
+  if (!document) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
+  if (!window) {
+    return nullptr;
+  }
+
+  // Trying to find the top window (equivalent to window.top).
+  if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetTop()) {
+    window = top.forget();
+  }
+  return window.forget();
+}
+
+/**
+ * nsAutoFocusEvent is used to dispatch a focus event for an
+ * nsGenericHTMLFormElement with the autofocus attribute enabled.
+ */
+class nsAutoFocusEvent : public Runnable
+{
+public:
+  explicit nsAutoFocusEvent(already_AddRefed<Element>&& aElement,
+                            already_AddRefed<nsPIDOMWindowOuter>&& aTopWindow)
+    : mozilla::Runnable("nsAutoFocusEvent")
+    , mElement(aElement)
+    , mTopWindow(aTopWindow)
+  {
+  }
+
+  NS_IMETHOD Run() override
+  {
+    nsCOMPtr<nsPIDOMWindowOuter> currentTopWindow =
+      FindTopWindowForElement(mElement);
+    if (currentTopWindow != mTopWindow) {
+      // The element's top window changed from when the event was queued.
+      // Don't take away focus from an unrelated window.
+      return NS_OK;
+    }
+
+    // Don't steal focus from the user.
+    if (mTopWindow->GetFocusedNode()) {
+      return NS_OK;
+    }
+
+    mozilla::ErrorResult rv;
+    mElement->Focus(rv);
+    return rv.StealNSResult();
+  }
+private:
+  nsCOMPtr<Element> mElement;
+  nsCOMPtr<nsPIDOMWindowOuter> mTopWindow;
+};
+
+void
+nsDocument::SetAutoFocusElement(Element* aAutoFocusElement)
+{
+  if (mAutoFocusFired) {
+    // Too late.
+    return;
+  }
+
+  if (mAutoFocusElement) {
+    // The spec disallows multiple autofocus elements, so we consider only the
+    // first one to preserve the old behavior.
+    return;
+  }
+
+  mAutoFocusElement = do_GetWeakReference(aAutoFocusElement);
+  TriggerAutoFocus();
+}
+
+void
+nsDocument::TriggerAutoFocus()
+{
+  if (mAutoFocusFired) {
+    return;
+  }
+
+  if (!mPresShell || !mPresShell->DidInitialize()) {
+    // Delay autofocus until frames are constructed so that we don't thrash
+    // style and layout calculations.
+    return;
+  }
+
+  nsCOMPtr<Element> autoFocusElement = do_QueryReferent(mAutoFocusElement);
+  if (autoFocusElement && autoFocusElement->OwnerDoc() == this) {
+    mAutoFocusFired = true;
+
+    nsCOMPtr<nsPIDOMWindowOuter> topWindow =
+      FindTopWindowForElement(autoFocusElement);
+    if (!topWindow) {
+      return;
+    }
+
+    // NOTE: This may be removed in the future since the spec technically
+    // allows autofocus after load.
+    nsCOMPtr<nsIDocument> topDoc = topWindow->GetExtantDoc();
+    if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
+      return;
+    }
+
+    nsCOMPtr<nsIRunnable> event =
+      new nsAutoFocusEvent(autoFocusElement.forget(), topWindow.forget());
+    nsresult rv = NS_DispatchToCurrentThread(event.forget());
+    NS_ENSURE_SUCCESS_VOID(rv);
+  }
+}
+
 void
 nsDocument::SetScrollToRef(nsIURI *aDocumentURI)
 {
   if (!aDocumentURI) {
     return;
   }
 
   nsAutoCString ref;
--- a/dom/base/nsDocument.h
+++ b/dom/base/nsDocument.h
@@ -799,16 +799,19 @@ public:
   virtual nsresult LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
                                        RefPtr<mozilla::StyleSheet>* aSheet) override;
 
   virtual nsISupports* GetCurrentContentSink() override;
 
   // Only BlockOnload should call this!
   void AsyncBlockOnload();
 
+  virtual void SetAutoFocusElement(Element* aAutoFocusElement) override;
+  virtual void TriggerAutoFocus() override;
+
   virtual void SetScrollToRef(nsIURI *aDocumentURI) override;
   virtual void ScrollToRef() override;
   virtual void ResetScrolledToRefAlready() override;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) override;
 
   virtual Element* LookupImageElement(const nsAString& aElementId) override;
   virtual void MozSetImageElement(const nsAString& aImageElementId,
                                   Element* aElement) override;
@@ -1301,16 +1304,18 @@ private:
 
   // Set if we've found a URL for the current picture
   nsString mPreloadPictureFoundSource;
 
   RefPtr<mozilla::dom::DOMImplementation> mDOMImplementation;
 
   RefPtr<nsContentList> mImageMaps;
 
+  nsWeakPtr mAutoFocusElement;
+
   nsCString mScrollToRef;
   uint8_t mScrolledToRefAlready : 1;
   uint8_t mChangeScrollPosWhenScrollingToRef : 1;
 
   // Tracking for plugins in the document.
   nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins;
 
   RefPtr<mozilla::dom::DocumentTimeline> mDocumentTimeline;
@@ -1351,16 +1356,17 @@ public:
   bool mWillReparent;
 #endif
 
 private:
   void RecordNavigationTiming(ReadyState aReadyState);
   bool mDOMLoadingSet : 1;
   bool mDOMInteractiveSet : 1;
   bool mDOMCompleteSet : 1;
+  bool mAutoFocusFired : 1;
 };
 
 class nsDocumentOnStack
 {
 public:
   explicit nsDocumentOnStack(nsDocument* aDoc) : mDoc(aDoc)
   {
     mDoc->IncreaseStackRefCnt();
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -1598,17 +1598,17 @@ nsFocusManager::CheckIfFocusable(nsICont
   nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
   // can't focus elements that are not in documents
   if (!doc) {
     LOGCONTENT("Cannot focus %s because content not in document", aContent)
     return nullptr;
   }
 
   // Make sure that our frames are up to date while ensuring the presshell is
-  // also initialized in case we come from an autofocus event.
+  // also initialized in case we come from a script calling focus() early.
   mEventHandlingNeedsFlush = false;
   doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
 
   nsIPresShell *shell = doc->GetShell();
   if (!shell)
     return nullptr;
 
   // the root content can always be focused,
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2632,16 +2632,19 @@ public:
    */
   mozilla::EventStates GetDocumentState() const
   {
     return mDocumentState;
   }
 
   virtual nsISupports* GetCurrentContentSink() = 0;
 
+  virtual void SetAutoFocusElement(Element* aAutoFocusElement) = 0;
+  virtual void TriggerAutoFocus() = 0;
+
   virtual void SetScrollToRef(nsIURI *aDocumentURI) = 0;
   virtual void ScrollToRef() = 0;
   virtual void ResetScrolledToRefAlready() = 0;
   virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue) = 0;
 
   using mozilla::dom::DocumentOrShadowRoot::GetElementById;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagName;
   using mozilla::dom::DocumentOrShadowRoot::GetElementsByTagNameNS;
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -106,74 +106,16 @@
 #include "mozilla/StyleSetHandleInlines.h"
 #include "ReferrerPolicy.h"
 #include "mozilla/dom/HTMLLabelElement.h"
 #include "mozilla/dom/HTMLInputElement.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-/**
- * nsAutoFocusEvent is used to dispatch a focus event when a
- * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute
- * enabled.
- */
-class nsAutoFocusEvent : public Runnable
-{
-public:
-  explicit nsAutoFocusEvent(nsGenericHTMLFormElement* aElement)
-    : mozilla::Runnable("nsAutoFocusEvent")
-    , mElement(aElement)
-  {
-  }
-
-  NS_IMETHOD Run() override {
-    nsFocusManager* fm = nsFocusManager::GetFocusManager();
-    if (!fm) {
-      return NS_ERROR_NULL_POINTER;
-    }
-
-    nsIDocument* document = mElement->OwnerDoc();
-
-    nsPIDOMWindowOuter* window = document->GetWindow();
-    if (!window) {
-      return NS_OK;
-    }
-
-    // Trying to found the top window (equivalent to window.top).
-    if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetTop()) {
-      window = top;
-    }
-
-    if (window->GetFocusedNode()) {
-      return NS_OK;
-    }
-
-    nsCOMPtr<nsIDocument> topDoc = window->GetExtantDoc();
-    if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
-      return NS_OK;
-    }
-
-    // If something is focused in the same document, ignore autofocus.
-    if (!fm->GetFocusedContent() ||
-        fm->GetFocusedContent()->OwnerDoc() != document) {
-      mozilla::ErrorResult rv;
-      mElement->Focus(rv);
-      return rv.StealNSResult();
-    }
-
-    return NS_OK;
-  }
-private:
-  // NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement
-  // because AddRef/Release are ambiguous with nsGenericHTMLFormElement
-  // and Focus() is declared (and defined) in nsGenericHTMLElement class.
-  RefPtr<nsGenericHTMLElement> mElement;
-};
-
 NS_IMPL_ADDREF_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
 NS_IMPL_RELEASE_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
 
 NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
   NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)
 
@@ -1877,20 +1819,18 @@ nsGenericHTMLFormElement::BindToTree(nsI
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // An autofocus event has to be launched if the autofocus attribute is
   // specified and the element accept the autofocus attribute. In addition,
   // the document should not be already loaded and the "browser.autofocus"
   // preference should be 'true'.
   if (IsAutofocusable() && HasAttr(kNameSpaceID_None, nsGkAtoms::autofocus) &&
-      nsContentUtils::AutoFocusEnabled()) {
-    nsCOMPtr<nsIRunnable> event = new nsAutoFocusEvent(this);
-    rv = NS_DispatchToCurrentThread(event);
-    NS_ENSURE_SUCCESS(rv, rv);
+      nsContentUtils::AutoFocusEnabled() && aDocument) {
+    aDocument->SetAutoFocusElement(this);
   }
 
   // If @form is set, the element *has* to be in a document, otherwise it
   // wouldn't be possible to find an element with the corresponding id.
   // If @form isn't set, the element *has* to have a parent, otherwise it
   // wouldn't be possible to find a form ancestor.
   // We should not call UpdateFormOwner if none of these conditions are
   // fulfilled.
--- a/dom/xbl/nsXBLWindowKeyHandler.cpp
+++ b/dom/xbl/nsXBLWindowKeyHandler.cpp
@@ -560,19 +560,22 @@ nsXBLWindowKeyHandler::HandleEventOnCapt
 void
 nsXBLWindowKeyHandler::HandleEventOnCaptureInSystemEventGroup(
                          KeyboardEvent* aEvent)
 {
   WidgetKeyboardEvent* widgetEvent =
     aEvent->WidgetEventPtr()->AsKeyboardEvent();
 
   // If the event won't be sent to remote process, this listener needs to do
-  // nothing.
-  if (widgetEvent->mFlags.mOnlySystemGroupDispatchInContent ||
-      !widgetEvent->WillBeSentToRemoteProcess()) {
+  // nothing.  Note that even if mOnlySystemGroupDispatchInContent is true,
+  // we need to send the event to remote process and check reply event
+  // before matching it with registered shortcut keys because event listeners
+  // in the system event group may want to handle the event before registered
+  // shortcut key handlers.
+  if (!widgetEvent->WillBeSentToRemoteProcess()) {
     return;
   }
 
   if (!HasHandlerForEvent(aEvent)) {
     return;
   }
 
   // If this event wasn't marked as IsCrossProcessForwardingStopped,
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4509,24 +4509,24 @@ BinParse(JSContext* cx, unsigned argc, V
 
     if (args.length() < 1) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                                   "parse", "0", "s");
         return false;
     }
     if (!args[0].isObject()) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportErrorASCII(cx, "expected object (typed array) to parse, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected object (ArrayBuffer) to parse, got %s", typeName);
         return false;
     }
 
     RootedObject obj(cx, &args[0].toObject());
-    if (!JS_IsTypedArrayObject(obj)) {
+    if (!JS_IsArrayBufferObject(obj)) {
         const char* typeName = InformalValueTypeName(args[0]);
-        JS_ReportErrorASCII(cx, "expected typed array to parse, got %s", typeName);
+        JS_ReportErrorASCII(cx, "expected ArrayBuffer to parse, got %s", typeName);
         return false;
     }
 
     uint32_t buf_length = 0;
     bool buf_isSharedMemory = false;
     uint8_t* buf_data = nullptr;
     GetArrayBufferViewLengthAndData(obj, &buf_length, &buf_isSharedMemory, &buf_data);
     MOZ_ASSERT(buf_data);
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -1812,16 +1812,18 @@ PresShell::Initialize(nscoord aWidth, ns
     // (Do this in a script runner, since our caller might have a script
     // blocker on the stack.)
     nsContentUtils::AddScriptRunner(new XBLConstructorRunner(mDocument));
 
     // XBLConstructorRunner might destroy us.
     NS_ENSURE_STATE(!mHaveShutDown);
   }
 
+  mDocument->TriggerAutoFocus();
+
   NS_ASSERTION(rootFrame, "How did that happen?");
 
   // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit
   // set, but XBL processing could have caused a reflow which clears it.
   if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) {
     // Unset the DIRTY bits so that FrameNeedsReflow() will work right.
     rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
                                NS_FRAME_HAS_DIRTY_CHILDREN);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/712130-1-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
+<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
+<input type="text">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/712130-1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
+<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
+<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/712130-2-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/712130-2.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="stylesheet" href="nothing"><!-- Empty stylesheet to delay PresShell init -->
+<input type="text" autofocus="" onfocus="document.documentElement.removeAttribute('class')">
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1702,16 +1702,18 @@ skip-if(azureSkiaGL) == 670442-1.html 67
 != 691087-1.html 691087-1-ref.html
 == 691571-1.html 691571-1-ref.html
 fuzzy-if(skiaContent,1,200) == 696307-1.html 696307-1-ref.html
 fuzzy-if(skiaContent,1,550) == 696739-1.html 696739-1-ref.html
 needs-focus == 703186-1.html 703186-1-ref.html
 needs-focus == 703186-2.html 703186-2-ref.html
 needs-focus != 703186-1.html 703186-2.html
 == 711359-1.html 711359-1-ref.html
+fuzzy-if(skiaContent,1,3) needs-focus == 712130-1.html 712130-1-ref.html
+fuzzy-if(skiaContent,1,3) needs-focus == 712130-2.html 712130-2-ref.html
 == 712849-1.html 712849-1-ref.html
 == 713856-static.html  713856-ref.html
 == 713856-dynamic.html 713856-ref.html
 == 714519-1-as.html 714519-1-ref.html
 == 714519-1-q.html 714519-1-ref.html
 == 714519-2-as.html 714519-2-ref.html
 == 714519-2-q.html 714519-2-ref.html
 fuzzy-if(true,1,21) fuzzy-if(d2d,71,173) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html # bug 773482
--- a/memory/build/rb.h
+++ b/memory/build/rb.h
@@ -62,16 +62,17 @@
 // that treat the first argument specially.
 //
 // ***************************************************************************
 
 #ifndef RB_H_
 #define RB_H_
 
 #include "mozilla/Alignment.h"
+#include "mozilla/Assertions.h"
 #include "Utils.h"
 
 enum NodeColor
 {
   Black = 0,
   Red = 1,
 };
 
@@ -415,18 +416,18 @@ private:
           // instead swap it with its successor and delete the
           // successor. Record enough information to do the
           // swap later. rbp_r_xp is the aNode's parent.
           rbp_r_xp = rbp_r_p;
           rbp_r_cmp = Order::eGreater; // Note that deletion is incomplete.
         }
       }
       if (rbp_r_cmp == Order::eGreater) {
-        if (rbp_r_c->Right() && (!rbp_r_c->Right()->Left() ||
-                                 rbp_r_c->Right()->Left()->IsBlack())) {
+        if (!rbp_r_c->Right() || !rbp_r_c->Right()->Left() ||
+            rbp_r_c->Right()->Left()->IsBlack()) {
           rbp_r_t = rbp_r_c->Left();
           if (rbp_r_t->IsRed()) {
             // Standard transform.
             rbp_r_t = MoveRedRight(rbp_r_c);
           } else {
             // Root-specific transform.
             rbp_r_c->SetColor(NodeColor::Red);
             rbp_r_u = rbp_r_t->Left();
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -2730,19 +2730,21 @@ public class BrowserApp extends GeckoApp
                     keywordSearch = "";
                 } else {
                     keyword = url.substring(0, index);
                     keywordSearch = url.substring(index + 1);
                 }
 
                 final String keywordUrl = db.getUrlForKeyword(getContentResolver(), keyword);
 
-                // If there isn't a bookmark keyword, load the url. This may result in a query
-                // using the default search engine.
-                if (TextUtils.isEmpty(keywordUrl)) {
+                // If there isn't a bookmark keyword, or if there is no search query
+                // within the keywordURL, yet one is provided, load the url.
+                // This may result in a query using the default search engine.
+                if (TextUtils.isEmpty(keywordUrl) ||
+                        (!TextUtils.isEmpty(keywordSearch) && !StringUtils.queryExists(keywordUrl))) {
                     Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
                     Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.ACTIONBAR, "user");
                     return;
                 }
 
                 // Otherwise, construct a search query from the bookmark keyword.
                 // Replace lower case bookmark keywords with URLencoded search query or
                 // replace upper case bookmark keywords with un-encoded search query.
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/StringUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/StringUtils.java
@@ -66,16 +66,28 @@ public class StringUtils {
         if (dot > -1 || colon > -1) {
             return false;
         }
         // Otherwise, text is ambiguous, and we keep its status unchanged
         return wasSearchQuery;
     }
 
     /**
+     * Check for the existence of %s and %S in a given URL
+     *
+     * @return True if  %s or %S exists, False otherwise.
+     */
+    public static boolean queryExists(final String inputURL) {
+        if (inputURL == null) {
+            return false;
+        }
+        return inputURL.contains("%s") || inputURL.contains("%S");
+    }
+
+    /**
      * Strip the ref from a URL, if present
      *
      * @return The base URL, without the ref. The original String is returned if it has no ref,
      *         of if the input is malformed.
      */
     public static String stripRef(final String inputURL) {
         if (inputURL == null) {
             return null;
@@ -313,9 +325,9 @@ public class StringUtils {
      * @param textPaint the paint used to render the text
      * @return          the width of the specified substring in screen pixels
      */
     public static int getTextWidth(final String text, final int start, final int end, final Paint textPaint) {
         final Rect bounds = new Rect();
         textPaint.getTextBounds(text, start, end, bounds);
         return bounds.width();
     }
-}
\ No newline at end of file
+}
--- a/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/TestStringUtils.java
+++ b/mobile/android/geckoview/src/test/java/org/mozilla/gecko/util/TestStringUtils.java
@@ -135,16 +135,35 @@ public class TestStringUtils {
         // test ambiguous
         String ambiguous = "~!@#$%^&*()_+`34567890-=qwertyuiop[]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"ZXCVBNM<>?zxcvbnm,./";
         ambiguous = ambiguous.replace(" ","").replace(".","").replace(":","");
         assertTrue(StringUtils.isSearchQuery(ambiguous,true));
         assertFalse(StringUtils.isSearchQuery(ambiguous,false));
 
 
     }
+
+    @Test
+    public void testQueryExists(){
+        // test empty
+        assertFalse(StringUtils.queryExists(""));
+
+        // test single
+        assertFalse(StringUtils.queryExists("mozilla.org"));
+        assertFalse(StringUtils.queryExists("https://www.google.com/"));
+        assertTrue(StringUtils.queryExists("https://www.google.com/search?q=%s"));
+        assertTrue(StringUtils.queryExists("https://www.google.com/search?q=%S"));
+        assertTrue(StringUtils.queryExists("%s"));
+        assertTrue(StringUtils.queryExists("%S"));
+
+        //test double
+        assertTrue(StringUtils.queryExists("%s%S"));
+        assertTrue(StringUtils.queryExists("https://www.google.com/search?q=%s%S"));
+    }
+
     @Test
     public void testPathStartIndex(){
         // Tests without protocol
         assertTrue(StringUtils.pathStartIndex("mozilla.org") == -1);
         assertTrue(StringUtils.pathStartIndex("mozilla.org/en-US") == 11);
 
         // Tests with protocol
         assertTrue(StringUtils.pathStartIndex("https://mozilla.org") == -1);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1258,21 +1258,17 @@ pref("extensions.spellcheck.inline.max-m
 // belong in comm-central/editor/ui/composer.js
 
 pref("editor.use_custom_colors", false);
 pref("editor.singleLine.pasteNewlines",      2);
 pref("editor.use_css",                       false);
 pref("editor.css.default_length_unit",       "px");
 pref("editor.resizing.preserve_ratio",       true);
 pref("editor.positioning.offset",            0);
-#ifdef EARLY_BETA_OR_EARLIER
 pref("editor.use_div_for_default_newlines",  true);
-#else
-pref("editor.use_div_for_default_newlines",  false);
-#endif
 
 // Scripts & Windows prefs
 pref("dom.disable_beforeunload",            false);
 pref("dom.disable_window_flip",             false);
 pref("dom.disable_window_move_resize",      false);
 
 pref("dom.disable_window_open_feature.titlebar",    false);
 pref("dom.disable_window_open_feature.close",       false);
--- a/security/manager/ssl/StaticHPKPins.h
+++ b/security/manager/ssl/StaticHPKPins.h
@@ -1157,9 +1157,9 @@ static const TransportSecurityPreload kP
   { "za.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
   { "zh.search.yahoo.com", false, true, false, -1, &kPinset_yahoo },
 };
 
 // Pinning Preload List Length = 484;
 
 static const int32_t kUnknownId = -1;
 
-static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1527104327502000);
+static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1527191478174000);
--- a/security/manager/ssl/nsSTSPreloadList.errors
+++ b/security/manager/ssl/nsSTSPreloadList.errors
@@ -1,10 +1,11 @@
 00220022.net: could not connect to host
 007-preisvergleich.de: could not connect to host
+00881919.com: could not connect to host
 01100010011001010111001101110100.com: could not connect to host
 0day.su: could not connect to host
 0i0.nl: could not connect to host
 0vi.org: could not connect to host
 0x52.org: could not connect to host
 10gb.io: could not connect to host
 135vv.com: could not connect to host
 13826145000.com: could not connect to host
@@ -62,48 +63,52 @@ achterhoekseveiligheidsbeurs.nl: could n
 acpinformatique.fr: could not connect to host
 acrossgw.com: could not connect to host
 ad-disruptio.fr: could not connect to host
 adamcoffee.net: could not connect to host
 adamdixon.co.uk: could not connect to host
 adec-emsa.ae: could not connect to host
 adora-illustrations.fr: could not connect to host
 adult.properties: could not connect to host
+adzie.xyz: could not connect to host
 aevpn.org: could not connect to host
 affily.io: could not connect to host
 afterstack.net: could not connect to host
 agoravm.tk: could not connect to host
 agowa.eu: could not connect to host
 agowa338.de: could not connect to host
 ahlz.sk: could not connect to host
 aiicy.org: could not connect to host
 aikenorganics.com: could not connect to host
 aim-consultants.com: could not connect to host
 ajetaci.cz: could not connect to host
 akiba-server.info: could not connect to host
 akita-stream.com: could not connect to host
+akoch.net: could not connect to host
 akoww.de: could not connect to host
 akul.co.in: could not connect to host
 al-f.net: could not connect to host
 alasta.info: could not connect to host
 alauda-home.de: could not connect to host
 alcatraz.online: could not connect to host
 alexandernorth.ch: could not connect to host
 alexdaulby.com: could not connect to host
 alexei.su: could not connect to host
 alexey-shamara.ru: could not connect to host
 alexmol.tk: could not connect to host
 alexperry.io: could not connect to host
 alilialili.ga: could not connect to host
 alldm.ru: could not connect to host
 alloutatl.com: could not connect to host
 allscammers.exposed: could not connect to host
+almatinki.com: could not connect to host
 alohapartyevents.co.uk: could not connect to host
 alphabrock.cn: could not connect to host
 altahrim.net: could not connect to host
+amateurvoicetalent.com: could not connect to host
 amdouglas.uk: could not connect to host
 ameho.me: could not connect to host
 americandistribuidora.com: could not connect to host
 amilum.org: could not connect to host
 amua.fr: could not connect to host
 amunoz.org: could not connect to host
 analyzemyfriends.com: could not connect to host
 anastasia-shamara.ru: could not connect to host
@@ -112,30 +117,30 @@ andreamcnett.com: could not connect to h
 andreas-kluge.eu: could not connect to host
 andreaskluge.eu: could not connect to host
 andrei-coman.com: could not connect to host
 andrewdaws.co: could not connect to host
 andrewdaws.info: could not connect to host
 andrewdaws.me: could not connect to host
 andrewdaws.tv: could not connect to host
 andrewrdaws.com: could not connect to host
+andronika.net: could not connect to host
 angrydragonproductions.com: could not connect to host
-animacurse.moe: could not connect to host
 anitube-nocookie.ch: could not connect to host
 annetaan.fi: could not connect to host
-anon-next.de: could not connect to host
 anothermanfilm.co.uk: could not connect to host
 anshumanbiswas.com: could not connect to host
 antimatiere.space: could not connect to host
 antoinedeschenes.com: could not connect to host
 anyways.at: could not connect to host
 aojiao.org: could not connect to host
 apkoyunlar.club: could not connect to host
 appdrinks.com: could not connect to host
 apple.ax: could not connect to host
+apps4all.sytes.net: could not connect to host
 area3.org: could not connect to host
 arent.kz: could not connect to host
 arenzanaphotography.com: could not connect to host
 argh.io: could not connect to host
 arknodejs.com: could not connect to host
 arksan.com.tr: could not connect to host
 armenians.online: could not connect to host
 arne-petersen.net: could not connect to host
@@ -143,22 +148,24 @@ arresttracker.com: could not connect to 
 arsenal.ru: could not connect to host
 artea.ga: could not connect to host
 articaexports.com: could not connect to host
 artisense.de: could not connect to host
 artisticedgegranite.net: could not connect to host
 artofeyes.nl: could not connect to host
 as200753.com: could not connect to host
 as200753.net: could not connect to host
+asdyx.de: could not connect to host
 ashleyadum.com: could not connect to host
 askmagicconch.com: could not connect to host
 asphaltfruehling.de: could not connect to host
 asral7.com: could not connect to host
 assdecoeur.org: could not connect to host
 assindia.nl: could not connect to host
+astaninki.com: could not connect to host
 asthon.cn: could not connect to host
 astrath.net: could not connect to host
 astrea-voetbal-groningen.nl: could not connect to host
 astrosnail.pt.eu.org: could not connect to host
 asuhe.xyz: could not connect to host
 async.be: could not connect to host
 at1.co: could not connect to host
 athi.pl: could not connect to host
@@ -196,16 +203,17 @@ bandarifamily.com: could not connect to 
 bannisbierblog.de: could not connect to host
 bardiharborow.com: could not connect to host
 bardiharborow.tk: could not connect to host
 barracuda.blog: could not connect to host
 barreaudenice.com: could not connect to host
 bashc.at: could not connect to host
 batfoundry.com: could not connect to host
 bbdos.ru: could not connect to host
+bbwcs.co.uk: could not connect to host
 bbwteens.org: could not connect to host
 bcnet.com.hk: could not connect to host
 bdsmxxxpics.com: could not connect to host
 beamitapp.com: could not connect to host
 beasel.biz: could not connect to host
 beccajoshwedding.com: could not connect to host
 beersandco.ch: could not connect to host
 bellavistaoutdoor.com: could not connect to host
@@ -271,23 +279,25 @@ bonobo.cz: could not connect to host
 bookreport.ga: could not connect to host
 borchers-media.de: could not connect to host
 borisbesemer.com: could not connect to host
 bouncing-bugs.co.uk: could not connect to host
 bqcp.net: could not connect to host
 brainlag.org: could not connect to host
 braintensive.com: could not connect to host
 brandontaylor-black.com: could not connect to host
+bratteng.me: could not connect to host
 breathingblanket.com: could not connect to host
 brettabel.com: could not connect to host
 brfvh24.se: could not connect to host
 brideandgroomdirect.ie: could not connect to host
 brio-ukraine.store: could not connect to host
 brookframework.org: could not connect to host
 brrr.fr: could not connect to host
+bruckner.li: could not connect to host
 bryanshearer.accountant: could not connect to host
 brynnan.nl: could not connect to host
 bsalyzer.com: could not connect to host
 bsktweetup.info: could not connect to host
 bslim-e-boutique.com: could not connect to host
 bsuess.de: could not connect to host
 btsow.com: could not connect to host
 buenotour.ru: could not connect to host
@@ -316,17 +326,16 @@ calculatoaresecondhand.xyz: could not co
 callabs.net: could not connect to host
 calleveryday.com: could not connect to host
 callsigns.ca: could not connect to host
 calypso-tour.net: could not connect to host
 camda.online: could not connect to host
 campingcarlovers.com: could not connect to host
 cancelmyprofile.com: could not connect to host
 canifis.net: could not connect to host
-caps.is: could not connect to host
 cardelmar.es: could not connect to host
 cardloan-manual.net: could not connect to host
 carey.bio: could not connect to host
 carloshmm.stream: could not connect to host
 carlovanwyk.com: could not connect to host
 carrierplatform.com: could not connect to host
 casinoreal.com: could not connect to host
 catsmagic.pp.ua: could not connect to host
@@ -345,18 +354,16 @@ centos.pub: could not connect to host
 centrallead.net: could not connect to host
 cervejista.com: could not connect to host
 cgtx.us: could not connect to host
 challengeskins.com: could not connect to host
 championnat-romand-cuisiniers-amateurs.ch: could not connect to host
 channellife.asia: could not connect to host
 chaouby.com: could not connect to host
 charonsecurity.com: could not connect to host
-chatzimanolis.com: could not connect to host
-chatzimanolis.gr: could not connect to host
 cheesefusion.com: could not connect to host
 chez-janine.de: could not connect to host
 childrendeservebetter.org: could not connect to host
 china-line.org: could not connect to host
 chinternet.xyz: could not connect to host
 chiropracticwpb.com: could not connect to host
 chloe.re: could not connect to host
 chocolat-suisse.ch: could not connect to host
@@ -375,17 +382,16 @@ class.com.au: could not connect to host
 clearchatsandbox.com: could not connect to host
 clearviewwealthprojector.com.au: could not connect to host
 clic-music.com: could not connect to host
 clintonbloodworth.com: could not connect to host
 closetemail.com: could not connect to host
 cloudbleed.info: could not connect to host
 cloudbolin.es: could not connect to host
 cloudimproved.com: could not connect to host
-cloudimprovedtest.com: could not connect to host
 cloudwarez.xyz: could not connect to host
 clownish.co.il: could not connect to host
 clycat.ru: could not connect to host
 cmpr.es: could not connect to host
 cmrss.com: could not connect to host
 cms-weble.jp: could not connect to host
 cmweller.com: could not connect to host
 cnetw.xyz: could not connect to host
@@ -407,16 +413,17 @@ coloppe.com: could not connect to host
 com.cc: could not connect to host
 combatshield.cz: could not connect to host
 complex-organization.com: could not connect to host
 complt.xyz: could not connect to host
 comprehensiveihc.com: could not connect to host
 conception.sk: could not connect to host
 conniesacademy.com: could not connect to host
 conrad.am: could not connect to host
+console.ninja: could not connect to host
 construct-trust.com: could not connect to host
 constructive.men: could not connect to host
 conve.eu: could not connect to host
 coreapm.com: could not connect to host
 coreapm.org: could not connect to host
 corecdn.org: could not connect to host
 corinnanese.de: could not connect to host
 correct.horse: could not connect to host
@@ -451,17 +458,16 @@ cypherpunk.ws: could not connect to host
 czlx.co: could not connect to host
 d-bood.site: could not connect to host
 d3x.pw: could not connect to host
 d8studio.net: could not connect to host
 daltonedwards.me: could not connect to host
 dam74.com.ar: could not connect to host
 daniel-stahl.net: could not connect to host
 danielthompson.info: could not connect to host
-danpiel.net: could not connect to host
 darkdestiny.ch: could not connect to host
 darlo.co.uk: could not connect to host
 darrienworth.com: could not connect to host
 dashboard.yt: could not connect to host
 data-detox.com: could not connect to host
 databutlr.com: could not connect to host
 databutlr.net: could not connect to host
 datacool.tk: could not connect to host
@@ -480,28 +486,29 @@ dc585.info: could not connect to host
 dcc.moe: could not connect to host
 dden.website: could not connect to host
 dden.xyz: could not connect to host
 de-servers.de: could not connect to host
 decoyrouting.com: could not connect to host
 dedietrich-asia.com: could not connect to host
 deepcreampie.com: could not connect to host
 deeps.cat: could not connect to host
-deepspace.dedyn.io: could not connect to host
 deloittequant.com: could not connect to host
 derchris.me: could not connect to host
 derivativeshub.pro: could not connect to host
 dermacarecomplex.com: could not connect to host
+design-fu.com: could not connect to host
 detecte-fuite.ch: could not connect to host
 detecte.ch: could not connect to host
 detectefuite.ch: could not connect to host
 devdesco.com: could not connect to host
 developersclub.website: could not connect to host
 deviltraxxx.de: could not connect to host
 devops.moe: could not connect to host
+dgby.org: could not connect to host
 dhl-smart.ch: could not connect to host
 dhub.xyz: could not connect to host
 dhuy.net: could not connect to host
 dhxxls.com: could not connect to host
 diceduels.com: could not connect to host
 dicgaming.net: could not connect to host
 dick.red: could not connect to host
 didierlaumen.be: could not connect to host
@@ -516,34 +523,33 @@ diguass.us: could not connect to host
 dijks.com: could not connect to host
 dingcc.com: could not connect to host
 directtwo.solutions: could not connect to host
 direwolfsoftware.ca: could not connect to host
 dirtycat.ru: could not connect to host
 disability.gov: could not connect to host
 disadattamentolavorativo.it: could not connect to host
 disco-crazy-world.de: could not connect to host
+discoveringdocker.com: could not connect to host
 discoveryballoon.org: could not connect to host
 distinctivephotography.com.au: could not connect to host
 ditch.ch: could not connect to host
 dixmag.com: could not connect to host
 djul.net: could not connect to host
 dlouwrink.nl: could not connect to host
 dlyl888.com: could not connect to host
 dnfc.rocks: could not connect to host
 dobrisan.ro: could not connect to host
 doctafit.com: could not connect to host
 doesmycodehavebugs.today: could not connect to host
 dogcratereview.info: could not connect to host
 dojifish.space: could not connect to host
 dolphin-hosting.com: could not connect to host
-domainstaff.com: could not connect to host
 domengrad.ru: could not connect to host
 domfee.com: could not connect to host
-dominicself.co.uk: could not connect to host
 dongkexue.com: could not connect to host
 doop.im: could not connect to host
 doopdidoop.com: could not connect to host
 dopesoft.de: could not connect to host
 dostavkakurierom.ru: could not connect to host
 dougferris.id.au: could not connect to host
 doyoulyft.com: could not connect to host
 doze-cloud.tech: could not connect to host
@@ -576,22 +582,24 @@ e-mak.eu: could not connect to host
 e-wishlist.net: could not connect to host
 earth-people.org: could not connect to host
 eatfitoutlet.com.br: could not connect to host
 eatry.io: could not connect to host
 ebonyriddle.com: could not connect to host
 eccux.com: could not connect to host
 ectora.com: could not connect to host
 edgecustomersportal.com: could not connect to host
+edp-collaborative.com: could not connect to host
 eduif.nl: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 115"  data: no]
 eeb98.com: could not connect to host
 effectiveosgi.com: could not connect to host
 ehrlichesbier.de: could not connect to host
 ehuber.info: could not connect to host
 einsatzstiefel.info: could not connect to host
+ejgconsultancy.co.uk: could not connect to host
 ekobudisantoso.net: could not connect to host
 elbetech.net: could not connect to host
 electricalcontrolpanels.co.uk: could not connect to host
 elektronring.com: could not connect to host
 elenorsmadness.org: could not connect to host
 elevateandprosper.com: could not connect to host
 elitesensual.com.br: could not connect to host
 elonbase.com: could not connect to host
@@ -603,32 +611,35 @@ embracethedarkness.co.uk: could not conn
 emeraldcoastrideshare.com: could not connect to host
 emilyjohnson.ga: could not connect to host
 emrenovation.com: could not connect to host
 endohaus.us: could not connect to host
 endspamwith.us: could not connect to host
 enoou.com: could not connect to host
 enpalmademallorca.info: could not connect to host
 er-music.com: could not connect to host
+erad.fr: could not connect to host
 erspro.net: could not connect to host
 erwinwensveen.nl: could not connect to host
 esoterik.link: could not connect to host
+esseriumani.com: could not connect to host
 ethiobaba.com: could not connect to host
 euexia.fr: could not connect to host
 eung.ga: could not connect to host
 eurostrategy.vn.ua: could not connect to host
 evankurniawan.com: could not connect to host
 everyarti.st: could not connect to host
 eveshaiwu.com: could not connect to host
+evileden.com: could not connect to host
 eworksmedia.com: could not connect to host
 exceed.global: could not connect to host
 exceptionalservices.us: could not connect to host
 exo.do: could not connect to host
-extensiblewebsummit.org: could not connect to host
 exteriorservices.io: could not connect to host
+extreme-players.com: could not connect to host
 eytosh.net: could not connect to host
 f1bigpicture.com: could not connect to host
 f8842.com: could not connect to host
 faber.org.ru: could not connect to host
 fabian-fingerle.de: could not connect to host
 fabian-kluge.de: could not connect to host
 fabienbaker.com: could not connect to host
 fabulouslyyouthfulskin.com: could not connect to host
@@ -722,46 +733,47 @@ frusky.net: could not connect to host
 fsfi.is: could not connect to host
 fsradio.eu: could not connect to host
 ftgho.com: could not connect to host
 fuckcf.cf: could not connect to host
 fugle.de: could not connect to host
 fuitedeau.ch: could not connect to host
 fukuko.biz: could not connect to host
 fukuko.xyz: could not connect to host
+fukuoka-cityliner.jp: could not connect to host
 fun9.cc: could not connect to host
 fun99.cc: could not connect to host
 funksteckdosen24.de: could not connect to host
 funoverip.net: could not connect to host
 funspins.com: could not connect to host
 futos.de: could not connect to host
 fuzoku-sodan.com: could not connect to host
 fyol.pw: could not connect to host
 g01.in.ua: could not connect to host
 g1jeu.com: could not connect to host
 gaasuper6.com: could not connect to host
 gabriele-kluge.de: could not connect to host
 gafachi.com: could not connect to host
-gagniard.org: could not connect to host
 gala.kiev.ua: could not connect to host
 galgoafegao.com.br: could not connect to host
 galgoingles.com.br: could not connect to host
 gam3rs.de: could not connect to host
 game-gentle.com: could not connect to host
 gameswitchers.uk: could not connect to host
 gametium.com: could not connect to host
 gametium.es: could not connect to host
 gamhealth.net: could not connect to host
 gancedo.com.es: could not connect to host
 garage-door.pro: could not connect to host
 gasbarkenora.com: could not connect to host
 gasnews.net: could not connect to host
 gautham.it: could not connect to host
 gautham.pro: could not connect to host
 gaygeeks.de: could not connect to host
+gaytorrent.ru: could not connect to host
 gc.net: could not connect to host
 gchoic.com: could not connect to host
 gdevpenze.ru: could not connect to host
 gdhzcgs.com: could not connect to host
 gdz-otvety.com: could not connect to host
 ge1.me: could not connect to host
 geek.ch: could not connect to host
 gehrke.nrw: could not connect to host
@@ -786,31 +798,33 @@ getitpeople.com: could not connect to ho
 getwarden.net: could not connect to host
 getyourphix.tk: could not connect to host
 gevaulug.fr: could not connect to host
 gfoss.gr: could not connect to host
 gglks.com: could not connect to host
 ggss.cf: could not connect to host
 gh16.com.ar: could not connect to host
 gifzilla.net: could not connect to host
+giliamor.com: could not connect to host
 gina-architektur.design: could not connect to host
 girlsforum.com: could not connect to host
 git.co: could not connect to host
 gix.net.pl: could not connect to host
 gladystudio.com: could not connect to host
 globalvisions-events.ch: could not connect to host
 glutenfreelife.co.nz: could not connect to host
 gmantra.org: could not connect to host
 gmanukyan.com: could not connect to host
 gnom.me: could not connect to host
 gnosticjade.net: could not connect to host
 godrealms.com: could not connect to host
 goiaspropaganda.com.br: could not connect to host
 goldfelt.com: could not connect to host
 gongjuhao.com: could not connect to host
+goodyearsotn.co.uk: could not connect to host
 google.ax: could not connect to host
 goranrango.ch: could not connect to host
 gottfridsberg.org: could not connect to host
 gozadentro.com: could not connect to host
 gradsm-ci.net: could not connect to host
 granth.io: could not connect to host
 grassenberg.de: could not connect to host
 gratisonlinesex.com: could not connect to host
@@ -818,28 +832,30 @@ greenitpark.net: could not connect to ho
 greggsfoundation.org.uk: could not connect to host
 gregmartyn.com: could not connect to host
 greuel.online: could not connect to host
 gritte.net: could not connect to host
 grossmisconduct.news: could not connect to host
 gugaltika-ipb.org: could not connect to host
 guinea-pig.co: could not connect to host
 guishem.com: could not connect to host
+gunhunter.com: could not connect to host
 gurochan.ch: could not connect to host
 gus.moe: could not connect to host
 gutuia.blue: could not connect to host
 gvchannel.xyz: could not connect to host
 gzpblog.com: could not connect to host
 h3artbl33d.nl: could not connect to host
 habeo.si: could not connect to host
 hackbubble.me: could not connect to host
 hackingsafe.com: could not connect to host
 hackmeplz.com: could not connect to host
 haktec.de: could not connect to host
 hakugin.me: could not connect to host
+halacs.hu: could not connect to host
 halcyonsbastion.com: could not connect to host
 half-logic.eu.org: could not connect to host
 halkyon.net: could not connect to host
 hamking.tk: could not connect to host
 hamu.blue: could not connect to host
 handinhandfoundation.org.uk: could not connect to host
 hapijs.cn: could not connect to host
 happytiger.eu: could not connect to host
@@ -878,32 +894,34 @@ hetmeisjeachterpauw.nl: could not connec
 hexobind.com: could not connect to host
 hfu.io: could not connect to host
 hg881.com: could not connect to host
 hialatv.com: could not connect to host
 hill.selfip.net: could not connect to host
 hintermeier-rae.at: could not connect to host
 hirte-digital.de: could not connect to host
 hitchunion.org: could not connect to host
+hiverlune.net: could not connect to host
 hjes.com.ve: could not connect to host
 hohm.in: could not connect to host
 holidayincotswolds.co.uk: could not connect to host
 homoglyph.net: could not connect to host
 hondenoppasfraneker.nl: could not connect to host
 honeycome.net: could not connect to host
 hoodoo.io: could not connect to host
 hoodoo.tech: could not connect to host
 hopglass.eu: could not connect to host
 hopglass.net: could not connect to host
 horvathd.eu: could not connect to host
 hosted-oswa.org: could not connect to host
 hotelmadhuwanvihar.com: could not connect to host
 hozinga.de: could not connect to host
 hr98.tk: could not connect to host
 hserver.top: could not connect to host
+https4all.org: could not connect to host
 httptest.net: could not connect to host
 huangzenghao.cn: could not connect to host
 huangzenghao.com: could not connect to host
 hudingyuan.cn: could not connect to host
 huiser.nl: could not connect to host
 hukkatavara.com: could not connect to host
 hunger.im: could not connect to host
 huongquynh.com: could not connect to host
@@ -942,16 +960,17 @@ imlinan.cn: could not connect to host
 imlinan.info: could not connect to host
 imlinan.net: could not connect to host
 imoner.ga: could not connect to host
 imperdintechnologies.com: could not connect to host
 increasetestosteronelevels.org: could not connect to host
 industreiler.com: could not connect to host
 industreiler.com.br: could not connect to host
 inexpensivecomputers.net: could not connect to host
+infocity-tech.fr: could not connect to host
 informatik.zone: could not connect to host
 infoworm.org: could not connect to host
 injust.me: could not connect to host
 innovativeideaz.org: could not connect to host
 inondation.ch: could not connect to host
 inscript.pl: could not connect to host
 insouciant.org: could not connect to host
 inst.mobi: could not connect to host
@@ -966,20 +985,23 @@ iodu.re: could not connect to host
 ip.or.at: could not connect to host
 iphonechina.net: could not connect to host
 iplog.info: could not connect to host
 ipnetworking.net: could not connect to host
 irinkeby.nu: could not connect to host
 isamiok.com: could not connect to host
 isisfighters.info: could not connect to host
 iskkk.com: could not connect to host
+isoroc-nidzica.pl: could not connect to host
 isscouncil.com: could not connect to host
+issuesofconcern.in: could not connect to host
 isthefieldcontrolsystemdown.com: could not connect to host
 isz.no: could not connect to host
 itad.top: could not connect to host
+itnews-bg.com: could not connect to host
 itpro-mg.de: could not connect to host
 its-schindler.de: could not connect to host
 itsatrap.nl: could not connect to host
 ivanilla.org: could not connect to host
 ivanpolchenko.com: could not connect to host
 ivystech.com: could not connect to host
 ixio.cz: could not connect to host
 j0ng.xyz: could not connect to host
@@ -1007,17 +1029,16 @@ jhburton.co.uk: could not connect to hos
 jiangzm.com: could not connect to host
 jiaqiang.vip: could not connect to host
 jmb.lc: could not connect to host
 jmk.hu: could not connect to host
 jobmedic.com: could not connect to host
 joecod.es: could not connect to host
 joetyson.io: could not connect to host
 johngo.tk: could not connect to host
-johnkastler.net: could not connect to host
 johntomasowa.com: could not connect to host
 jonathansanchez.pro: could not connect to host
 jonfor.net: could not connect to host
 jonpads.com: could not connect to host
 jooto.com: could not connect to host
 josephsniderman.net: could not connect to host
 jpod.cc: could not connect to host
 js88.sg: could not connect to host
@@ -1028,39 +1049,38 @@ juliaoantiguidades.com.br: could not con
 juliawebber.co.za: could not connect to host
 jumbopan.com: could not connect to host
 jumbopan.net: could not connect to host
 just-pools.co.za: could not connect to host
 justinharrison.ca: could not connect to host
 justzz.xyz: could not connect to host
 juventusmania1897.com: could not connect to host
 k33k00.com: could not connect to host
-kabus.org: could not connect to host
 kaika-facilitymanagement.de: could not connect to host
 kaloix.de: could not connect to host
 kamalame.co: could not connect to host
 kamitech.ch: could not connect to host
 kandalife.com: could not connect to host
 kanganer.com: could not connect to host
 kangzaber.com: could not connect to host
 kapo.info: could not connect to host
 karamna.com: could not connect to host
 karuneshjohri.com: could not connect to host
 kat.al: could not connect to host
-katzen.me: could not connect to host
 kawaiiku.com: could not connect to host
 kawaiiku.de: could not connect to host
 kaydan.io: could not connect to host
 kearney.io: could not connect to host
 kela.jp: could not connect to host
 kellyandantony.com: could not connect to host
 kelm.me: could not connect to host
 kermadec.com: could not connect to host
 keshausconsulting.com: could not connect to host
 kevinbowers.me: could not connect to host
+kevinbusse.de: could not connect to host
 kevindekoninck.com: could not connect to host
 kevinfoley.cc: could not connect to host
 kevinfoley.org: could not connect to host
 keyihao.cn: could not connect to host
 keyserver.sexy: could not connect to host
 kgb.us: could not connect to host
 kidbacker.com: could not connect to host
 kieranweightman.me: could not connect to host
@@ -1091,16 +1111,17 @@ kotorimusic.ga: could not connect to hos
 kozmik.co: could not connect to host
 krampus-fischamend.at: could not connect to host
 kriegskindernothilfe.de: could not connect to host
 ktube.yt: could not connect to host
 kubusadvocaten.nl: could not connect to host
 kuko-crews.org: could not connect to host
 kupiec.eu.org: could not connect to host
 kwikmed.eu: could not connect to host
+kyberna.xyz: could not connect to host
 kyle.place: could not connect to host
 kylebaldw.in: could not connect to host
 kylling.io: could not connect to host
 kyujin-office.net: could not connect to host
 l18.io: could not connect to host
 laboutiquemarocaineduconvoyeur.com: could not connect to host
 laboutiquemarocaineduconvoyeur.ma: could not connect to host
 lacasa.fr: could not connect to host
@@ -1141,16 +1162,17 @@ leveredge.net: could not connect to host
 lezdomsm.com: could not connect to host
 lfaz.org: could not connect to host
 lhalbert.xyz: could not connect to host
 lheinrich.org: could not connect to host
 lhsj28.com: could not connect to host
 lhsj68.com: could not connect to host
 lhsj78.com: could not connect to host
 liaozheqi.cn: could not connect to host
+liautard.fr: could not connect to host
 libertas-tech.com: could not connect to host
 libscode.com: could not connect to host
 likenosis.com: could not connect to host
 linkages.org: could not connect to host
 linksanitizer.com: could not connect to host
 linksextremist.at: could not connect to host
 linley.de: could not connect to host
 linostassi.net: could not connect to host
@@ -1210,28 +1232,30 @@ mamastore.eu: could not connect to host
 marcdorka.de: could not connect to host
 marcelmarnitz.com: could not connect to host
 marche-nordic-jorat.ch: could not connect to host
 mardelcupon.com: could not connect to host
 mare92.cz: could not connect to host
 mariusschulte.de: could not connect to host
 marketingdesignu.cz: could not connect to host
 marko-fenster24.de: could not connect to host
+markrego.com: could not connect to host
 martins.im: could not connect to host
 marxist.party: could not connect to host
 mashandco.it: could not connect to host
 mastodon.expert: could not connect to host
 mastodon.my: could not connect to host
 matarrosabierzo.com: could not connect to host
 matcha-iga.jp: could not connect to host
 mathijskingma.nl: could not connect to host
 matthewtester.com: could not connect to host
 matthey.nl: could not connect to host
 mattli.us: could not connect to host
 mattwb65.com: could not connect to host
+matze.co: could not connect to host
 maybeul.com: could not connect to host
 maynardnetworks.com: could not connect to host
 mazternet.ru: could not connect to host
 mazurlabs.tk: could not connect to host
 mb-is.info: could not connect to host
 mbdrogenbos-usedcars.be: could not connect to host
 mbsec.net: could not connect to host
 mbwemmel-usedcars.be: could not connect to host
@@ -1262,27 +1286,31 @@ mentorithm.com: could not connect to hos
 menzaijia.com: could not connect to host
 mercanix.co.uk: could not connect to host
 mes10doigts.ovh: could not connect to host
 metrix-money-ptc.com: could not connect to host
 metrix.design: could not connect to host
 mexior.nl: could not connect to host
 meyeraviation.com: could not connect to host
 mhjuma.com: could not connect to host
+michaelcullen.name: could not connect to host
 michaelkuchta.me: could not connect to host
 michaelsulzer.com: could not connect to host
 michaelsulzer.eu: could not connect to host
 mieterschutzkartei.de: could not connect to host
 mikeybot.com: could not connect to host
 min.kiwi: could not connect to host
 mingy.ddns.net: could not connect to host
 mingyueli.com: could not connect to host
 minitruckin.net: could not connect to host
+misconfigured.io: could not connect to host
 mkfs.fr: could not connect to host
 mkplay.io: could not connect to host
+mm13.at: could not connect to host
+mmilog.hu: could not connect to host
 mmstick.tk: could not connect to host
 mneeb.de: could not connect to host
 mobile.eti.br: could not connect to host
 mobmp4.co: could not connect to host
 modded-minecraft-server-list.com: could not connect to host
 modernibytovytextil.cz: could not connect to host
 moderntld.net: could not connect to host
 moe-max.jp: could not connect to host
@@ -1312,17 +1340,16 @@ mrafrohead.com: could not connect to hos
 mremallin.ca: could not connect to host
 mrizzio.com: could not connect to host
 mrjooz.com: could not connect to host
 mrliu.me: could not connect to host
 msgallery.tk: could not connect to host
 msz-fotografie.de: could not connect to host
 mtirc.co: could not connect to host
 mtn.cc: could not connect to host
-muchohentai.com: could not connect to host
 muj-svet.cz: could not connect to host
 multivpn.fr: could not connect to host
 munduch.cz: could not connect to host
 murraycolin.org: could not connect to host
 murz.tv: could not connect to host
 muslimbanter.co.za: could not connect to host
 mxawei.cn: could not connect to host
 mxlife.org: could not connect to host
@@ -1335,33 +1362,31 @@ mygreatjob.eu: could not connect to host
 mygreatjobs.de: could not connect to host
 mykeepsake.xyz: could not connect to host
 myndcommunication.com: could not connect to host
 mytravelblog.de: could not connect to host
 mzlog.win: could not connect to host
 n0099.cf: could not connect to host
 naano.org: could not connect to host
 naphex.rocks: could not connect to host
-narodsovety.ru: could not connect to host
 nassi.me: could not connect to host
 nastysclaw.com: could not connect to host
 natur-udvar.hu: could not connect to host
 ncdesigns-studio.com: could not connect to host
 ndtblog.com: could not connect to host
 necesitodinero.org: could not connect to host
 neer.io: could not connect to host
-nephy.jp: could not connect to host
 nerfroute.com: could not connect to host
 nestone.ru: could not connect to host
 net4visions.at: could not connect to host
+netica.fr: could not connect to host
 netscaler.expert: could not connect to host
 nevadafiber.net: could not connect to host
 newcityinfo.info: could not connect to host
 newfacialbeautycream.com: could not connect to host
-nex.sx: could not connect to host
 nexusbyte.de: could not connect to host
 nexuscorporation.in: could not connect to host
 nfluence.org: could not connect to host
 ngiemboon.net: could not connect to host
 nico.st: could not connect to host
 nienfun.com: could not connect to host
 nikksno.io: could not connect to host
 nikobradshaw.com: could not connect to host
@@ -1389,41 +1414,40 @@ nowremindme.com: could not connect to ho
 nsbfalconacademy.org: could not connect to host
 nsdev.cn: could not connect to host
 nsmail.cn: could not connect to host
 nudel.ninja: could not connect to host
 nyanpasu.tv: could not connect to host
 obdolbacca.ru: could not connect to host
 oberam.de: could not connect to host
 oberhof.co: could not connect to host
-odifi.com: could not connect to host
 off-the-clock.us: could not connect to host
 offgames.pro: could not connect to host
 office-ruru.com: could not connect to host
 ohyooo.com: could not connect to host
 oinky.ddns.net: could not connect to host
+okmx.de: could not connect to host
 oldchaphome.nl: could not connect to host
 oldtimer-trifft-flugplatz.de: could not connect to host
 oliverspringer.eu: could not connect to host
 omnibot.tv: could not connect to host
 onewebdev.info: could not connect to host
 onsite4u.de: could not connect to host
 onstud.com: could not connect to host
 onwie.fr: could not connect to host
 ooeste.com: could not connect to host
 open-desk.org: could not connect to host
 opinion8td.com: could not connect to host
 optimist.bg: could not connect to host
 oscarmashauri.com: could not connect to host
 oscsdp.cz: could not connect to host
+oskuro.net: could not connect to host
 osmanlitorunu.com: could not connect to host
-osterkraenzchen.de: could not connect to host
 otinane.eu: could not connect to host
 ourchoice2016.com: could not connect to host
-overthinkingit.com: could not connect to host
 owlscrap.ru: could not connect to host
 oxynux.xyz: could not connect to host
 pabloartea.ga: could not connect to host
 packetcrash.net: could not connect to host
 paichai.space: could not connect to host
 paio2-rec.com: could not connect to host
 paio2.com: could not connect to host
 panasca.is: could not connect to host
@@ -1434,16 +1458,17 @@ panascais.eu: could not connect to host
 panascais.host: could not connect to host
 panascais.io: could not connect to host
 panascais.me: could not connect to host
 panascais.pw: could not connect to host
 panascais.site: could not connect to host
 panascais.tech: could not connect to host
 panascais.us: could not connect to host
 pandapsy.com: could not connect to host
+paradisenazarene.com: could not connect to host
 pardnoy.com: could not connect to host
 pascalmathis.com: could not connect to host
 pascalmathis.me: could not connect to host
 pascalmathis.net: could not connect to host
 passrhce.com: could not connect to host
 passrhcsa.com: could not connect to host
 pastie.se: could not connect to host
 patrickbusch.net: could not connect to host
@@ -1454,18 +1479,20 @@ paulshir.is: could not connect to host
 payload.tech: could not connect to host
 paymon.tj: could not connect to host
 paypod.org: could not connect to host
 pbytes.com: could not connect to host
 pcvirusclear.com: could not connect to host
 pear2pear.de: could not connect to host
 peerless.ae: could not connect to host
 peirong.me: could not connect to host
+penfold.fr: could not connect to host
 pengisatelier.net: could not connect to host
 pepper.dog: could not connect to host
+perrone.co: could not connect to host
 persjrp.ca: could not connect to host
 persoform.ch: could not connect to host
 petlife.od.ua: could not connect to host
 peuf.shop: could not connect to host
 peykezamin.ir: could not connect to host
 pgmsource.com: could not connect to host
 phdwuda.com: could not connect to host
 phelx.de: could not connect to host
@@ -1481,16 +1508,17 @@ pianetaottica.info: could not connect to
 picallo.es: could not connect to host
 picone.com.au: could not connect to host
 picsandtours.com: could not connect to host
 pierrejeansuau.fr: could not connect to host
 pieterhordijk.com: could not connect to host
 pimspage.nl: could not connect to host
 pinebaylibrary.org: could not connect to host
 pinkhq.com: could not connect to host
+pinoyonlinetv.com: could not connect to host
 pitot-rs.org: could not connect to host
 pixelgliders.de: could not connect to host
 plaasprodukte.com: could not connect to host
 planbox.info: could not connect to host
 playsharp.com: could not connect to host
 please-deny.me: could not connect to host
 plussizereviews.com: could not connect to host
 pmbremer.de: could not connect to host
@@ -1521,16 +1549,17 @@ ppoozl.com: could not connect to host
 prettytunesapp.com: could not connect to host
 princessbackpack.de: could not connect to host
 printsos.com: could not connect to host
 prism-communication.com: could not connect to host
 privacymanatee.com: could not connect to host
 privcloud.org: could not connect to host
 privilegevisa.fr: could not connect to host
 proactive.run: could not connect to host
+procinorte.net: could not connect to host
 profinetz.de: could not connect to host
 progressivecfo.co.nz: could not connect to host
 projectasterk.com: could not connect to host
 projectte.ch: could not connect to host
 projectx.top: could not connect to host
 projekt-umbriel.de: could not connect to host
 prokop.ovh: could not connect to host
 promhadan.com: could not connect to host
@@ -1543,38 +1572,38 @@ prpsss.com: could not connect to host
 pruikshop.nl: could not connect to host
 prytkov.com: could not connect to host
 psncardplus.be: could not connect to host
 psncardplus.com: could not connect to host
 psncardplus.dk: could not connect to host
 psncardplus.nl: could not connect to host
 psncardplus.se: could not connect to host
 psychoco.net: could not connect to host
-psylab.re: could not connect to host
 publimepa.it: could not connect to host
 pugilares.com.pl: could not connect to host
 puhe.se: could not connect to host
-putney.io: could not connect to host
 pwdgen.net: could not connect to host
 pypa.io: could not connect to host
 pythia.nz: could not connect to host
 qbin.io: could not connect to host
 qforum.org: could not connect to host
 qikan.net: could not connect to host
 qirinus.com: could not connect to host
 qldformulaford.org: could not connect to host
 qnatek.org: could not connect to host
 qoqo.us: could not connect to host
 qqvips.com: could not connect to host
 qrlfinancial.com: could not connect to host
 qto.net: could not connect to host
 r-cut.fr: could not connect to host
 rackblue.com: could not connect to host
+raidensnakesden.co.uk: could not connect to host
+raidensnakesden.com: could not connect to host
+raidensnakesden.net: could not connect to host
 rainbin.com: could not connect to host
-ramatola.uk: could not connect to host
 ranos.org: could not connect to host
 ravengergaming.net: could not connect to host
 ravse.dk: could not connect to host
 raycarruthersphotography.co.uk: could not connect to host
 rb-china.net: could not connect to host
 rbxcatalog.com: could not connect to host
 rcoliveira.com: could not connect to host
 rdfz.tech: could not connect to host
@@ -1583,16 +1612,19 @@ reaiaer.com: could not connect to host
 real-compare.com: could not connect to host
 realcli.com: could not connect to host
 reality0ne.com: could not connect to host
 realloc.me: could not connect to host
 realnewhomes.com: could not connect to host
 realraghavgupta.com: could not connect to host
 realwoo.com: could not connect to host
 reath.me: could not connect to host
+reeson.at: could not connect to host
+reeson.info: could not connect to host
+reeson.org: could not connect to host
 reevu.net: could not connect to host
 reflecton.io: could not connect to host
 regendevices.eu: could not connect to host
 regio-salland.nl: could not connect to host
 reignsphere.net: could not connect to host
 reismil.ch: could not connect to host
 renemayrhofer.com: could not connect to host
 rentbrowser.com: could not connect to host
@@ -1606,16 +1638,17 @@ reth.ch: could not connect to host
 retube.ga: could not connect to host
 reykjavik.guide: could not connect to host
 ribopierre.fr: could not connect to host
 riceglue.com: could not connect to host
 richardb.me: could not connect to host
 richeza.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 115"  data: no]
 ris.fi: could not connect to host
 riversideauto.net: could not connect to host
+riverweb.gr: could not connect to host
 robertocasares.no-ip.biz: could not connect to host
 robi-net.it: could not connect to host
 robomonkey.org: could not connect to host
 robust.ga: could not connect to host
 rodehutskors.net: could not connect to host
 rofrank.space: could not connect to host
 rolandszabo.com: could not connect to host
 romanticschemermovie.com: could not connect to host
@@ -1624,61 +1657,62 @@ ronghexx.com: could not connect to host
 roolevoi.ru: could not connect to host
 rootbsd.at: could not connect to host
 rospa100.com: could not connect to host
 rotterdamjazz.info: could not connect to host
 royzez.com: could not connect to host
 rozalynne-dawn.ga: could not connect to host
 rpasafrica.com: could not connect to host
 rs-devdemo.host: could not connect to host
+rsauget.fr: could not connect to host
 rsldb.com: could not connect to host
 rtc.fun: could not connect to host
 rubbix.net: could not connect to host
 rubendv.be: could not connect to host
 ruhr3.de: could not connect to host
 runcarina.com: could not connect to host
 rundumcolumn.xyz: could not connect to host
 runementors.com: could not connect to host
-ruri.io: could not connect to host
 ruurdboomsma.nl: could not connect to host
 rzegroup.com: could not connect to host
 s0923.com: could not connect to host
 s3n.se: could not connect to host
 sabine-forschbach.de: could not connect to host
 sabineforschbach.de: could not connect to host
 safedevice.net: could not connect to host
 safejourney.education: could not connect to host
 saferedirectlink.com: could not connect to host
 sallysubs.com: could not connect to host
 salzamt.tk: could not connect to host
 samaritan.tech: could not connect to host
 samsonova.de: could not connect to host
 sanael.net: could not connect to host
 sanatrans.com: could not connect to host
+santojuken.co.jp: could not connect to host
 sarahlicity.me.uk: could not connect to host
 sarindia.com: could not connect to host
 sarindia.de: could not connect to host
 sarndipity.com: could not connect to host
 sash.pw: could not connect to host
 savethedogfishfoundation.org: could not connect to host
 savingbytes.com: could not connect to host
 sbm.cloud: could not connect to host
 schaafenstrasse.koeln: could not connect to host
 schmidttulskie.de: could not connect to host
 schnapke.name: could not connect to host
 schwarzegar.de: could not connect to host
-schwarzwaldcon.de: could not connect to host
 sciencemonster.co.uk: could not connect to host
 scintillating.stream: could not connect to host
 scitopia.me: could not connect to host
 scm-2017.org: could not connect to host
 scottainslie.me.uk: could not connect to host
 scripthost.org: could not connect to host
 scriptjunkie.us: could not connect to host
 sctm.at: could not connect to host
+seankilgarriff.com: could not connect to host
 sebastian-lutsch.de: could not connect to host
 secitem.de: could not connect to host
 sectest.ml: could not connect to host
 secure-automotive-cloud.com: could not connect to host
 secure-automotive-cloud.org: could not connect to host
 secureindia.co: could not connect to host
 security.xn--q9jyb4c: could not connect to host
 securitymap.wiki: could not connect to host
@@ -1691,16 +1725,17 @@ seleondar.ru: could not connect to host
 selfserverx.com: could not connect to host
 sellmoretires.com: could not connect to host
 seoscribe.net: could not connect to host
 serverlauget.no: could not connect to host
 servfefe.com: could not connect to host
 seryovpn.com: could not connect to host
 sesha.co.za: could not connect to host
 sessionslogning.dk: could not connect to host
+sevsey.ru: could not connect to host
 shadiku.com: could not connect to host
 shadowplus.net: could not connect to host
 shadowrocket.net: could not connect to host
 shang-yu.cn: could not connect to host
 shanxiapark.com: could not connect to host
 shavingks.com: could not connect to host
 sheying.tm: could not connect to host
 shinko-osaka.jp: could not connect to host
@@ -1710,51 +1745,54 @@ shredoptics.ch: could not connect to hos
 shurita.org: could not connect to host
 shuzicai.cn: could not connect to host
 shymeck.pw: could not connect to host
 siamega.com: could not connect to host
 siebens.net: could not connect to host
 signosquecombinam.com.br: could not connect to host
 sijmenschoon.nl: could not connect to host
 sikatehtaat.fi: could not connect to host
+sikko.biz: could not connect to host
 siku.pro: could not connect to host
 silqueskineyeserum.com: could not connect to host
 silvistefi.com: could not connect to host
 sim4seed.org: could not connect to host
 simhaf.cf: could not connect to host
 simplerses.com: could not connect to host
 sims4hub.ga: could not connect to host
 sinfulforums.net: could not connect to host
 siqi.wang: could not connect to host
+sistem-maklumat.com: could not connect to host
 sistersurprise.de: could not connect to host
 sitemaxiphilippe.ch: could not connect to host
 skarox.ru: could not connect to host
 sky-aroma.com: could not connect to host
 skylocker.net: could not connect to host
 skylocker.nl: could not connect to host
 skyvault.io: could not connect to host
 slaps.be: could not connect to host
 slytech.ch: could not connect to host
-sm-supplements.gr: could not connect to host
 smallchat.nl: could not connect to host
 smartbiz.vn: could not connect to host
 smith.is: could not connect to host
 sml.lc: could not connect to host
 smuhelper.cn: could not connect to host
 sniderman.pro: could not connect to host
 sniderman.us: could not connect to host
 snowdy.eu: could not connect to host
 soboleva-pr.com.ua: could not connect to host
+soc.net: could not connect to host
 socialworkout.com: could not connect to host
 socialworkout.net: could not connect to host
 socialworkout.org: could not connect to host
 socialworkout.tv: could not connect to host
 socketize.com: could not connect to host
 sogravatas.net.br: could not connect to host
 sojingle.net: could not connect to host
+solariiknight.org: could not connect to host
 soldout-app.com: could not connect to host
 solymar.co: could not connect to host
 sonafe.info: could not connect to host
 sonja-kowa.de: could not connect to host
 soontm.de: could not connect to host
 sorenam.com: could not connect to host
 sortaweird.net: could not connect to host
 sowingseasons.com: could not connect to host
@@ -1833,38 +1871,37 @@ tapestries.tk: could not connect to host
 tarek.link: could not connect to host
 tazemama.biz: could not connect to host
 tcpweb.net: could not connect to host
 tdelmas.eu: could not connect to host
 tdelmas.ovh: could not connect to host
 tdsb.cf: could not connect to host
 tdsbhack.tk: could not connect to host
 teacherph.net: could not connect to host
-teamdaylo.xyz: could not connect to host
 tebieer.com: could not connect to host
 techask.it: could not connect to host
 techiehall.com: could not connect to host
 techpit.us: could not connect to host
 techshift.se: could not connect to host
 tektoria.de: could not connect to host
 telekollektiv.org: could not connect to host
+tenberg.com: could not connect to host
 tenispopular.com: could not connect to host
-teodio.cl: could not connect to host
 terra-x.net: could not connect to host
 terrax.net: could not connect to host
 testadron.com: could not connect to host
 testovaci.ml: could not connect to host
 tgod.co: could not connect to host
 thaigirls.xyz: could not connect to host
 the-digitale.com: could not connect to host
 the-finance-blog.com: could not connect to host
 the-gist.io: could not connect to host
 the-pcca.org: could not connect to host
 thebte.com: could not connect to host
-thecozycastle.com: could not connect to host
+thecuriouscat.net: could not connect to host
 thedailyupvote.com: could not connect to host
 thedarkartsandcrafts.com: could not connect to host
 theeducationchannel.info: could not connect to host
 theeducationdirectory.org: could not connect to host
 thefox.co: could not connect to host
 thefrk.xyz: could not connect to host
 thelostyankee.com: could not connect to host
 thenrdhrd.nl: could not connect to host
@@ -1873,16 +1910,17 @@ theprincegame.com: could not connect to 
 theprivacysolution.com: could not connect to host
 thequillmagazine.org: could not connect to host
 thermique.ch: could not connect to host
 thesehighsandlows.com: could not connect to host
 theserver201.tk: could not connect to host
 thetapirsmouth.com: could not connect to host
 thevoid.one: could not connect to host
 thinkcash.nl: could not connect to host
+thismumdoesntknowbest.com: could not connect to host
 thompsonfamily.cloud: could not connect to host
 threatcentral.io: could not connect to host
 thxandbye.de: could not connect to host
 thynx.io: could not connect to host
 tianxicaipiao.com: could not connect to host
 tianxicaipiao.win: could not connect to host
 tianxicp.com: could not connect to host
 tibovanheule.site: could not connect to host
@@ -1927,17 +1965,16 @@ tucidi.net: could not connect to host
 tupizm.com: could not connect to host
 turismo.cl: could not connect to host
 turkiet.guide: could not connect to host
 turn-sticks.com: could not connect to host
 tutiendaroja.com: could not connect to host
 tutiendarosa.com: could not connect to host
 tutoragency.org: could not connect to host
 tuvangoicuoc.com: could not connect to host
-tuxflow.de: could not connect to host
 tuxhound.org: could not connect to host
 twinkieman.com: could not connect to host
 twiri.net: could not connect to host
 twittelzie.nl: could not connect to host
 twitter.ax: could not connect to host
 twotube.ie: could not connect to host
 tykoon.com: could not connect to host
 tylerharcourt.com: could not connect to host
@@ -1953,16 +1990,17 @@ ulalau.com: could not connect to host
 ulti.gq: could not connect to host
 unefuite.ch: could not connect to host
 unhu.fr: could not connect to host
 uni2share.com: could not connect to host
 unicorn.li: could not connect to host
 uniformespousoalegre.com.br: could not connect to host
 uploadbro.com: could not connect to host
 upmchealthsecurity.us: could not connect to host
+urbanwildlifealliance.org: could not connect to host
 urcentral.org: could not connect to host
 usafuelservice.com: could not connect to host
 uscp8.com: could not connect to host
 usportsgo.com: could not connect to host
 uwesander.de: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 115"  data: no]
 uwimonacs.org.jm: could not connect to host
 uygindir.ml: could not connect to host
 vaaddress.co: could not connect to host
@@ -1971,25 +2009,26 @@ vadik.me: could not connect to host
 valecnatechnika.cz: could not connect to host
 valenhub.com: could not connect to host
 valenhub.es: could not connect to host
 valis.sx: could not connect to host
 vamosfalardesaude.pt: could not connect to host
 vanderstraeten.dynv6.net: could not connect to host
 varela-electricite.fr: could not connect to host
 varta.io: could not connect to host
+vasyharan.com: could not connect to host
 vayaport.com: could not connect to host
 vconcept.ch: could not connect to host
 vconcept.me: could not connect to host
+vectro.me: could not connect to host
 velen.io: could not connect to host
 venicecomputerrepair.com: could not connect to host
 venicefloridawebsitedesign.com: could not connect to host
 venturavwparts.com: could not connect to host
 verdeandco.co.uk: could not connect to host
-vernonfigureskatingclub.com: could not connect to host
 versfin.net: could not connect to host
 veryyounglesbians.com: could not connect to host
 vgatest.nl: could not connect to host
 vicenage.com: could not connect to host
 viciousviscosity.xyz: could not connect to host
 videorullen.se: could not connect to host
 vidiproject.com: could not connect to host
 vikasbabyworld.de: could not connect to host
@@ -2072,17 +2111,16 @@ wilhelm-nathan.de: could not connect to 
 willkommen-fuerstenberg.de: could not connect to host
 winnersports.co: could not connect to host
 winsufi.biz: could not connect to host
 wisak.eu: could not connect to host
 wishesbee.com: could not connect to host
 wissl.org: could not connect to host
 wizznab.tk: could not connect to host
 wk577.com: could not connect to host
-wlog.it: could not connect to host
 wmawri.com: could not connect to host
 wolfemg.com: could not connect to host
 wollongongbaptist.hopto.org: could not connect to host
 wonderbooks.club: could not connect to host
 woomu.me: could not connect to host
 wordsofamaster.com: could not connect to host
 workemy.com: could not connect to host
 worldfree4.org: could not connect to host
@@ -2115,21 +2153,19 @@ xn--yj8h0m.ws: could not connect to host
 xn--ykrp42k.com: could not connect to host
 xpwn.cz: could not connect to host
 xtom.io: could not connect to host
 xuntaosms.com: could not connect to host
 xwaretech.info: could not connect to host
 xyfun.net: could not connect to host
 y3451.com: could not connect to host
 yabrt.cn: could not connect to host
-yagihiro.tech: could not connect to host
 yahoo.ax: could not connect to host
 yarchives.jp: could not connect to host
 yaucy.win: could not connect to host
-ybresson.com: could not connect to host
 yd.io: could not connect to host
 yellowcar.website: could not connect to host
 yemalu.com: could not connect to host
 yemekbaz.az: could not connect to host
 yepbitcoin.com: could not connect to host
 yesfone.com.br: could not connect to host
 yggdar.ga: could not connect to host
 yhori.xyz: could not connect to host
@@ -2151,17 +2187,16 @@ yum.beer: could not connect to host
 yurimoens.be: could not connect to host
 yux.fr: could not connect to host
 yveshield.com: could not connect to host
 z0rro.net: could not connect to host
 zachbolinger.com: could not connect to host
 zaoext.com: could not connect to host
 zbchen.com: could not connect to host
 zeitzer-turngala.de: could not connect to host
-zemlova.cz: could not connect to host
 zenghx.tk: could not connect to host
 zero-x-baadf00d.com: could not connect to host
 zerosource.net: could not connect to host
 zertif.info: could not connect to host
 zeug.co: could not connect to host
 zhangfangzhou.com: could not connect to host
 zhangsir.net: could not connect to host
 zhaochen.xyz: could not connect to host
@@ -2228,17 +2263,17 @@ 12vpnchina.com: could not connect to hos
 1391kj.com: did not receive HSTS header
 1396.cc: did not receive HSTS header
 1536.cf: could not connect to host
 163pwd.com: could not connect to host
 16deza.com: did not receive HSTS header
 16packets.com: could not connect to host
 173vpn.cn: could not connect to host
 173vpns.com: did not receive HSTS header
-173vpnv.com: did not receive HSTS header
+173vpnv.com: could not connect to host
 188betwarriors.co.uk: could not connect to host
 188trafalgar.ca: did not receive HSTS header
 195gm.com: could not connect to host
 1a-jva.de: could not connect to host
 1atic.com: could not connect to host
 1co-jp.net: did not receive HSTS header
 1cover.com: could not connect to host
 1k8b.com: could not connect to host
@@ -2472,17 +2507,16 @@ aether.pw: could not connect to host
 aevpn.net: could not connect to host
 aeyoun.com: did not receive HSTS header
 af-fotografie.net: did not receive HSTS header
 afdkompakt.de: max-age too low: 86400
 aficotroceni.ro: did not receive HSTS header
 afiru.net: could not connect to host
 afmchandler.com: did not receive HSTS header
 afp548.tk: could not connect to host
-africantourer.com: did not receive HSTS header
 after.im: did not receive HSTS header
 afvallendoeje.nu: could not connect to host
 afyou.co.kr: could not connect to host
 agalaxyfarfaraway.co.uk: could not connect to host
 agatheetraphael.fr: could not connect to host
 agbremen.de: did not receive HSTS header
 agentseeker.ca: could not connect to host
 agevio.com: could not connect to host
@@ -2730,20 +2764,20 @@ aquariumaccessories.shop: did not receiv
 aquilalab.com: could not connect to host
 arabdigitalexpression.org: did not receive HSTS header
 aradulconteaza.ro: could not connect to host
 aran.me.uk: could not connect to host
 arboineuropa.nl: did not receive HSTS header
 arboleda-hurtado.com: could not connect to host
 arbu.eu: max-age too low: 2419200
 arcbit.io: did not receive HSTS header
-archii.ca: did not receive HSTS header
+archii.ca: could not connect to host
 architecte-interieur.be: did not receive HSTS header
 arcusnova.de: could not connect to host
-ardao.me: did not receive HSTS header
+ardao.me: could not connect to host
 ardorlabs.se: could not connect to host
 arewedubstepyet.com: did not receive HSTS header
 areyouever.me: did not receive HSTS header
 argennon.xyz: could not connect to host
 arguggi.co.uk: could not connect to host
 ariacreations.net: did not receive HSTS header
 arislight.com: could not connect to host
 arlatools.com: did not receive HSTS header
@@ -2798,17 +2832,17 @@ ass.org.au: could not connect to host
 assekuranzjobs.de: could not connect to host
 asset-alive.com: did not receive HSTS header
 asset-alive.net: did not receive HSTS header
 assurancesmons.be: did not receive HSTS header
 astraalivankila.net: did not receive HSTS header
 astral.gq: did not receive HSTS header
 astrolpost.com: could not connect to host
 astromelody.com: did not receive HSTS header
-asuhe.cc: did not receive HSTS header
+asuhe.cc: could not connect to host
 atacadodesandalias.com.br: did not receive HSTS header
 atavio.at: could not connect to host
 atavio.ch: could not connect to host
 atavio.de: did not receive HSTS header
 atbeckett.com: did not receive HSTS header
 atelier-rk.com: did not receive HSTS header
 ateliersantgervasi.com: did not receive HSTS header
 atencionbimbo.com: max-age too low: 86400
@@ -2875,21 +2909,21 @@ avantmfg.com: did not receive HSTS heade
 avastantivirus.ro: did not receive HSTS header
 avec-ou-sans-ordonnance.fr: could not connect to host
 aveling-adventure.co.uk: did not receive HSTS header
 avepol.cz: did not receive HSTS header
 avepol.eu: did not receive HSTS header
 aviacao.pt: did not receive HSTS header
 avidcruiser.com: did not receive HSTS header
 aviodeals.com: could not connect to host
-avmo.pw: did not receive HSTS header
+avmo.pw: could not connect to host
 avqueen.cn: could not connect to host
-avso.pw: did not receive HSTS header
+avso.pw: could not connect to host
 avus-automobile.com: did not receive HSTS header
-avxo.pw: did not receive HSTS header
+avxo.pw: could not connect to host
 awanderlustadventure.com: did not receive HSTS header
 awg-mode.de: did not receive HSTS header
 aww.moe: did not receive HSTS header
 axado.com.br: did not receive HSTS header
 axelchv.fr: did not receive HSTS header
 axeny.com: did not receive HSTS header
 axolsoft.com: max-age too low: 10540800
 ayahuascaadvisor.com: could not connect to host
@@ -2949,17 +2983,17 @@ banbanchs.com: could not connect to host
 banchethai.com: could not connect to host
 bandb.xyz: could not connect to host
 bandrcrafts.com: did not receive HSTS header
 bangzafran.com: did not receive HSTS header
 bankmilhas.com.br: did not receive HSTS header
 banksaround.com: did not receive HSTS header
 banqingdiao.com: could not connect to host
 baobaobooks.net: did not receive HSTS header
-baobeiglass.com: could not connect to host
+baobeiglass.com: did not receive HSTS header
 barcel.com.mx: max-age too low: 86400
 barely.sexy: did not receive HSTS header
 barrelhead.org: could not connect to host
 barrut.me: did not receive HSTS header
 barshout.co.uk: could not connect to host
 bartbania.com: did not receive HSTS header
 barunisystems.com: could not connect to host
 bashcode.ninja: could not connect to host
@@ -2967,16 +3001,17 @@ basicsolutionsus.com: did not receive HS
 basilisk.io: could not connect to host
 basketsbymaurice.com: did not receive HSTS header
 baskettemple.com: did not receive HSTS header
 bassh.net: did not receive HSTS header
 baud.ninja: could not connect to host
 baudairenergyservices.com: did not receive HSTS header
 baum.ga: could not connect to host
 baumstark.ca: could not connect to host
+bayinstruments.com: did not receive HSTS header
 baysse.eu: could not connect to host
 bazarstupava.sk: could not connect to host
 bazisszoftver.hu: did not receive HSTS header
 bb-shiokaze.jp: did not receive HSTS header
 bblovess.cn: could not connect to host
 bbrinck.eu: could not connect to host
 bbuio.com: max-age too low: 86400
 bbwdom.xyz: could not connect to host
@@ -2993,16 +3028,17 @@ bcnx.de: max-age too low: 0
 bcsytv.com: could not connect to host
 bcweightlifting.ca: could not connect to host
 bddemir.com: could not connect to host
 bde-epitech.fr: could not connect to host
 be-real.life: did not receive HSTS header
 beach-inspector.com: did not receive HSTS header
 beachi.es: could not connect to host
 beaglewatch.com: could not connect to host
+beanworks.ca: did not receive HSTS header
 bearden.io: did not receive HSTS header
 beardydave.com: did not receive HSTS header
 beastlog.tk: could not connect to host
 beastowner.com: did not receive HSTS header
 beavers.io: could not connect to host
 bebeefy.uk: could not connect to host
 bebesurdoue.com: could not connect to host
 bedabox.com: max-age too low: 0
@@ -3053,17 +3089,16 @@ bestcellular.com: did not receive HSTS h
 besthost.cz: did not receive HSTS header
 bestmodels.su: did not receive HSTS header
 bestof1001.de: could not connect to host
 bestorangeseo.com: could not connect to host
 betaclean.fr: did not receive HSTS header
 betafive.net: could not connect to host
 betakah.net: could not connect to host
 betcafearena.ro: did not receive HSTS header
-bethanyduke.com: did not receive HSTS header
 bethditto.com: did not receive HSTS header
 betnet.fr: could not connect to host
 betplanning.it: did not receive HSTS header
 bets.de: did not receive HSTS header
 bets.gg: did not receive HSTS header
 betterlifemakers.com: max-age too low: 200
 bettween.com: did not receive HSTS header
 betz.ro: did not receive HSTS header
@@ -3124,16 +3159,17 @@ biophysik-ssl.de: did not receive HSTS h
 birgitandmerlin.com: did not receive HSTS header
 birkman.com: did not receive HSTS header
 bismarck.moe: did not receive HSTS header
 bisterfeldt.com: could not connect to host
 bitbit.org: did not receive HSTS header
 bitbr.net: did not receive HSTS header
 bitcantor.com: did not receive HSTS header
 bitchan.it: could not connect to host
+bitcoinhk.org: did not receive HSTS header
 bitcoinprivacy.net: did not receive HSTS header
 bitcoinworld.me: did not receive HSTS header
 bitconcepts.co.uk: could not connect to host
 biteoftech.com: did not receive HSTS header
 bitf.ly: could not connect to host
 bitfactory.ws: could not connect to host
 bitfarm-archiv.com: did not receive HSTS header
 bitfarm-archiv.de: did not receive HSTS header
@@ -3178,16 +3214,17 @@ blocksatz-medien.de: could not connect t
 blog-ritaline.com: could not connect to host
 blog.coffee: could not connect to host
 blog.cyveillance.com: did not receive HSTS header
 blog.torproject.org: max-age too low: 1000
 bloglife-bb.com: did not receive HSTS header
 bloglikepro.com: could not connect to host
 blognone.com: did not receive HSTS header
 blogonblogspot.com: did not receive HSTS header
+blok56.nl: did not receive HSTS header
 bloomnbud.com: did not receive HSTS header
 bloomzoomy.ru: max-age too low: 172800
 blowjs.com: could not connect to host
 bls-fiduciaire.be: did not receive HSTS header
 bltc.co: could not connect to host
 blubbablasen.de: could not connect to host
 blucas.org: did not receive HSTS header
 blue17.co.uk: did not receive HSTS header
@@ -3241,17 +3278,17 @@ borscheid-wenig.com: did not receive HST
 boschee.net: could not connect to host
 botox.bz: did not receive HSTS header
 botstack.host: did not receive HSTS header
 bounceboxspc.com: did not receive HSTS header
 bouncecoffee.com: did not receive HSTS header
 bouncelanduk.co.uk: did not receive HSTS header
 bouncycastleandparty.co.uk: did not receive HSTS header
 bourhis.info: did not receive HSTS header
-bouwbedrijfpurmerend.nl: could not connect to host
+bouwbedrijfpurmerend.nl: did not receive HSTS header
 bowlroll.net: max-age too low: 0
 boxcryptor.com: did not receive HSTS header
 boxing-austria.eu: did not receive HSTS header
 boxlitepackaging.com: did not receive HSTS header
 boyan.in: could not connect to host
 boyfriendhusband.men: did not receive HSTS header
 bp-wahl.at: did not receive HSTS header
 bqtoolbox.com: could not connect to host
@@ -3298,25 +3335,24 @@ brunohenc.from.hr: could not connect to 
 brunoonline.co.uk: could not connect to host
 bryn.xyz: could not connect to host
 bs12v.ru: did not receive HSTS header
 bsdtips.com: could not connect to host
 bsklabels.com: did not receive HSTS header
 btc-e.com: did not receive HSTS header
 btcdlc.com: could not connect to host
 btcpot.ltd: did not receive HSTS header
-btio.pw: did not receive HSTS header
+btio.pw: could not connect to host
 btxiaobai.com: did not receive HSTS header
 buben.tech: did not receive HSTS header
 bubulazi.com: did not receive HSTS header
 bubulazy.com: did not receive HSTS header
 buch-cuber.de: max-age too low: 0
 buchheld.at: did not receive HSTS header
 bucket.tk: could not connect to host
-buderus-family.be: did not receive HSTS header
 budgetthostels.nl: did not receive HSTS header
 budskap.eu: did not receive HSTS header
 buenosairesestetica.com.ar: could not connect to host
 bugtrack.io: could not connect to host
 bugwie.com: did not receive HSTS header
 buhler.pro: did not receive HSTS header
 buildci.asia: could not connect to host
 buildify.co.za: could not connect to host
@@ -3501,17 +3537,16 @@ ccretreatandfarm.com: did not receive HS
 cctech.ph: did not receive HSTS header
 cd0.us: could not connect to host
 cdnb.co: could not connect to host
 cdndepo.com: could not connect to host
 cdreporting.co.uk: did not receive HSTS header
 cdt.org: did not receive HSTS header
 ce-agentur.de: did not receive HSTS header
 cecilwalker.com.au: did not receive HSTS header
-celebphotos.blog: did not receive HSTS header
 celeirorural.com.br: did not receive HSTS header
 celina-reads.de: did not receive HSTS header
 cellsites.nz: could not connect to host
 centennialrewards.com: did not receive HSTS header
 centralpoint.be: did not receive HSTS header
 centralpoint.nl: did not receive HSTS header
 centralvacsunlimited.net: did not receive HSTS header
 centralync.com: could not connect to host
@@ -3800,17 +3835,16 @@ contactbig.com: did not receive HSTS hea
 contaimo.com: did not receive HSTS header
 container-lion.com: did not receive HSTS header
 containerstatistics.com: could not connect to host
 contarkos.xyz: could not connect to host
 content-design.de: did not receive HSTS header
 continuumgaming.com: could not connect to host
 contraspin.co.nz: did not receive HSTS header
 controlcenter.gigahost.dk: did not receive HSTS header
-controleer-maar-een-ander.nl: did not receive HSTS header
 convert.zone: did not receive HSTS header
 cooink.net: could not connect to host
 coolaj86.com: did not receive HSTS header
 coolbutbroken.com: did not receive HSTS header
 coolchevy.org.ua: did not receive HSTS header
 coole-meister.de: could not connect to host
 cooxa.com: did not receive HSTS header
 copshop.com.br: could not connect to host
@@ -3943,17 +3977,17 @@ cuongthach.com: did not receive HSTS hea
 curlyroots.com: did not receive HSTS header
 curroapp.com: could not connect to host
 curveweb.co.uk: did not receive HSTS header
 cusfit.com: did not receive HSTS header
 custe.rs: could not connect to host
 customadesign.com: did not receive HSTS header
 cutorrent.com: could not connect to host
 cuvva.insure: did not receive HSTS header
-cvjm-memmingen.de: could not connect to host
+cvjm-memmingen.de: did not receive HSTS header
 cvtparking.co.uk: did not receive HSTS header
 cwage.com: could not connect to host
 cyanogenmod.xxx: could not connect to host
 cyber-konzept.de: did not receive HSTS header
 cybercecurity.com: did not receive HSTS header
 cyberfrancais.ro: did not receive HSTS header
 cyberlab.kiev.ua: did not receive HSTS header
 cyberlab.team: did not receive HSTS header
@@ -4100,27 +4134,26 @@ dekasan.ru: could not connect to host
 delayrefunds.co.uk: could not connect to host
 deliverance.co.uk: could not connect to host
 deltaconcepts.de: did not receive HSTS header
 delvj.org: could not connect to host
 demdis.org: could not connect to host
 demilitarized.ninja: could not connect to host
 demo-server.us: could not connect to host
 demo.swedbank.se: did not receive HSTS header
-demomanca.com: could not connect to host
+demomanca.com: did not receive HSTS header
 demotops.com: could not connect to host
 dempsters.ca: max-age too low: 86400
 denh.am: did not receive HSTS header
 denisjean.fr: could not connect to host
 dentaldomain.org: did not receive HSTS header
 dentaldomain.ph: did not receive HSTS header
 denvercybersecurity.com: did not receive HSTS header
 denverprophit.us: did not receive HSTS header
 deped.blog: did not receive HSTS header
-depedtayo.com: did not receive HSTS header
 depijl-mz.nl: did not receive HSTS header
 depixion.agency: could not connect to host
 depo.space: could not connect to host
 dequehablamos.es: could not connect to host
 derbyshiredotnet.co.uk: did not receive HSTS header
 derevtsov.com: did not receive HSTS header
 derpumpkinfuhrer.com: could not connect to host
 derrickemery.com: did not receive HSTS header
@@ -4219,16 +4252,17 @@ diva-ey.com: could not connect to host
 diversity-spielzeug.de: did not receive HSTS header
 divvymonkey.com: did not receive HSTS header
 divvyradio.com: did not receive HSTS header
 dixiediner.com: did not receive HSTS header
 diyvideoeditor.com: did not receive HSTS header
 dizihocasi.com: could not connect to host
 dizorg.net: could not connect to host
 dj4et.de: could not connect to host
+djangogolf.com: did not receive HSTS header
 djieno.com: did not receive HSTS header
 djxmmx.net: did not receive HSTS header
 djz4music.com: did not receive HSTS header
 dkniss.de: could not connect to host
 dlc.viasinc.com: could not connect to host
 dlemper.de: did not receive HSTS header
 dmcibulldog.com: did not receive HSTS header
 dmix.ca: could not connect to host
@@ -4368,16 +4402,17 @@ dudesunderwear.com.br: could not connect
 duelysthub.com: could not connect to host
 dukec.me: did not receive HSTS header
 dullsir.com: did not receive HSTS header
 dune.io: did not receive HSTS header
 dunea.nl: did not receive HSTS header
 duole30.com: did not receive HSTS header
 duongpho.com: did not receive HSTS header
 duskopy.top: could not connect to host
+dutchessuganda.com: did not receive HSTS header
 dutchrank.com: did not receive HSTS header
 duuu.ch: could not connect to host
 duyao.de: max-age too low: 86400
 dv189.com: did not receive HSTS header
 dycem-ns.com: did not receive HSTS header
 dycontrol.de: could not connect to host
 dylanscott.com.au: did not receive HSTS header
 dymersion.com: did not receive HSTS header
@@ -4473,24 +4508,26 @@ eengezinswoningverkopen.nl: could not co
 eenhoorn.ga: could not connect to host
 eesistumine2017.ee: could not connect to host
 efficienthealth.com: did not receive HSTS header
 effortlesshr.com: did not receive HSTS header
 eftcorp.biz: did not receive HSTS header
 egge.com: max-age too low: 0
 egit.co: could not connect to host
 ego-world.org: could not connect to host
+egupova.ru: did not receive HSTS header
 ehealthcounselor.com: could not connect to host
 ehipaadev.com: could not connect to host
 ehito.ovh: could not connect to host
 ehrenamt-skpfcw.de: could not connect to host
 eicfood.com: could not connect to host
 eidolonhost.com: did not receive HSTS header
 eifelindex.de: did not receive HSTS header
 eigo.work: could not connect to host
+eimanavicius.lt: did not receive HSTS header
 einhorn.space: could not connect to host
 ekbanden.nl: could not connect to host
 eksik.com: did not receive HSTS header
 el-soul.com: did not receive HSTS header
 elaintehtaat.fi: could not connect to host
 elan-organics.com: did not receive HSTS header
 elanguest.pl: could not connect to host
 elanguest.ro: could not connect to host
@@ -4672,16 +4709,17 @@ euph.eu: did not receive HSTS header
 eupho.me: could not connect to host
 eupresidency2018.com: did not receive HSTS header
 euren.se: could not connect to host
 eurocamping.se: could not connect to host
 euroshop24.net: could not connect to host
 eurospecautowerks.com: did not receive HSTS header
 evafojtova.cz: did not receive HSTS header
 evanhandgraaf.nl: did not receive HSTS header
+evantage.org: did not receive HSTS header
 evdenevenakliyatankara.pw: could not connect to host
 evecalm.com: did not receive HSTS header
 events12.com: did not receive HSTS header
 eventsafrica.net: did not receive HSTS header
 everybooks.com: could not connect to host
 everydaytherich.com: max-age too low: 7776000
 everygayporn.xyz: did not receive HSTS header
 everylab.org: could not connect to host
@@ -4916,17 +4954,16 @@ flow.pe: could not connect to host
 flowersandclouds.com: could not connect to host
 floweslawncare.com: did not receive HSTS header
 flowlo.me: could not connect to host
 fluidojobs.com: could not connect to host
 flukethoughts.com: did not receive HSTS header
 flurrybridge.com: did not receive HSTS header
 flushstudios.com: did not receive HSTS header
 flyaces.com: could not connect to host
-flyspace.ga: did not receive HSTS header
 fm83.nl: could not connect to host
 fm992.com: did not receive HSTS header
 fnvsecurity.com: could not connect to host
 fobc-usa.org: did not receive HSTS header
 foerster-kunststoff.de: did not receive HSTS header
 fojtova.cz: did not receive HSTS header
 fojtovi.cz: did not receive HSTS header
 fokan.ch: did not receive HSTS header
@@ -4985,16 +5022,17 @@ franta.email: did not receive HSTS heade
 franzt.de: could not connect to host
 frasesdeamizade.pt: could not connect to host
 frasys.io: did not receive HSTS header
 fraudempire.com: could not connect to host
 freeasinlliure.org: did not receive HSTS header
 freeflow.tv: could not connect to host
 freekdevries.nl: did not receive HSTS header
 freelanced.co.za: could not connect to host
+freelandinnovation.com: did not receive HSTS header
 freelo.cz: did not receive HSTS header
 freematthale.net: did not receive HSTS header
 freesoftwaredriver.com: could not connect to host
 freethought.org.au: could not connect to host
 freeutopia.org: did not receive HSTS header
 freqlabs.com: did not receive HSTS header
 freshfind.xyz: could not connect to host
 freshlymind.com: did not receive HSTS header
@@ -5039,32 +5077,35 @@ funnyang.com: could not connect to host
 funrun.com: did not receive HSTS header
 funtastic-event-hire.co.uk: did not receive HSTS header
 fuorifuocogenova.it: did not receive HSTS header
 furiffic.com: did not receive HSTS header
 furnation.com: could not connect to host
 furry.be: did not receive HSTS header
 fusedrops.com: could not connect to host
 fusionmate.com: could not connect to host
-futbol11.com: could not connect to host
+futbol11.com: did not receive HSTS header
+futbolvivo.tv: did not receive HSTS header
 futurefundapp.com: did not receive HSTS header
 futurestarsusa.org: did not receive HSTS header
 futuretechnologi.es: could not connect to host
 futureyouhealth.com: did not receive HSTS header
+futuristarchitecture.com: did not receive HSTS header
 fuvpn.com: could not connect to host
 fws.gov: did not receive HSTS header
 fx-rk.com: did not receive HSTS header
 fyfywka.com: max-age too low: 86400
 fyodorpi.com: did not receive HSTS header
 fysiohaenraets.nl: did not receive HSTS header
 fzn.io: did not receive HSTS header
 fzslm.me: could not connect to host
 g-i-s.vn: did not receive HSTS header
 g-marketing.ro: did not receive HSTS header
 g-rickroll-o.pw: could not connect to host
+g-rom.net: did not receive HSTS header
 g2a.co: did not receive HSTS header
 g2g.com: did not receive HSTS header
 g5led.nl: could not connect to host
 g77.ca: could not connect to host
 gaanbaksho.com.au: did not receive HSTS header
 gabber.scot: could not connect to host
 gabi.com.es: could not connect to host
 gabi.soy: did not receive HSTS header
@@ -5140,17 +5181,16 @@ genesischangelog.com: did not receive HS
 genshiken.org: could not connect to host
 genuu.com: could not connect to host
 genuxation.com: could not connect to host
 genyaa.com: could not connect to host
 genyhitch.com: did not receive HSTS header
 geoffdev.com: could not connect to host
 geoffreyrichard.com: did not receive HSTS header
 geopals.net: did not receive HSTS header
-geoponika.gr: did not receive HSTS header
 george-brighton.co.uk: could not connect to host
 georgebrighton.co.uk: could not connect to host
 georgesonarthurs.com.au: did not receive HSTS header
 gereja.ga: could not connect to host
 gerencianet.com.br: did not receive HSTS header
 gereon.ch: could not connect to host
 gesiwista.net: could not connect to host
 gesunde-smoothies.de: did not receive HSTS header
@@ -5373,27 +5413,29 @@ gts-schulsoftware.de: did not receive HS
 guarajubaimoveis.com.br: did not receive HSTS header
 guava.studio: did not receive HSTS header
 guentherhouse.com: did not receive HSTS header
 guenthernoack.de: could not connect to host
 guffrits.com: could not connect to host
 guge.gq: could not connect to host
 gugga.dk: could not connect to host
 guguke.net: did not receive HSTS header
+guidetoiceland.is: did not receive HSTS header
 guilde-vindicta.fr: did not receive HSTS header
 guillaume-leduc.fr: did not receive HSTS header
 guillaumematheron.fr: did not receive HSTS header
 guineafruitcorp.com: could not connect to host
 gulch.in.ua: did not receive HSTS header
 gulenet.com: could not connect to host
 gulfcoast-sandbox.com: could not connect to host
 gunnarhafdal.com: did not receive HSTS header
 gunnaro.com: could not connect to host
 guntbert.net: could not connect to host
 guoqiang.info: did not receive HSTS header
+guozeyu.com: did not receive HSTS header
 gurom.lv: could not connect to host
 gurusupe.com: could not connect to host
 guso.gq: could not connect to host
 guso.ml: could not connect to host
 guso.site: could not connect to host
 guso.tech: could not connect to host
 gussi.is: did not receive HSTS header
 gvpt.sk: did not receive HSTS header
@@ -5776,16 +5818,17 @@ ierna.com: did not receive HSTS header
 ies-italia.it: did not receive HSTS header
 ies.id.lv: could not connect to host
 ievgenialehner.com: did not receive HSTS header
 ifad.org: did not receive HSTS header
 ifastuniversity.com: did not receive HSTS header
 ifleurs.com: could not connect to host
 ifx.ee: could not connect to host
 ifxor.com: did not receive HSTS header
+igd.chat: did not receive HSTS header
 igforums.com: could not connect to host
 igi.codes: did not receive HSTS header
 igiftcards.nl: did not receive HSTS header
 ignatisd.gr: did not receive HSTS header
 igule.net: could not connect to host
 ihotel.io: did not receive HSTS header
 ihrlotto.de: could not connect to host
 ihrnationalrat.ch: could not connect to host
@@ -5843,16 +5886,17 @@ imusic.dk: did not receive HSTS header
 inb4.us: could not connect to host
 inbox.li: did not receive HSTS header
 incendiary-arts.com: could not connect to host
 inche-ali.com: did not receive HSTS header
 inchomatic.com: did not receive HSTS header
 indiecert.net: could not connect to host
 indiemods.com: could not connect to host
 indien.guide: could not connect to host
+indilens.com: did not receive HSTS header
 indochina.io: could not connect to host
 indoorskiassen.nl: did not receive HSTS header
 indredouglas.me: could not connect to host
 industrybazar.com: max-age too low: 2592000
 ineed.com.mt: could not connect to host
 infcof.com: did not receive HSTS header
 infilock.com: could not connect to host
 infinitude.me.uk: could not connect to host
@@ -5937,17 +5981,17 @@ invinsec.cloud: did not receive HSTS hea
 inviosolutions.com: max-age too low: 0
 invite24.pro: could not connect to host
 invitethemhome.com: did not receive HSTS header
 iodice.org: did not receive HSTS header
 iolife.dk: could not connect to host
 ionas-law.ro: did not receive HSTS header
 iop.intuit.com: max-age too low: 86400
 iora.fr: could not connect to host
-iosmods.com: did not receive HSTS header
+iosmods.com: could not connect to host
 iostips.ru: could not connect to host
 ip-life.net: did not receive HSTS header
 ip6.im: did not receive HSTS header
 ipbill.org.uk: could not connect to host
 iplife.cn: could not connect to host
 ipmimagazine.com: did not receive HSTS header
 iprice.co.id: did not receive HSTS header
 iprice.hk: did not receive HSTS header
@@ -5975,16 +6019,17 @@ irland.guide: could not connect to host
 irmtrudjurke.de: did not receive HSTS header
 irstaxforumsonline.com: did not receive HSTS header
 irugs.ch: did not receive HSTS header
 irugs.co.uk: did not receive HSTS header
 irugs.com.sg: did not receive HSTS header
 irukandjilabs.com: could not connect to host
 irvinepa.org: max-age too low: 10540800
 is-a-furry.org: did not receive HSTS header
+isaackhor.com: did not receive HSTS header
 ischool.co.jp: did not receive HSTS header
 isdf.me: could not connect to host
 isef-eg.com: did not receive HSTS header
 iseulde.com: did not receive HSTS header
 ishadowsocks.ltd: could not connect to host
 ishangirdhar.com: could not connect to host
 ishillaryclintoninprisonyet.com: could not connect to host
 isitamor.pm: could not connect to host
@@ -6079,16 +6124,17 @@ jan-daniels.de: did not receive HSTS hea
 jan27.org: did not receive HSTS header
 janario.me: could not connect to host
 janbrodda.de: max-age too low: 2592000
 jangho.me: could not connect to host
 janking.de: could not connect to host
 janmachynka.cz: did not receive HSTS header
 jannyrijneveld.nl: did not receive HSTS header
 janus-engineering.de: did not receive HSTS header
+jap-nope.de: did not receive HSTS header
 japaripark.com: could not connect to host
 japlex.com: could not connect to host
 jaqen.ch: could not connect to host
 jaredbates.net: did not receive HSTS header
 jarivisual.com: did not receive HSTS header
 jarnail.ca: did not receive HSTS header
 jaroslavtrsek.cz: did not receive HSTS header
 jarsater.com: could not connect to host
@@ -6282,17 +6328,17 @@ kaanduman.com: did not receive HSTS head
 kaasbijwijn.nl: did not receive HSTS header
 kabinapp.com: could not connect to host
 kabuabc.com: could not connect to host
 kackscharf.de: could not connect to host
 kadioglumakina.com.tr: did not receive HSTS header
 kaela.design: could not connect to host
 kahopoon.net: could not connect to host
 kaika-hms.de: did not receive HSTS header
-kainz.bayern: did not receive HSTS header
+kainz.bayern: could not connect to host
 kaisers.de: did not receive HSTS header
 kaiyuewu.com: could not connect to host
 kaketalk.com: did not receive HSTS header
 kalami.nl: could not connect to host
 kaleidomarketing.com: did not receive HSTS header
 kambodja.guide: could not connect to host
 kamcvicit.sk: could not connect to host
 kamikano.com: could not connect to host
@@ -6315,16 +6361,17 @@ kashdash.ca: could not connect to host
 katalogakci.cz: did not receive HSTS header
 katiaetdavid.fr: could not connect to host
 katoju.co.jp: could not connect to host
 katproxy.al: could not connect to host
 katproxy.online: could not connect to host
 katproxy.site: could not connect to host
 katproxy.tech: could not connect to host
 katproxy.top: did not receive HSTS header
+katzen.me: did not receive HSTS header
 kaufkraftkiel.de: could not connect to host
 kauplusprofesional.com: did not receive HSTS header
 kausch.at: could not connect to host
 kavinvin.me: could not connect to host
 kcluster.io: could not connect to host
 kd-plus.pp.ua: could not connect to host
 kdata.it: did not receive HSTS header
 kdbx.online: could not connect to host
@@ -6702,17 +6749,16 @@ lightning-ashe.com: did not receive HSTS
 lightnovelsekai.com: could not connect to host
 lightpaste.com: could not connect to host
 lightworkerandempathsupport.com: max-age too low: 300
 lightworx.io: did not receive HSTS header
 lila.pink: did not receive HSTS header
 lilapmedia.com: did not receive HSTS header
 lillpopp.eu: max-age too low: 10
 lilpwny.com: could not connect to host
-lily-bearing.com: did not receive HSTS header
 lilycms.com: could not connect to host
 lim-light.com: did not receive HSTS header
 limalama.eu: max-age too low: 1
 limeyeti.com: could not connect to host
 limiteddata.co.uk: did not receive HSTS header
 limodo-shop.de: did not receive HSTS header
 limpens.net: did not receive HSTS header
 limpido.it: could not connect to host
@@ -6748,16 +6794,17 @@ listage.ovh: did not receive HSTS header
 litespeed.io: could not connect to host
 little.pw: did not receive HSTS header
 littlefreelibrary.org: did not receive HSTS header
 liujunyang.com: did not receive HSTS header
 livedemo.io: could not connect to host
 livej.am: could not connect to host
 liverewrite.com: could not connect to host
 liviababynet.com.br: could not connect to host
+livinghealthywithchocolate.com: did not receive HSTS header
 livrariahugodesaovitor.com.br: did not receive HSTS header
 lixiang.one: could not connect to host
 lixingcong.com: could not connect to host
 lkp111138.me: could not connect to host
 llamasweet.tech: could not connect to host
 loacg.com: did not receive HSTS header
 loadingdeck.com: did not receive HSTS header
 loadso.me: could not connect to host
@@ -7084,17 +7131,16 @@ mca2017.org: did not receive HSTS header
 mcard.vn: did not receive HSTS header
 mcb-bank.com: did not receive HSTS header
 mcc.re: could not connect to host
 mccarty.io: could not connect to host
 mcdonalds.ru: did not receive HSTS header
 mcga.media: could not connect to host
 mclab.su: max-age too low: 2592000
 mclist.it: could not connect to host
-mclyr.com: did not receive HSTS header
 mcmillansedationdentistry.com: did not receive HSTS header
 mcooperlaw.com: did not receive HSTS header
 mcuexchange.com: did not receive HSTS header
 mdfnet.se: did not receive HSTS header
 mdscomp.net: did not receive HSTS header
 meadowfenfarm.com: could not connect to host
 meat-education.com: could not connect to host
 mebio.us: could not connect to host
@@ -7102,17 +7148,16 @@ mecenat-cassous.com: did not receive HST
 mechmk1.me: did not receive HSTS header
 medallia.io: could not connect to host
 media-access.online: did not receive HSTS header
 mediacru.sh: could not connect to host
 mediafinancelab.org: did not receive HSTS header
 mediamag.am: max-age too low: 0
 mediawikicn.org: could not connect to host
 medienservice-fritz.de: did not receive HSTS header
-medifab.online: did not receive HSTS header
 medirich.co: could not connect to host
 meditek-dv.ru: could not connect to host
 mediterenopmaandag.nl: did not receive HSTS header
 medm-test.com: could not connect to host
 medzinenews.com: did not receive HSTS header
 meedoennoordkop.nl: did not receive HSTS header
 meedoenzaanstad.nl: did not receive HSTS header
 meetfinch.com: could not connect to host
@@ -7522,17 +7567,17 @@ n0psled.nl: could not connect to host
 n2x.in: could not connect to host
 n4l.pw: could not connect to host
 n8ch.net: could not connect to host
 nabru.co.uk: did not receive HSTS header
 nabu-bad-nauheim.de: did not receive HSTS header
 nabytko.cz: could not connect to host
 nacktetatsachen.at: did not receive HSTS header
 nadia.pt: could not connect to host
-nagios.by: could not connect to host
+nagios.by: did not receive HSTS header
 nagoya-kyuyo.com: could not connect to host
 naiharngym.com: did not receive HSTS header
 najedlo.sk: could not connect to host
 nakamastreamingcommunity.com: could not connect to host
 nakliyatsirketi.biz: could not connect to host
 nakuro.de: could not connect to host
 nalifornia.com: did not receive HSTS header
 nalinux.cz: did not receive HSTS header
@@ -7752,17 +7797,17 @@ novacraft.me: did not receive HSTS heade
 novaopcaofestas.com.br: could not connect to host
 novatrucking.de: could not connect to host
 novavoidhowl.com: did not receive HSTS header
 novelabs.de: could not connect to host
 novelabs.eu: could not connect to host
 novelshouse.com: did not receive HSTS header
 novtest.ru: did not receive HSTS header
 novurania.com: did not receive HSTS header
-nowak.ninja: did not receive HSTS header
+nowak.ninja: could not connect to host
 noworrywp.com: could not connect to host
 nowprotein.com: did not receive HSTS header
 nozoe.jp: could not connect to host
 npol.de: could not connect to host
 nq7.pl: could not connect to host
 nrechn.de: could not connect to host
 nrizzio.me: could not connect to host
 nrnjn.xyz: did not receive HSTS header
@@ -7775,16 +7820,17 @@ nu3.co.uk: could not connect to host
 nu3.com: did not receive HSTS header
 nu3.de: did not receive HSTS header
 nu3.dk: did not receive HSTS header
 nu3.fi: did not receive HSTS header
 nu3.fr: did not receive HSTS header
 nu3.no: did not receive HSTS header
 nu3.se: did not receive HSTS header
 nube.ninja: did not receive HSTS header
+nuevaimagenpublicidad.es: did not receive HSTS header
 nufla.de: could not connect to host
 nuiguru.me: could not connect to host
 nukenet.se: could not connect to host
 nukute.com: did not receive HSTS header
 null-pointer.eu: did not receive HSTS header
 null-sec.ru: could not connect to host
 null.cat: did not receive HSTS header
 null.tips: could not connect to host
@@ -8026,17 +8072,17 @@ pagerate.io: did not receive HSTS header
 pagetoimage.com: could not connect to host
 pahlawanpulsa.com: did not receive HSTS header
 paigeglass.com: did not receive HSTS header
 paino.cloud: could not connect to host
 paintingat.com: could not connect to host
 paisaone.com: did not receive HSTS header
 pajadam.me: did not receive HSTS header
 pajonzeck.de: could not connect to host
-paket.io: did not receive HSTS header
+paket.io: could not connect to host
 paku.me: could not connect to host
 palmer.im: could not connect to host
 pammbook.com: did not receive HSTS header
 pamplona.tv: could not connect to host
 pamsoft.pl: max-age too low: 0
 pan.tips: could not connect to host
 panaceallc.net: could not connect to host
 panama-gbs.com: did not receive HSTS header
@@ -8059,17 +8105,17 @@ paperwallets.io: did not receive HSTS he
 papierniak.net: could not connect to host
 papygeek.com: could not connect to host
 parabhairavayoga.com: max-age too low: 0
 paradependentesquimicos.com.br: did not receive HSTS header
 paragon.edu: did not receive HSTS header
 parent5446.us: could not connect to host
 parentmail.co.uk: did not receive HSTS header
 parfum-baza.ru: did not receive HSTS header
-paris-cyber.fr: did not receive HSTS header
+paris-cyber.fr: could not connect to host
 parisvox.info: did not receive HSTS header
 parithy.net: could not connect to host
 parkingplus.co.il: could not connect to host
 parkrocker.com: max-age too low: 604800
 parkwithark.com: could not connect to host
 parodybit.net: did not receive HSTS header
 parpaing-paillette.net: could not connect to host
 particonpsplus.it: could not connect to host
@@ -8138,16 +8184,17 @@ peekops.com: could not connect to host
 peerherrmann.de: could not connect to host
 peissen.com: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 115"  data: no]
 pekkapikkarainen.fi: did not receive HSTS header
 pekkarik.ru: could not connect to host
 peliculasaudiolatinoonline.com: could not connect to host
 peliseries24.com: did not receive HSTS header
 pemberton.at: did not receive HSTS header
 penablog.com: did not receive HSTS header
+pencillab.cn: did not receive HSTS header
 pengui.uk: could not connect to host
 penguinclientsystem.com: did not receive HSTS header
 pennylane.me.uk: did not receive HSTS header
 pensanisso.com: max-age too low: 2592000
 pentagram.me: max-age too low: 2592000
 pentano.net: could not connect to host
 people-mozilla.org: could not connect to host
 peperiot.com: did not receive HSTS header
@@ -8207,16 +8254,18 @@ phonenumberinfo.co.uk: could not connect
 phongmay24h.com: could not connect to host
 phood.be: did not receive HSTS header
 photoblogverona.com: could not connect to host
 photoboothpartyhire.co.uk: did not receive HSTS header
 phototag.org: did not receive HSTS header
 php-bach.org: could not connect to host
 phperformances.fr: did not receive HSTS header
 phrasing.me: could not connect to host
+phuket-idc.com: did not receive HSTS header
+phuket-idc.de: did not receive HSTS header
 physicaltherapist.com: did not receive HSTS header
 pi-eng.fr: did not receive HSTS header
 pianetaottica.net: could not connect to host
 pianetaottica.org: could not connect to host
 picardiascr.com: did not receive HSTS header
 pickersurvey.org: could not connect to host
 pickr.co: did not receive HSTS header
 picotronic.biz: could not connect to host
@@ -8281,16 +8330,17 @@ pleasure.forsale: could not connect to h
 pleier-it.de: did not receive HSTS header
 pleier.it: did not receive HSTS header
 plfgr.eu.org: could not connect to host
 plhdb.org: did not receive HSTS header
 plirt.ru: could not connect to host
 plixer.com: did not receive HSTS header
 plogable.co: could not connect to host
 plombirator.kz: did not receive HSTS header
+plongee-phuket.fr: did not receive HSTS header
 plothost.com: did not receive HSTS header
 ploup.net: could not connect to host
 ploxel.com: did not receive HSTS header
 pluff.nl: did not receive HSTS header
 plur.com.au: did not receive HSTS header
 plus-digital.net: did not receive HSTS header
 plus-u.com.au: did not receive HSTS header
 plut.org: could not connect to host
@@ -8337,17 +8387,16 @@ popi.se: did not receive HSTS header
 popkins.ml: could not connect to host
 poris.web.id: could not connect to host
 pornstars.me: did not receive HSTS header
 portalm.tk: could not connect to host
 portalplatform.net: could not connect to host
 portaluniversalista.org: could not connect to host
 poshpak.com: max-age too low: 86400
 postcodewise.co.uk: did not receive HSTS header
-posterspy.com: did not receive HSTS header
 postscheduler.org: could not connect to host
 posylka.de: did not receive HSTS header
 potatoheads.net: could not connect to host
 potentialproject.com: did not receive HSTS header
 potsky.com: did not receive HSTS header
 pottshome.co.uk: did not receive HSTS header
 pourmesloisirs.com: did not receive HSTS header
 poussinooz.fr: could not connect to host
@@ -8445,17 +8494,16 @@ proxybay.al: could not connect to host
 proxybay.club: could not connect to host
 proxybay.info: did not receive HSTS header
 proxybay.top: did not receive HSTS header
 proxydesk.net: could not connect to host
 proxyowl.pw: could not connect to host
 proxyportal.me: did not receive HSTS header
 proxyrox.com: could not connect to host
 proxyweb.us: did not receive HSTS header
-prstatic.com: did not receive HSTS header
 prxio.date: could not connect to host
 prxio.site: could not connect to host
 pscleaningsolutions.co.uk: could not connect to host
 pshostpk.com: did not receive HSTS header
 psicologia.co.ve: could not connect to host
 psicologoforensebarcelona.com: did not receive HSTS header
 pstudio.me: did not receive HSTS header
 psw.academy: could not connect to host
@@ -8590,27 +8638,26 @@ rate-esport.de: could not connect to hos
 rationem.nl: did not receive HSTS header
 ratuseks.com: could not connect to host
 ratuseks.net: could not connect to host
 ratuseks.us: could not connect to host
 rauchenwald.net: did not receive HSTS header
 raulfraile.net: could not connect to host
 ravage.fm: did not receive HSTS header
 raven.lipetsk.ru: could not connect to host
-ravenger.net: did not receive HSTS header
 ravengergaming.ga: did not receive HSTS header
 ravkr.duckdns.org: max-age too low: 360000
 raw-diets.com: did not receive HSTS header
 rawet.se: could not connect to host
 rawoil.com: could not connect to host
 rawstorieslondon.com: could not connect to host
 raydan.space: could not connect to host
 raydobe.me: could not connect to host
 raytron.org: could not connect to host
-razeencheng.com: could not connect to host
+razeencheng.com: did not receive HSTS header
 razlaw.name: did not receive HSTS header
 razzolini.com.br: could not connect to host
 rbhighinc.org: could not connect to host
 rbose.org: could not connect to host
 rbqcloud.com: could not connect to host
 rbti.me: could not connect to host
 rc-rp.com: did not receive HSTS header
 rc4.io: could not connect to host
@@ -8662,16 +8709,17 @@ regenbogenwald.de: did not receive HSTS 
 regenerescence.com: did not receive HSTS header
 reggae-cdmx.com: could not connect to host
 regionale.org: did not receive HSTS header
 registertovoteflorida.gov: did not receive HSTS header
 rehabthailand.nl: could not connect to host
 reic.me: could not connect to host
 reidascuecas.com.br: could not connect to host
 reikiqueen.uk: could not connect to host
+reimann.me: did not receive HSTS header
 reisyukaku.org: did not receive HSTS header
 reithguard-it.de: did not receive HSTS header
 rejo.in: could not connect to host
 rejuvemedspa.com: did not receive HSTS header
 relayawards.com: could not connect to host
 reldoc.com.mx: did not receive HSTS header
 reliable-mail.de: could not connect to host
 relisten.nl: did not receive HSTS header
@@ -8887,16 +8935,17 @@ sageth.com: max-age too low: 0
 sah3.net: could not connect to host
 saharalondon.com: max-age too low: 0
 saharmassachi.com: could not connect to host
 saigonstar.de: did not receive HSTS header
 sail-nyc.com: did not receive HSTS header
 saint-astier-triathlon.com: did not receive HSTS header
 saintjohnlutheran.church: did not receive HSTS header
 sairai.bid: could not connect to host
+sajamstudija.info: did not receive HSTS header
 sakaki.anime.my: max-age too low: 5184000
 sakaserver.com: did not receive HSTS header
 sakib.ninja: did not receive HSTS header
 sakurabuff.com: could not connect to host
 saleslift.pl: did not receive HSTS header
 salserocafe.com: did not receive HSTS header
 salserototal.com: could not connect to host
 saltedskies.com: could not connect to host
@@ -8940,16 +8989,17 @@ satriyowibowo.my.id: could not connect t
 satsukii.moe: did not receive HSTS header
 saturne.tk: could not connect to host
 saturngames.co.uk: did not receive HSTS header
 saucyfox.net: did not receive HSTS header
 saudeeconforto.com.br: did not receive HSTS header
 saumon.xyz: could not connect to host
 saunasandstuff.ca: did not receive HSTS header
 saunasandstuff.com: did not receive HSTS header
+savacloud.com: did not receive HSTS header
 save.gov: could not connect to host
 saveaward.gov: could not connect to host
 saveyour.biz: could not connect to host
 savingrecipe.com: did not receive HSTS header
 savisasolutions.co.za: did not receive HSTS header
 savvysuit.com: did not receive HSTS header
 sawamura-rental.com: did not receive HSTS header
 say-hanabi.com: could not connect to host
@@ -9006,16 +9056,17 @@ screencaster.io: did not receive HSTS he
 screenresolution.space: could not connect to host
 screensaversplanet.com: did not receive HSTS header
 scribbleserver.com: could not connect to host
 scribe.systems: could not connect to host
 scrion.com: could not connect to host
 scriptenforcer.net: did not receive HSTS header
 scriptict.nl: could not connect to host
 scrollstory.com: did not receive HSTS header
+scubadiving-phuket.com: did not receive HSTS header
 sdhmanagementgroup.com: could not connect to host
 sdia.ru: could not connect to host
 sdmoscow.ru: could not connect to host
 sdrobs.com: did not receive HSTS header
 sdsl-speedtest.de: could not connect to host
 se7ensins.com: did not receive HSTS header
 seans.cc: did not receive HSTS header
 searchgov.gov.il: did not receive HSTS header
@@ -9061,17 +9112,16 @@ securiviera.ch: did not receive HSTS hea
 sedoexpert.nl: could not connect to host
 sedoexperts.nl: could not connect to host
 sedrubal.de: could not connect to host
 sedziapilkarski.pl: did not receive HSTS header
 seedboxers.net: could not connect to host
 seefunk.net: did not receive HSTS header
 seele.ca: could not connect to host
 sehenderson.com: did not receive HSTS header
-seiko-dojo.com: could not connect to host
 seiler-bad.de: did not receive HSTS header
 seizoushokoyuubangou.com: did not receive HSTS header
 sektor.team: could not connect to host
 selecadm.name: could not connect to host
 selectary.com: could not connect to host
 selectcertifiedautos.com: did not receive HSTS header
 selectel.com: did not receive HSTS header
 selectruckscalltrackingreports.com: could not connect to host
@@ -9181,17 +9231,17 @@ shiftplanning.com: did not receive HSTS 
 shiinko.com: could not connect to host
 shikinobi.com: did not receive HSTS header
 shindorei.fr: could not connect to host
 shinebijoux.com.br: could not connect to host
 shinju.moe: could not connect to host
 shiona.xyz: could not connect to host
 shipinsight.com: did not receive HSTS header
 shipmile.com: did not receive HSTS header
-shipping24h.com: could not connect to host
+shipping24h.com: did not receive HSTS header
 shirosaki.org: could not connect to host
 shitfest.info: did not receive HSTS header
 shitposting.life: could not connect to host
 shm-forum.org.uk: could not connect to host
 shocksrv.com: did not receive HSTS header
 shooshosha.com: could not connect to host
 shopherbal.co.za: did not receive HSTS header
 shopods.com: did not receive HSTS header
@@ -9406,16 +9456,17 @@ soply.com: did not receive HSTS header
 soporte.cc: could not connect to host
 sorensen-online.com: could not connect to host
 sosaka.ml: could not connect to host
 sosiolog.com: could not connect to host
 sotor.de: did not receive HSTS header
 soucorneteiro.com.br: could not connect to host
 soulfulglamour.uk: could not connect to host
 soundforsound.co.uk: did not receive HSTS header
+souravsaha.com: did not receive HSTS header
 sourcelair.com: did not receive HSTS header
 sourcitec.com: did not receive HSTS header
 southcoastswords.com: did not receive HSTS header
 southernjamusa.com: did not receive HSTS header
 southgale.condos: could not connect to host
 southside-crew.club: could not connect to host
 southworcestershiregpservices.co.uk: could not connect to host
 souvik.me: did not receive HSTS header
@@ -9461,17 +9512,16 @@ spineandscoliosis.com: did not receive H
 spirit-dev.net: max-age too low: 0
 spiritfanfics.com: did not receive HSTS header
 spisoggrin.dk: did not receive HSTS header
 spitefultowel.com: did not receive HSTS header
 spititout.it: could not connect to host
 spittersberger.recipes: did not receive HSTS header
 spokonline.com: could not connect to host
 sponsortobias.com: could not connect to host
-sport-socken.net: did not receive HSTS header
 sportchirp-internal.azurewebsites.net: did not receive HSTS header
 sporthit.ru: did not receive HSTS header
 sportifik.com: did not receive HSTS header
 sportingoods.com.br: could not connect to host
 sportscollection.com.br: could not connect to host
 sportwette.eu: did not receive HSTS header
 spot-events.com: could not connect to host
 spotifyripper.tk: could not connect to host
@@ -9479,17 +9529,17 @@ spotlightsrule.ddns.net: could not conne
 spr.id.au: did not receive HSTS header
 spresso.me: did not receive HSTS header
 sprint.ml: did not receive HSTS header
 sprk.fitness: did not receive HSTS header
 sproutconnections.com: could not connect to host
 sprutech.de: could not connect to host
 spyroszarzonis.com: could not connect to host
 sqetsa.com: did not receive HSTS header
-squaddraft.com: could not connect to host
+squaddraft.com: did not receive HSTS header
 square.gs: could not connect to host
 squatldf.org: did not receive HSTS header
 srcc.fr: could not connect to host
 srevilak.net: did not receive HSTS header
 srmaximo.com: could not connect to host
 srna.sk: did not receive HSTS header
 srpdb.com: did not receive HSTS header
 srrr.ca: could not connect to host
@@ -9594,22 +9644,24 @@ strivephysmed.com: did not receive HSTS 
 stroeercrm.de: could not connect to host
 strongest-privacy.com: could not connect to host
 stuartbaxter.co: could not connect to host
 student-scientist.org: did not receive HSTS header
 studentrdh.com: did not receive HSTS header
 studentresearcher.org: did not receive HSTS header
 studentskydenik.cz: could not connect to host
 studenttravel.cz: did not receive HSTS header
+studienservice.de: max-age too low: 7889238
 studinf.xyz: could not connect to host
 studio-panic.com: did not receive HSTS header
 studiozelden.com: did not receive HSTS header
 studybay.com: did not receive HSTS header
 studydrive.net: did not receive HSTS header
 studyhub.cf: did not receive HSTS header
+stuffie.org: did not receive HSTS header
 stugb.de: did not receive HSTS header
 sturbock.me: did not receive HSTS header
 sturdio.com.br: could not connect to host
 stylenda.com: could not connect to host
 stytt.com: did not receive HSTS header
 subbing.work: could not connect to host
 subdimension.org: did not receive HSTS header
 subeesu.com: could not connect to host
@@ -9836,30 +9888,31 @@ tekshrek.com: did not receive HSTS heade
 tel-dithmarschen.de: did not receive HSTS header
 teleallarme.ch: could not connect to host
 telefisk.org: did not receive HSTS header
 telefonnummer.online: could not connect to host
 telefoonnummerinfo.nl: could not connect to host
 telescam.com: could not connect to host
 teletechnology.in: did not receive HSTS header
 teletra.ru: could not connect to host
-tellingua.com: did not receive HSTS header
+tellingua.com: could not connect to host
 temasa.net: did not receive HSTS header
 temehu.com: did not receive HSTS header
 tempcraft.net: could not connect to host
 tempo.co: did not receive HSTS header
 tempodecolheita.com.br: could not connect to host
 tendertool.nl: could not connect to host
 tendoryu-aikido.org: did not receive HSTS header
 tenerife-villas.com: did not receive HSTS header
 tengroup.com: max-age too low: 0
 tenni.xyz: could not connect to host
 tensei-slime.com: did not receive HSTS header
 tensionup.com: could not connect to host
 tentins.com: could not connect to host
+teodio.cl: did not receive HSTS header
 teoleonie.com: did not receive HSTS header
 teos.online: could not connect to host
 terra.by: did not receive HSTS header
 terrax.berlin: could not connect to host
 terrax.info: could not connect to host
 teru.com.br: could not connect to host
 test02.dk: did not receive HSTS header
 testandroid.xyz: could not connect to host
@@ -10004,26 +10057,28 @@ thorncreek.net: did not receive HSTS hea
 thriveapproach.co.uk: did not receive HSTS header
 thrivewellnesshub.co.za: did not receive HSTS header
 throughthelookingglasslens.co.uk: could not connect to host
 thumbtack.com: did not receive HSTS header
 thundercampaign.com: could not connect to host
 ti.blog.br: could not connect to host
 tianxing.pro: did not receive HSTS header
 tianxingvpn.pro: could not connect to host
+tibbitshall.ca: did not receive HSTS header
 ticketoplichting.nl: did not receive HSTS header
 tickopa.co.uk: could not connect to host
 tickreport.com: did not receive HSTS header
 ticktock.today: did not receive HSTS header
 tictactux.de: could not connect to host
 tidmore.us: could not connect to host
 tie-online.org: did not receive HSTS header
 tiendschuurstraat.nl: could not connect to host
 tiensnet.com: could not connect to host
 tierrarp.com: could not connect to host
+tiffanytravels.com: did not receive HSTS header
 tightlineproductions.com: did not receive HSTS header
 tikutiku.pl: could not connect to host
 tildebot.com: could not connect to host
 tilient.eu: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsISiteSecurityService.processHeader]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: /builds/slave/m-cen-l64-periodicupdate-00000/getHSTSPreloadList.js :: processStsHeader :: line 115"  data: no]
 tilikum.io: did not receive HSTS header
 tilkah.com.au: did not receive HSTS header
 tillcraft.com: could not connect to host
 timbeilby.com: could not connect to host
@@ -10058,21 +10113,21 @@ titanleaf.com: could not connect to host
 titouan.co: did not receive HSTS header
 tittarpuls.se: could not connect to host
 titties.ml: could not connect to host
 tjc.wiki: could not connect to host
 tjeckien.guide: could not connect to host
 tkappertjedemetamorfose.nl: could not connect to host
 tkarstens.de: did not receive HSTS header
 tkonstantopoulos.tk: could not connect to host
-tlach.cz: did not receive HSTS header
 tlcdn.net: could not connect to host
 tlo.hosting: could not connect to host
 tlo.link: could not connect to host
 tlo.network: could not connect to host
+tloxygen.com: did not receive HSTS header
 tls.li: could not connect to host
 tlsbv.nl: did not receive HSTS header
 tlshost.net: could not connect to host
 tm-solutions.eu: could not connect to host
 tmaward.net: could not connect to host
 tmhlive.com: could not connect to host
 tmitchell.io: could not connect to host
 tmprod.com: did not receive HSTS header
@@ -10102,31 +10157,32 @@ tokobungadipadangflorist.com: did not re
 tokoone.com: did not receive HSTS header
 tokotamz.net: could not connect to host
 tokotimbangandigitalmurah.web.id: did not receive HSTS header
 tokoyo.biz: could not connect to host
 tollmanz.com: did not receive HSTS header
 tolud.com: could not connect to host
 tom.run: did not receive HSTS header
 tomeara.net: could not connect to host
-tomevans.io: did not receive HSTS header
+tomevans.io: could not connect to host
 tomlankhorst.nl: did not receive HSTS header
 tomli.me: could not connect to host
 tommsy.com: did not receive HSTS header
 tommy-bordas.fr: did not receive HSTS header
 tommyads.com: could not connect to host
 tommyweber.de: did not receive HSTS header
 tomphill.co.uk: could not connect to host
 tongmu.me: did not receive HSTS header
 tonyfantjr.com: max-age too low: 0
 toomanypillows.com: could not connect to host
 top-stage.net: could not connect to host
 topbargains.com.au: did not receive HSTS header
 topbestsellerproduct.com: did not receive HSTS header
 topdeskdev.net: could not connect to host
+topdogsinflatables.co.uk: did not receive HSTS header
 topmarine.se: could not connect to host
 topnewstoday.org: could not connect to host
 topnovini.com: did not receive HSTS header
 toppik.com.br: could not connect to host
 topshelfguild.com: could not connect to host
 toptenthebest.com: did not receive HSTS header
 toptranslation.com: did not receive HSTS header
 topyx.com: did not receive HSTS header
@@ -10214,17 +10270,17 @@ tripinsider.club: did not receive HSTS h
 trixies-wish.nz: could not connect to host
 trixy.com.br: could not connect to host
 troi.de: did not receive HSTS header
 trollme.me: could not connect to host
 trollscave.xyz: could not connect to host
 troo.ly: could not connect to host
 trouter.io: could not connect to host
 true.ink: did not receive HSTS header
-truebred-labradors.com: did not receive HSTS header
+truebred-labradors.com: could not connect to host
 trunkjunk.co: did not receive HSTS header
 trustedinnovators.com: did not receive HSTS header
 trusteecar.com: did not receive HSTS header
 trustmeimfancy.com: could not connect to host
 trybind.com: could not connect to host
 tryoneday.co: did not receive HSTS header
 ts2.se: could not connect to host
 ts3.consulting: could not connect to host
@@ -10463,17 +10519,17 @@ vadodesign.nl: did not receive HSTS head
 valenscaelum.com: could not connect to host
 valethound.com: could not connect to host
 valhalla-agency.com: max-age too low: 0
 valhallacostarica.com: could not connect to host
 valhallamovement.com: did not receive HSTS header
 valitron.se: did not receive HSTS header
 valkyrja.xyz: could not connect to host
 valleyridgepta.org: could not connect to host
-vallis.net: did not receive HSTS header
+vallis.net: could not connect to host
 valmagus.com: could not connect to host
 vamoaeturismo.com.br: could not connect to host
 vampirism.eu: could not connect to host
 vanacht.co.za: did not receive HSTS header
 vanajahosting.com: did not receive HSTS header
 vanderkley.it: could not connect to host
 vanestack.com: could not connect to host
 vanitas.xyz: could not connect to host
@@ -10611,28 +10667,30 @@ voceinveste.com: did not receive HSTS he
 voicesuk.co.uk: did not receive HSTS header
 voidserv.net: could not connect to host
 volcrado.com: did not receive HSTS header
 voliere-info.nl: did not receive HSTS header
 volkden.com: could not connect to host
 voltotc.com: did not receive HSTS header
 vonavy-cukor.sk: could not connect to host
 vonavycukor.sk: could not connect to host
+vonedelmann.de: did not receive HSTS header
 vonterra.us: did not receive HSTS header
 vooreenveiligthuis.nl: did not receive HSTS header
 voorjou.com: did not receive HSTS header
 vorangerie.com: could not connect to host
 vortexhobbies.com: did not receive HSTS header
 vowsy.club: did not receive HSTS header
 vox.vg: did not receive HSTS header
 vpip.net: could not connect to host
 vpl.me: did not receive HSTS header
 vpn-byen.dk: did not receive HSTS header
 vpn.pics: did not receive HSTS header
 vpnhot.com: could not connect to host
+vpnzoom.com: did not receive HSTS header
 vps-szerver-berles.hu: could not connect to host
 vpsmojo.com: could not connect to host
 vratny.space: could not connect to host
 vriendenvoordeel.com: did not receive HSTS header
 vrijstaandhuis-in-alphen-aan-den-rijn-kopen.nl: could not connect to host
 vrijstaandhuis-in-brielle-kopen.nl: could not connect to host
 vrijstaandhuis-in-delfzijl-kopen.nl: could not connect to host
 vrijstaandhuis-in-friesland-kopen.nl: could not connect to host
@@ -10859,16 +10917,17 @@ wodice.com: could not connect to host
 wohnungsbau-ludwigsburg.de: did not receive HSTS header
 woima.fi: max-age too low: 604800
 wolfenland.net: did not receive HSTS header
 wolfesden.com: could not connect to host
 womf.org: did not receive HSTS header
 womosale.de: could not connect to host
 wonder.com.mx: max-age too low: 86400
 wonderfall.xyz: could not connect to host
+wondermags.com: did not receive HSTS header
 wondy.com: could not connect to host
 woodlandschurch.net: max-age too low: 43200
 woodmafia.com.au: could not connect to host
 woodworkertip.com: did not receive HSTS header
 woording.com: could not connect to host
 wootton95.com: could not connect to host
 wooviet.com: could not connect to host
 work-and-jockel.de: did not receive HSTS header
@@ -10922,17 +10981,17 @@ www-1117.com: could not connect to host
 www-39988.com: did not receive HSTS header
 www-507.net: could not connect to host
 www-746.com: could not connect to host
 www-771122.com: did not receive HSTS header
 www-8003.com: did not receive HSTS header
 www-88599.com: did not receive HSTS header
 www-9995.com: did not receive HSTS header
 www-djbet.com: did not receive HSTS header
-www-jinshavip.com: could not connect to host
+www-jinshavip.com: did not receive HSTS header
 www.cueup.com: could not connect to host
 www.cyveillance.com: did not receive HSTS header
 www.developer.mydigipass.com: could not connect to host
 www.elanex.biz: did not receive HSTS header
 www.gamesdepartment.co.uk: did not receive HSTS header
 www.gpo.gov: did not receive HSTS header
 www.greplin.com: could not connect to host
 www.jitsi.org: did not receive HSTS header
@@ -11016,17 +11075,16 @@ xn--datenrettung-mnchen-jbc.com: did not
 xn--ekr87w7se89ay98ezcs.biz: did not receive HSTS header
 xn--gmq92k.nagoya: did not receive HSTS header
 xn--jp-6l5cs1yf3ivjsglphyv.net: could not connect to host
 xn--l8j9d2b.jp: did not receive HSTS header
 xn--lgb3a8bcpn.cf: could not connect to host
 xn--lgb3a8bcpn.ga: could not connect to host
 xn--lgb3a8bcpn.gq: could not connect to host
 xn--lgb3a8bcpn.ml: could not connect to host
-xn--lnakuten-9za.com: did not receive HSTS header
 xn--ls8hi7a.tk: could not connect to host
 xn--milchaufschumer-test-lzb.de: could not connect to host
 xn--n8jubz39q0g0afpa985c.com: could not connect to host
 xn--neb-tma3u8u.xyz: could not connect to host
 xn--p8jskj.jp: did not receive HSTS header
 xn--pck4e3a2ex597b4ml.xyz: did not receive HSTS header
 xn--qckqc0nxbyc4cdb4527err7c.biz: did not receive HSTS header
 xn--u9jy16ncfao19mo8i.nagoya: did not receive HSTS header
--- a/security/manager/ssl/nsSTSPreloadList.inc
+++ b/security/manager/ssl/nsSTSPreloadList.inc
@@ -3,17 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*****************************************************************************/
 /* This is an automatically generated file. If you're not                    */
 /* nsSiteSecurityService.cpp, you shouldn't be #including it.     */
 /*****************************************************************************/
 
 #include <stdint.h>
-const PRTime gPreloadListExpirationTime = INT64_C(1529523515392000);
+const PRTime gPreloadListExpirationTime = INT64_C(1529610665474000);
 %%
 0-1.party, 1
 0.me.uk, 1
 0005pay.com, 1
 00100010.net, 1
 0010100.net, 1
 00120012.net, 1
 00130013.net, 1
@@ -127,17 +127,17 @@ 112hz.com, 1
 113113113.net, 1
 118118118.net, 1
 11loc.de, 1
 11scc.com, 1
 11thstreetcoffee.com, 1
 11urss.com, 1
 1212873467.rsc.cdn77.org, 1
 1218641649.rsc.cdn77.org, 1
-123comparer.fr, 1
+123comparer.fr, 0
 123djdrop.com, 1
 123midterm.com, 1
 123pay.ir, 0
 123plons.nl, 1
 123termpapers.com, 1
 123test.com, 1
 123test.nl, 1
 125m125.de, 1
@@ -1095,16 +1095,17 @@ aflowershop.ca, 1
 afmt.fr, 1
 afmtevents.com, 1
 afonso.io, 1
 afp548.com, 1
 afri.cc, 1
 africa.dating, 1
 africanexponent.com, 1
 africanimpact.com, 1
+africantourer.com, 1
 africatravel.de, 1
 afrikarl.de, 1
 afrodigital.uk, 1
 after.digital, 1
 afterhate.fr, 1
 afterstack.net, 1
 afuh.de, 1
 afva.net, 1
@@ -1628,17 +1629,17 @@ alza.de, 1
 alza.hu, 1
 alza.sk, 1
 alzashop.com, 1
 alzonaprinting.com, 1
 am2s.fr, 1
 am3.se, 1
 ama.ne.jp, 1
 amaderelectronics.com, 1
-amadilo.de, 1
+amadilo.de, 0
 amadoraslindas.com, 1
 amadvice.com, 1
 amaforro.com, 1
 amaforums.org, 1
 amagdic.com, 1
 amagical.net, 1
 amalfi5stars.com, 1
 amalficoastchauffeur.com, 1
@@ -3332,17 +3333,16 @@ bayer-stefan.com, 1
 bayer-stefan.de, 1
 bayer-stefan.eu, 1
 bayerhazard.de, 1
 bayerstefan.com, 1
 bayerstefan.de, 1
 bayerstefan.eu, 1
 bayherbalist.com, 1
 bayilelakiku.com, 1
-bayinstruments.com, 1
 baymard.com, 1
 bayrisch-fuer-anfaenger.de, 1
 baywatch.io, 1
 bayz.de, 1
 bazaarcompass.com, 1
 bazdell.com, 0
 bazos.at, 1
 bazos.cz, 1
@@ -3420,17 +3420,16 @@ be9966.com, 1
 beachfutbolclub.com, 1
 beacinsight.com, 1
 beadare.com, 1
 beagreenbean.co.uk, 1
 bealpha.pl, 1
 beamitapp.com, 1
 beanjuice.me, 1
 beans-one.com, 0
-beanworks.ca, 1
 bearcosports.com.br, 1
 bearded.sexy, 1
 bearingworks.com, 1
 beasel.biz, 1
 beastowner.li, 1
 beatfeld.de, 1
 beatnikbreaks.com, 1
 beatrizaebischer.ch, 1
@@ -3734,16 +3733,17 @@ bet909.com, 1
 bet990.com, 1
 bet9bet9.net, 1
 betamint.org, 1
 betaworx.de, 1
 betaworx.eu, 1
 betecnet.de, 1
 betformular.com, 1
 betgo9.cc, 1
+bethanyduke.com, 1
 betkoo.com, 1
 betobaccofree.gov, 1
 betonmoney.com, 1
 betpamm.com, 1
 betseybuckheit.com, 1
 betshoot.com, 1
 betsonlinefree.com.au, 1
 betsyshilling.com, 1
@@ -4051,17 +4051,16 @@ bitcoin.de, 1
 bitcoin.im, 1
 bitcoin.info, 1
 bitcoin.org, 1
 bitcoin.us, 1
 bitcoinbitcoin.com, 1
 bitcoinclashic.ninja, 1
 bitcoincore.org, 1
 bitcoinec.info, 1
-bitcoinhk.org, 1
 bitcoinindia.com, 1
 bitcoinjpn.com, 1
 bitcoinkarlsruhe.de, 1
 bitcoinrealestate.com.au, 1
 bitcointhefts.com, 1
 bitcoinwalletscript.tk, 1
 bitcoinx.gr, 1
 bitcoinx.ro, 1
@@ -4297,17 +4296,16 @@ blogexpert.ca, 1
 blogging-life.com, 1
 bloggingwithchildren.com, 1
 bloggytalky.com, 1
 bloginbeeld.nl, 1
 blogom.at, 1
 blogpentrusuflet.ro, 1
 blogreen.org, 1
 blogtroterzy.pl, 1
-blok56.nl, 1
 blokuhaka.fr, 1
 bloodsports.org, 1
 bloodyexcellent.com, 1
 bloom-avenue.com, 1
 bltc.co.uk, 1
 bltc.com, 1
 bltc.net, 1
 bltc.org, 1
@@ -5020,16 +5018,17 @@ buck.com, 1
 buckmulligans.com, 1
 buckypaper.com, 1
 budaev-shop.ru, 1
 buddhistische-weisheiten.org, 1
 buddie5.com, 1
 buddlycrafts.com, 1
 buddyworks.net, 1
 budeanu.com, 1
+buderus-family.be, 1
 budger.nl, 1
 budget.gov, 1
 budgetalk.com, 1
 budgetcastlehire.co.uk, 1
 budgetenergievriendenvoordeel.nl, 1
 budgetlob.gov, 1
 budgetlovers.nl, 1
 budgiesballoons.com, 1
@@ -5764,16 +5763,17 @@ cedriccassimo.ch, 1
 cedriccassimo.com, 1
 cee.io, 1
 ceebee.com, 1
 cefak.org.br, 1
 cegfw.com, 1
 ceilingpac.org, 1
 cejhon.cz, 0
 cekaja.com, 1
+celebphotos.blog, 1
 celebrityscope.net, 1
 celec.gob.ec, 0
 celectro-pro.com, 1
 celiendev.ch, 1
 celigo.com, 1
 celltek-server.de, 1
 celti.ie.eu.org, 1
 celti.name, 1
@@ -7059,16 +7059,17 @@ continuation.io, 1
 contrabass.net, 1
 contractormountain.com, 1
 contratatupoliza.com, 1
 contributor.google.com, 1
 controlarlaansiedad.com, 1
 controlautocom.com.br, 1
 controlbooth.com, 1
 controle.net, 1
+controleer-maar-een-ander.nl, 1
 controltickets.com.br, 1
 contxt-agentur.de, 1
 conv2pdf.com, 1
 conve.eu, 1
 convergemagazine.com, 1
 convergence.fi, 1
 convergencela.com, 1
 convergnce.com, 1
@@ -8307,17 +8308,17 @@ delivery.co.at, 1
 dellipaoli.com, 1
 delogo.nl, 1
 deloittequant.com, 1
 delorenzi.dk, 1
 delphine.dance, 1
 delta-data.ch, 1
 delta-smart.ch, 1
 delta.ru, 1
-delta23.de, 0
+delta23.de, 1
 deltaacademy.org, 1
 deltadata.ch, 1
 deltaonlineguards.com, 1
 deltasmart.ch, 1
 deltava.org, 1
 demandware.com, 1
 demarche-expresse.com, 1
 demarle.ch, 1
@@ -8368,16 +8369,17 @@ dentistglasgow.com, 1
 dentrassi.de, 1
 dentystabirmingham.co.uk, 1
 denverphilharmonic.org, 1
 deontology.com, 1
 depaddestoeltjes.be, 1
 deparis.me, 1
 depechemode-live.com, 1
 depedshs.com, 1
+depedtayo.com, 1
 depedtayo.ph, 1
 depicus.com, 1
 depone.net, 1
 depot-leipzig.de, 1
 depotsquarekerrville.com, 1
 depotter-usedcars.be, 1
 deprecate.de, 1
 deprobe.pro, 1
@@ -8882,17 +8884,16 @@ diycc.org, 1
 diymediahome.org, 1
 diyosun.com, 1
 diz.in.ua, 1
 dizzythewizard.co.uk, 1
 dj-leszwolle.nl, 1
 dj-x.info, 1
 dj3dub.com, 1
 djangobirthday.com, 1
-djangogolf.com, 1
 djangoproject.com, 1
 djangosnippets.org, 1
 djbbouncycastles.co.uk, 1
 djc.me, 1
 djcursuszwolle.nl, 1
 djdavid98.hu, 1
 djipanov.com, 1
 djlive.pl, 1
@@ -9483,17 +9484,16 @@ dusmomente.com, 1
 dusnan.com, 1
 dustplanet.de, 1
 dustri.org, 1
 dustycloth.com, 1
 dustygroove.com, 1
 dustyspokesbnb.ca, 1
 dutch.desi, 1
 dutch1.nl, 1
-dutchessuganda.com, 1
 dutchrank.nl, 1
 dutchwanderers.nl, 1
 dutchweballiance.nl, 1
 dutyfreeonboard.com, 1
 dvbris.co.uk, 1
 dvbris.com, 1
 dvdland.com.au, 1
 dvhosting.be, 1
@@ -9871,17 +9871,16 @@ egiftcards.be, 1
 eglek.com, 1
 ego4u.com, 1
 ego4u.de, 1
 egoroof.ru, 1
 egov4.ch, 1
 egretail.no, 0
 egrp365.ru, 1
 egumenita.ro, 1
-egupova.ru, 1
 egw-ceramica.de, 1
 egweb.tv, 1
 ehaccp.it, 1
 ehandel.com, 1
 ehazi.hu, 1
 ehertz.uk, 1
 ehipaa.com, 1
 ehlacademy.org, 1
@@ -9897,17 +9896,16 @@ eickhofcolumbaria.com, 1
 eidolons.org, 1
 eiga-movie.com, 1
 eigenbubi.de, 1
 eighty-aid.com, 1
 eightyfour.ca, 1
 eigpropertyauctions.co.uk, 1
 eilhan.com, 1
 eimacs.com, 1
-eimanavicius.lt, 1
 einar.io, 1
 einaros.is, 1
 einfachbahn.de, 1
 einfachmaldiefressehalten.de, 1
 einheft.info, 1
 einheizpreis.de, 1
 einmonolog.de, 1
 einrichtwerk.de, 1
@@ -10479,17 +10477,17 @@ errietta.me, 1
 errlytics.com, 1
 error418.nl, 1
 ers35.com, 1
 ersa-shop.com, 1
 ershiwo.com, 1
 ersinerce.com, 1
 erspro.net, 1
 erstehilfeprodukte.at, 1
-eru.im, 1
+eru.im, 0
 erudicia.com, 1
 erudicia.de, 1
 erudicia.es, 1
 erudicia.fr, 1
 erudicia.it, 1
 erudicia.nl, 1
 erudicia.se, 1
 erudicia.uk, 1
@@ -10844,17 +10842,16 @@ evades.io, 1
 evailoil.ee, 1
 evailoil.eu, 1
 evalesc.com, 1
 evamachkova.cz, 1
 evamira.com, 1
 evanfiddes.com, 1
 evangelosm.com, 1
 evankurniawan.com, 1
-evantage.org, 1
 evantageglobal.com, 1
 evapp.org, 1
 evasion-energie.com, 1
 evasioncreole.com, 1
 evasovova.cz, 1
 eve0s.com, 1
 evegalaxy.net, 1
 evelienzorgt.nl, 1
@@ -11822,16 +11819,17 @@ flygpost.com, 1
 flyingdoggy.net, 1
 flyinglocksmiths.com, 0
 flyingpackets.net, 1
 flyingrub.me, 1
 flymns.fr, 1
 flynn.io, 1
 flyp.me, 1
 flyserver.co.il, 1
+flyspace.ga, 1
 flyspace.ml, 1
 flyss.net, 1
 flyssh.net, 1
 flyt.online, 1
 flytoadventures.com, 1
 fm-cdn.de, 1
 fm.ie, 1
 fmapplication.com, 1
@@ -12157,17 +12155,16 @@ freejeremy.net, 1
 freejidi.com, 1
 freela.ch, 1
 freelance.boutique, 1
 freelance.guide, 1
 freelance.nl, 1
 freelancecollab.com, 1
 freelancehunt.com, 1
 freelanceshipping.com, 1
-freelandinnovation.com, 1
 freelansir.com, 1
 freelauri.com, 1
 freelifer.jp, 1
 freemanning.de, 1
 freemans.com, 1
 freemedforms.com, 1
 freemyipod.org, 1
 freend.me, 0
@@ -12418,26 +12415,24 @@ furrybot.me, 1
 furryyiff.site, 1
 furtivelook.com, 1
 fusa-miyamoto.jp, 1
 fuseos.net, 1
 fushee.com, 1
 fuskator.com, 1
 fussball-xxl.de, 1
 fussell.io, 1
-futbolvivo.tv, 1
 futos.de, 1
 futrou.com, 1
 futurefire.de, 1
 futurehack.io, 1
 futurenda.com, 1
 futureoceans.org, 1
 futuresonline.com, 1
 futurezone.at, 1
-futuristarchitecture.com, 1
 futurope.com, 1
 fuwafuwa.moe, 1
 fuxwerk.de, 1
 fuyu.moe, 1
 fuzoku-sodan.com, 1
 fuzoku.jp, 1
 fuzzing-project.org, 1
 fveevaete.com, 1
@@ -12470,17 +12465,16 @@ fysio123.nl, 1
 fysiotherapieholtenbroek.nl, 1
 fysiotherapierossum.nl, 1
 fysiovdberg.nl, 1
 fysuite.com, 1
 fzbrweb.cz, 1
 fzx750.ru, 1
 g-m-w.eu, 1
 g-o.pl, 1
-g-rom.net, 1
 g01.in.ua, 1
 g1.ie, 1
 g10e.ch, 1
 g1jeu.com, 1
 g2-inc.com, 1
 g2links.com, 1
 g2pla.net, 1
 g2soft.net, 1
@@ -12825,16 +12819,17 @@ geocompass.at, 1
 geoffanderinmyers.com, 1
 geoffmyers.com, 0
 geofox.org, 1
 geoip.fedoraproject.org, 1
 geoip.stg.fedoraproject.org, 1
 geojs.io, 1
 geolad.com, 0
 geometra.roma.it, 1
+geoponika.gr, 1
 geoport.al, 1
 george-orwell.com, 1
 georgehalachev.com, 1
 georgemaschke.com, 1
 georgemaschke.net, 1
 georgescarryout.com, 1
 georgewbushlibrary.gov, 1
 georgiaglassrepair.com, 1
@@ -13649,17 +13644,16 @@ guid2steamid.com, 1
 guid2steamid.pw, 1
 guide-peche-cantal.com, 1
 guidechecking.com, 1
 guidedselling.net, 1
 guideline.gov, 1
 guidelines.gov, 1
 guideo.ch, 1
 guides-peche64.com, 1
-guidetoiceland.is, 0
 guildgearscore.cf, 0
 guildofmusicsupervisors.co.uk, 1
 guillaume-briand.fr, 1
 guillaumecote.me, 1
 guillaumeperrin.io, 1
 guillemaud.me, 0
 guiltypleasuresroleplaying.com, 1
 guim.co.uk, 1
@@ -13676,17 +13670,16 @@ gumballs.com, 1
 gume4you.com, 1
 gumi.ca, 1
 gummibande.noip.me, 1
 gunhunter.com, 1
 guniram.com, 1
 gunwatch.co.uk, 1
 guochang.xyz, 1
 guoliang.me, 1
-guozeyu.com, 1
 guphi.net, 0
 gurkan.in, 1
 gurmel.ru, 1
 gurochan.ch, 1
 guru-naradi.cz, 1
 gurueffect.com, 1
 gus.host, 1
 gus.moe, 1
@@ -15236,17 +15229,16 @@ ifsclist.com, 1
 ifsr.de, 1
 iftrue.de, 1
 ifxnet.com, 1
 ifyou.live, 1
 ig.com, 1
 iga-semi.jp, 1
 igamingforums.com, 1
 igcc.jp, 1
-igd.chat, 1
 igglabs.com, 1
 iggprivate.com, 1
 iggsoft.com, 1
 iggsoftware.com, 1
 igiftcards.de, 1
 igimusic.com, 1
 igk.nz, 1
 igm-be.ch, 1
@@ -15492,17 +15484,16 @@ indianaantlersupply.com, 1
 indianaffairs.gov, 0
 indiawise.co.uk, 1
 indicateurs-flash.fr, 1
 indieethos.com, 1
 indiegame.space, 1
 indievelopment.nl, 1
 indigoinflatables.com, 1
 indigosakura.com, 1
-indilens.com, 1
 inditip.com, 1
 indogerman.de, 1
 indogermanstartup.com, 1
 indogermantrade.de, 1
 indoorplantsexpert.com, 1
 indostar303.com, 1
 indovinabank.com.vn, 1
 indusap.com, 1
@@ -15950,17 +15941,16 @@ irritant.net, 1
 iruarts.ch, 1
 iruca.co, 1
 is-sw.net, 1
 isaackabel.cf, 1
 isaackabel.ga, 1
 isaackabel.gq, 1
 isaackabel.ml, 1
 isaackabel.tk, 1
-isaackhor.com, 1
 isaacman.tech, 1
 isaacpartnership.co.uk, 1
 isaacpartnership.com, 1
 isaacphysics.org, 1
 isaaczais.com, 1
 isabelle-delpech.com, 1
 isabellehogarth.co.uk, 1
 isakssons.com, 1
@@ -16354,17 +16344,16 @@ jannisfink.de, 1
 janoberst.com, 1
 janokacer.sk, 1
 janosh.com, 1
 janschaumann.de, 1
 janssen.fm, 1
 janssenwigman.nl, 1
 janverlaan.nl, 1
 jaot.info, 1
-jap-nope.de, 1
 japan4you.org, 1
 japaneseemoticons.org, 1
 japanesenames.biz, 1
 japaniac.de, 0
 japanphilosophy.com, 1
 japanwatches.xyz, 1
 jape.today, 1
 jardin-exotique-rennes.fr, 1
@@ -17283,17 +17272,16 @@ kato-yane.com, 1
 katrinjanke.de, 0
 katscastles.co.uk, 1
 kattelans.eu, 1
 kattenfun.be, 1
 kattenfun.nl, 1
 katthewaffle.fr, 1
 katyl.info, 0
 katyusha.net, 1
-katzen.me, 1
 katzspeech.com, 1
 kau-boys.com, 1
 kau-boys.de, 1
 kaufberatung.community, 1
 kauperwood.ovh, 1
 kausta.me, 1
 kavik.no, 1
 kavovary-kava.cz, 1
@@ -18914,16 +18902,17 @@ likegeeks.com, 1
 likehifi.de, 1
 likemovies.de, 1
 likenewhearing.com.au, 1
 likenosis.com, 1
 lilaccakeboutique.com, 1
 liliang13.com, 1
 lilismartinis.com, 1
 lillepuu.com, 1
+lily-bearing.com, 1
 lily-inn.com, 1
 lilyfarmfreshskincare.com, 1
 lilygreen.co.za, 1
 lilysbouncycastles.com, 1
 limawi.io, 1
 limberg.me, 1
 limbo.services, 1
 limeburst.net, 1
@@ -19112,17 +19101,16 @@ livepath.ch, 1
 liveperformersmeeting.net, 1
 liveregistratie.nl, 1
 livesearch-fukuoka.com, 1
 livesure.com, 1
 livi.co, 1
 living-space.co.nz, 1
 living24.de, 1
 livingforreal.com, 1
-livinghealthywithchocolate.com, 1
 livingworduk.org, 1
 livnev.me, 1
 livnev.xyz, 1
 livolett.de, 1
 livrariacoad.com.br, 1
 livroseuniformes.com.br, 1
 lixtick.com, 1
 liyang.pro, 1
@@ -20352,16 +20340,17 @@ mcideas.tk, 1
 mcjackk77.com, 1
 mckenry.net, 1
 mckernan.in, 1
 mckinley.school, 1
 mckinley1.com, 1
 mckinleytk.com, 1
 mcl.gg, 1
 mclinflatables.co.uk, 1
+mclyr.com, 1
 mcmillanskiclub.com.au, 1
 mcneill.io, 1
 mcnext.net, 1
 mcpaoffice.com, 1
 mcpart.land, 1
 mcpro.games, 1
 mcrn.jp, 1
 mcsa-usa.org, 1
@@ -20450,16 +20439,17 @@ mediawiki.org, 1
 mediawin.pl, 1
 medic-world.com, 1
 medicalcountermeasures.gov, 1
 medicinesfast.com, 0
 medicinia.com.br, 1
 medicinskavranje.edu.rs, 1
 medicocompetente.it, 1
 medicoresponde.com.br, 1
+medifab.online, 1
 medifi.com, 1
 medinside.ch, 1
 medinside.li, 1
 medinsider.ch, 1
 medinsider.li, 1
 medireport.fr, 1
 medium.com, 1
 mediumraw.org, 1
@@ -21502,17 +21492,17 @@ mpi-sa.fr, 1
 mpintaamalabanna.it, 1
 mplanetphl.fr, 1
 mplant.io, 1
 mplicka.cz, 1
 mplusm.eu, 1
 mpn.poker, 1
 mpnpokertour.com, 1
 mpodraza.pl, 1
-mpreserver.com, 0
+mpreserver.com, 1
 mprsco.eu, 1
 mpserver12.org, 1
 mpsgarage.com.au, 1
 mpsoundcraft.com, 1
 mpy.ovh, 1
 mr-anderson.org, 1
 mr-labo.jp, 1
 mr-nachhilfe.de, 1
@@ -23053,17 +23043,16 @@ nubu.at, 1
 nuclear-crimes.com, 1
 nuclearcat.com, 1
 nuclearcrimes.com, 1
 nuclearcrimes1.com, 1
 nucleuscore.org, 1
 nudel.ninja, 1
 nudestpics.com, 1
 nuel.cl, 1
-nuevaimagenpublicidad.es, 1
 null-life.com, 1
 nullday.de, 1
 nullpointer.io, 1
 nullroute.com, 1
 nulltime.net, 1
 numarasorgulama.tel, 1
 numatic.co.uk, 1
 number.me, 1
@@ -24393,17 +24382,16 @@ pelican.ie, 1
 pelletizermill.com, 1
 pelletsprice.com, 1
 pelopogrund.com, 1
 pelopoplot.com, 1
 pelotonimports.com, 1
 pemagrid.org, 1
 penaugustin.com, 1
 pencepay.com, 1
-pencillab.cn, 1
 pendriveapps.com, 1
 penetrationstest.se, 1
 penfold.fr, 1
 pengi.me, 1
 pengisatelier.net, 1
 penguinprotocols.com, 1
 pengumuman.id, 1
 penispumpen.se, 1
@@ -24645,18 +24633,16 @@ phpkari.cz, 1
 phpliteadmin.org, 1
 phpmyadmin.net, 1
 phpprime.com, 1
 phpsecure.info, 1
 phra.gs, 1
 phrive.space, 1
 phryanjr.com, 0
 phryneas.de, 1
-phuket-idc.com, 1
-phuket-idc.de, 1
 phunehehe.net, 1
 phuong.faith, 1
 phurl.de, 1
 phurl.io, 1
 phus.lu, 1
 physicalism.com, 1
 physicalist.com, 1
 physiovesenaz.ch, 1
@@ -24953,17 +24939,16 @@ plexpy13.ddns.net, 1
 plextv.de, 1
 plexusmd.com, 1
 plinc.co, 1
 pliosoft.com, 1
 plitu.de, 1
 ploader.ru, 0
 plochka.bg, 1
 plomberierenga.com, 1
-plongee-phuket.fr, 1
 ploofer.com, 1
 plot.ly, 1
 plotbubble.com, 1
 plr4wp.com, 1
 plsboop.me, 1
 pluga.co, 1
 plugboard.xyz, 1
 plugcubed.net, 0
@@ -25215,16 +25200,17 @@ postbox.life, 1
 postcardpayment.com, 1
 postcode.nl, 1
 postcodegarant.nl, 1
 postdarwinian.com, 1
 postdarwinism.com, 1
 postdeck.de, 1
 posteo.de, 0
 posters.win, 1
+posterspy.com, 1
 postfalls-naturopathic.com, 1
 postfinance.ch, 1
 postmatescode.com, 1
 postn.eu, 1
 postpot.co.kr, 1
 posttigo.com, 1
 potatiz.com, 1
 potatofrom.space, 0
@@ -25645,16 +25631,17 @@ proxybay.one, 1
 proxybay.tv, 1
 proxydesk.eu, 1
 proxyportal.net, 1
 proxyportal.org, 1
 proymaganadera.com, 1
 prpferrara.it, 1
 prplz.io, 1
 prpsss.com, 1
+prstatic.com, 1
 prt.in.th, 1
 prtimes.com, 1
 prtpe.com, 1
 pruikshop.nl, 1
 pruma.com.br, 1
 prvikvadrat.hr, 1
 prylarprylar.se, 1
 pryspry.com, 1
@@ -26191,16 +26178,17 @@ rattenkot.io, 1
 raucris.ro, 1
 raulrivero.es, 1
 raumzeitlabor.de, 0
 rauros.net, 1
 rautelow.de, 1
 rautermods.net, 1
 ravchat.com, 1
 raven.dog, 1
+ravenger.net, 1
 ravengergaming.net, 1
 ravensbuch.de, 1
 ravhaaglanden.org, 1
 ravindran.me, 1
 raviparekh.co.uk, 1
 ravis.org, 1
 ravse.dk, 1
 rawsec.net, 1
@@ -26475,17 +26463,16 @@ rei.ki, 1
 reichel-steinmetz.de, 1
 reichelt-cloud.de, 1
 reichl-online.net, 1
 reidasbombas.com, 1
 reignsphere.net, 1
 reiki-coaching.nl, 0
 reilly.io, 1
 reimaginebelonging.de, 1
-reimann.me, 1
 reimers.de, 1
 reimu.ink, 0
 rein.kr, 1
 reinaertvandecruys.me, 1
 reinaldudras.ee, 1
 reinaldudrasfamily.ee, 1
 reineberthe.ch, 1
 reinencaressa.be, 1
@@ -27252,17 +27239,17 @@ runebet.com, 1
 runementors.com, 0
 runklesecurity.com, 1
 runnergrapher.com, 1
 runreport.fr, 1
 runschrauger.com, 1
 runvs.io, 1
 ruobiyi.com, 1
 ruobr.ru, 1
-ruri.io, 1
+ruri.io, 0
 rus-trip.ru, 1
 rusempire.ru, 1
 rushball.net, 1
 rushiiworks.com, 1
 rushpoppershop.co.uk, 1
 rushyo.com, 1
 rusi-ns.ca, 1
 ruskod.net, 1
@@ -27424,17 +27411,16 @@ saintaardvarkthecarpeted.com, 1
 saintanthonyscorner.com, 1
 sainth.de, 1
 saintsrobotics.com, 1
 saintw.com, 1
 saipariwar.com, 1
 saiputra.com, 1
 saitrance.com, 1
 saiyasu-search.com, 1
-sajamstudija.info, 1
 sajdowski.de, 1
 sakostacloud.de, 1
 sakuraflores.com.br, 1
 salaervergleich.com, 1
 salde.net, 1
 sale4ru.ru, 1
 saleaks.org, 1
 salearnership.co.za, 1
@@ -27640,17 +27626,16 @@ saumon-france.com, 1
 saumon.io, 1
 saumondefrance.fr, 1
 saumonfrance.fr, 1
 saunahats.eu, 1
 saunas.fr, 1
 saunatime.jp, 1
 saurel.me, 1
 sauvagebridge.nl, 1
-savacloud.com, 1
 savageorgiev.com, 1
 savannahtasteexperience.com, 1
 save-me-aachen.de, 1
 save-me-koeln.de, 1
 savecashindia.com, 1
 savecrypto.org, 1
 savekorea.net, 1
 savemoneyonenergy.com, 1
@@ -27910,17 +27895,16 @@ scruffymen.com, 0
 scrumbleship.com, 1
 scrumstack.co.uk, 1
 scryfall.com, 1
 scs-simulatoren.de, 1
 scsd.si, 1
 scswam.com, 1
 sctm.at, 1
 sctrainingllc.com, 1
-scubadiving-phuket.com, 1
 scul.net, 1
 sculpture.support, 1
 scuolaguidalame.ch, 1
 scw.com, 1
 scw.nz, 1
 scwilliams.co.uk, 1
 scwilliams.uk, 1
 sd.af, 1
@@ -28118,16 +28102,17 @@ segmetic.com, 1
 segulink.com, 1
 segurosbalboa.com.ec, 0
 segurosocial.gov, 1
 seguroviagem.srv.br, 1
 sehnenweh.org, 1
 seida.at, 1
 seifried.org, 1
 seikatu-navi.com, 1
+seiko-dojo.com, 1
 seinfeldquote.com, 1
 seirei.ne.jp, 1
 seiryokuzai-ch.com, 1
 seitai-taiyou.com, 1
 seitenwaelzer.de, 1
 sekisonn.com, 1
 selbys.net.au, 1
 selco-himejiminami.com, 1
@@ -29479,17 +29464,16 @@ soumya92.me, 1
 soundabout.nl, 1
 soundedj.com.br, 1
 soundeo.com, 1
 soundeo.net, 1
 soundgasm.net, 1
 soundhunter.xyz, 0
 soundsecurity.io, 1
 sour.is, 1
-souravsaha.com, 1
 sourcebox.be, 1
 sourcecode.love, 1
 sourcely.net, 1
 sourceway.de, 1
 souris.ch, 1
 sous-surveillance.net, 1
 southafrican.dating, 1
 southambouncycastle.co.uk, 1
@@ -29649,16 +29633,17 @@ spookbook.net, 1
 spookquest.com, 1
 spookyinternet.com, 1
 spoopy.link, 1
 sporcard.com, 1
 spornkuller.de, 1
 sport-in-sundern.de, 1
 sport-potreby.cz, 1
 sport-potreby.sk, 1
+sport-socken.net, 1
 sporter.com, 1
 sportflash.info, 1
 sportnesia.com, 1
 sportovnidum.cz, 1
 sportparks.com, 1
 sportparks.org, 1
 sportressofblogitude.com, 1
 sports.dating, 1
@@ -30191,17 +30176,16 @@ studentfinancecountdown.com, 1
 studentforums.biz, 1
 studentite.bg, 0
 studentloans.gov, 1
 studentrightsadvocate.org, 1
 studenttenant.com, 1
 studer.su, 1
 studiemeter.nl, 1
 studienportal.eu, 1
-studienservice.de, 1
 studiereader.nl, 1
 studio-architetto.com, 1
 studio-fotografico.ru, 1
 studiodentisticosanmarco.it, 1
 studiodewit.nl, 1
 studiodoprazer.com.br, 1
 studiogavioli.com, 1
 studiograou.com, 1
@@ -30220,17 +30204,16 @@ studium.cz, 1
 studlan.no, 1
 studport.rv.ua, 1
 studyabroadstation.com, 1
 studying-neet.com, 1
 stuermer.me, 1
 stuetzredli.ch, 1
 stuff-fibre.co.nz, 1
 stuffi.fr, 1
-stuffie.org, 1
 stuka-art.de, 1
 stulda.cz, 0
 stumeta.de, 1
 stumeta2018.de, 1
 stumf.si, 1
 stuntmen.xyz, 1
 stupendous.net, 0
 stupidstatetricks.com, 1
@@ -31071,17 +31054,16 @@ tenseapp.pl, 1
 tenshoku-hanashi.com, 1
 tent.io, 1
 tenta.com, 1
 tentabrowser.com, 1
 tentations-voyages.com, 0
 tenthousandcoffees.com, 1
 tenyx.de, 1
 tenzer.dk, 1
-teodio.cl, 1
 teoskanta.fi, 1
 tepid.org, 1
 tepitus.de, 1
 tequilazor.com, 1
 terabyte.services, 1
 teracloud.at, 1
 teranacreative.com, 1
 teranga.ch, 1
@@ -31622,17 +31604,16 @@ ti-planet.org, 1
 tiacollection.com, 1
 tiagonunes.pt, 1
 tiaki.org, 1
 tianeptine.com, 1
 tianshili.me, 1
 tianxicaipiao.com, 1
 tianxicaipiao.win, 1
 tianxicp.com, 1
-tibbitshall.ca, 1
 tibipg.com, 1
 tibovanheule.site, 1
 ticfleet.com, 1
 ticketluck.com, 1
 ticketmates.com.au, 1
 ticketpro.ca, 1
 ticketslover.com, 1
 ticketsmate.com, 1
@@ -31650,17 +31631,16 @@ tiendavertigo.com, 1
 tiens-ib.cz, 1
 tier-1-entrepreneur.com, 1
 tierarztpraxis-bogenhausen.de, 1
 tierarztpraxis-weinert.de, 1
 tiernanx.com, 1
 ties.com, 1
 tiew.pl, 1
 tifan.net, 1
-tiffanytravels.com, 1
 tiffnix.com, 1
 tigerchef.com, 1
 tigerdile.com, 1
 tiggeriffic.com, 1
 tigit.co.nz, 1
 tiglitub.com, 1
 tiihosen.fi, 1
 tijden.nu, 1
@@ -31782,21 +31762,21 @@ tkat.ch, 1
 tkeycoin.com, 1
 tkgpm.com, 1
 tkjg.fi, 1
 tkn.me, 1
 tkn.tokyo, 1
 tkts.cl, 1
 tkusano.jp, 1
 tkw01536.de, 1
+tlach.cz, 1
 tlca.org, 1
 tlcnet.info, 1
 tlehseasyads.com, 1
 tlo.xyz, 1
-tloxygen.com, 1
 tls-proxy.de, 1
 tls.builders, 1
 tls.care, 1
 tls1914.org, 1
 tlsrobot.se, 1
 tlthings.net, 1
 tlys.de, 1
 tm.id.au, 1
@@ -32031,17 +32011,16 @@ topaxi.codes, 1
 topbilan.com, 1
 topbounce.com, 1
 topbouncycastles.co.uk, 1
 topbrakes.com, 1
 topclassfun.ie, 1
 topdesk.net, 1
 topdetoxcleanse.com, 1
 topdevbox.net, 1
-topdogsinflatables.co.uk, 1
 topeng-emas.com, 1
 topesb.com, 1
 topfivepercent.co.uk, 1
 topicdesk.com, 1
 topicit.net, 1
 topirishcasinos.com, 1
 topjobs.ch, 1
 toplist.eu, 1
@@ -33710,17 +33689,16 @@ vollans.id.au, 1
 voloevents.com, 1
 volta.io, 1
 voltimax.com, 1
 volto.io, 1
 volunteeringmatters.org.uk, 1
 vomitb.in, 1
 vonauw.com, 1
 vonborstelboerner.de, 1
-vonedelmann.de, 0
 vongerlach.at, 1
 vonniehudson.com, 1
 vonski.pl, 1
 voodoochile.at, 1
 vop.li, 1
 vorderklier.de, 1
 vorkbaard.nl, 1
 vorlicek.de, 1
@@ -33751,17 +33729,16 @@ voyageforum.com, 1
 voyagesaufildespages.be, 1
 voyageschine.com, 1
 voyagesdetective.fr, 1
 vozami.com, 1
 vpc-display.com, 1
 vpn.black, 1
 vpn.ht, 1
 vpnservice.nl, 1
-vpnzoom.com, 1
 vpsboard.com, 1
 vpsdream.dk, 1
 vrandopulo.ru, 1
 vranjske.co.rs, 1
 vreeman.com, 1
 vriesdonkow.be, 1
 vrijgezellen-feest.com, 1
 vrijgezellenfeestzwolle.com, 1
@@ -34711,17 +34688,16 @@ women-only.net, 1
 womenshairlossproject.com, 1
 wonabo.com, 1
 wonderbill.com, 1
 wonderbooks.club, 1
 wondergorilla.com, 1
 wonderhost.info, 1
 wonderhowto.com, 1
 wonderlandmovies.de, 1
-wondermags.com, 1
 wondershift.biz, 1
 woodbury.io, 1
 woodcoin.org, 1
 woodev.us, 1
 woodlandhillselectrical.com, 1
 woodlandsmetro.church, 1
 woodlandsvale.uk, 1
 woodlandwindows.com, 1
@@ -35205,16 +35181,17 @@ xn--jbs-tna.de, 1
 xn--jda.tk, 1
 xn--jp8hx8f.ws, 1
 xn--jywq5uqwqxhd2onsij.jp, 1
 xn--kda.tk, 1
 xn--knstler-n2a.tips, 0
 xn--ktha-kamrater-pfba.se, 1
 xn--lna-2000-9za.nu, 1
 xn--lna-4000-9za.nu, 1
+xn--lnakuten-9za.com, 1
 xn--love-un4c7e0d4a.com, 1
 xn--lsaupp-iua.se, 1
 xn--lsupp-mra.net, 1
 xn--manuela-stsser-psb.de, 1
 xn--maraa-rta.org, 1
 xn--mentaltraining-fr-musiker-uwc.ch, 1
 xn--mgbbh2a9fub.xn--ngbc5azd, 0
 xn--mgbmmp7eub.com, 1
--- a/servo/components/style/gecko/rules.rs
+++ b/servo/components/style/gecko/rules.rs
@@ -16,17 +16,18 @@ use gecko_bindings::sugar::ns_css_value:
 use gecko_bindings::sugar::refptr::{RefPtr, UniqueRefPtr};
 use nsstring::nsString;
 use properties::longhands::font_language_override;
 use shared_lock::{ToCssWithGuard, SharedRwLockReadGuard};
 use std::fmt::{self, Write};
 use std::str;
 use str::CssStringWriter;
 use values::computed::font::FamilyName;
-use values::specified::font::{FontTag, FontVariationSettings, SpecifiedFontFeatureSettings};
+use values::generics::font::FontTag;
+use values::specified::font::{FontVariationSettings, SpecifiedFontFeatureSettings};
 
 /// A @font-face rule
 pub type FontFaceRule = RefPtr<nsCSSFontFaceRule>;
 
 impl ToNsCssValue for FamilyName {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         nscssvalue.set_string_from_atom(&self.name)
     }
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1447,18 +1447,17 @@ impl Clone for ${style_struct.gecko_stru
         }
     }
 
     pub fn reset_${ident}(&mut self, other: &Self) {
         self.copy_${ident}_from(other)
     }
 
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
-        use values::generics::font::{FontSettings, ${tag_type}};
-        use values::specified::font::FontTag;
+        use values::generics::font::{FontSettings, FontTag, ${tag_type}};
 
         FontSettings(
             self.gecko.mFont.${gecko_ffi_name}.iter().map(|gecko_font_setting| {
                 ${tag_type} {
                     tag: FontTag(gecko_font_setting.mTag),
                     value: gecko_font_setting.mValue as ${value_type},
                 }
             }).collect::<Vec<_>>().into_boxed_slice()
@@ -2385,17 +2384,17 @@ fn static_assert() {
 
     pub fn unzoom_fonts(&mut self, device: &Device) {
         self.gecko.mSize = device.unzoom_text(Au(self.gecko.mSize)).0;
         self.gecko.mScriptUnconstrainedSize = device.unzoom_text(Au(self.gecko.mScriptUnconstrainedSize)).0;
         self.gecko.mFont.size = device.unzoom_text(Au(self.gecko.mFont.size)).0;
     }
 
     pub fn set_font_size(&mut self, v: FontSize) {
-        use values::specified::font::KeywordSize;
+        use values::generics::font::KeywordSize;
         self.gecko.mSize = v.size().0;
         self.gecko.mScriptUnconstrainedSize = v.size().0;
         if let Some(info) = v.keyword_info {
             self.gecko.mFontSizeKeyword = match info.kw {
                 KeywordSize::XXSmall => structs::NS_STYLE_FONT_SIZE_XXSMALL,
                 KeywordSize::XSmall => structs::NS_STYLE_FONT_SIZE_XSMALL,
                 KeywordSize::Small => structs::NS_STYLE_FONT_SIZE_SMALL,
                 KeywordSize::Medium => structs::NS_STYLE_FONT_SIZE_MEDIUM,
@@ -2597,18 +2596,17 @@ fn static_assert() {
             self.gecko.mFontSizeFactor = 1.;
             self.gecko.mFontSizeOffset = 0;
             self.gecko.mScriptUnconstrainedSize = parent.gecko.mScriptUnconstrainedSize;
         }
         self.fixup_font_min_size(device);
     }
 
     pub fn clone_font_size(&self) -> FontSize {
-        use values::computed::font::KeywordInfo;
-        use values::specified::font::KeywordSize;
+        use values::generics::font::{KeywordInfo, KeywordSize};
         let size = Au(self.gecko.mSize).into();
         let kw = match self.gecko.mFontSizeKeyword as u32 {
             structs::NS_STYLE_FONT_SIZE_XXSMALL => KeywordSize::XXSmall,
             structs::NS_STYLE_FONT_SIZE_XSMALL => KeywordSize::XSmall,
             structs::NS_STYLE_FONT_SIZE_SMALL => KeywordSize::Small,
             structs::NS_STYLE_FONT_SIZE_MEDIUM => KeywordSize::Medium,
             structs::NS_STYLE_FONT_SIZE_LARGE => KeywordSize::Large,
             structs::NS_STYLE_FONT_SIZE_XLARGE => KeywordSize::XLarge,
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -47,24 +47,22 @@ use values::computed::ToComputedValue;
 use values::computed::transform::{DirectionVector, Matrix, Matrix3D};
 use values::computed::transform::TransformOperation as ComputedTransformOperation;
 use values::computed::transform::Transform as ComputedTransform;
 use values::computed::transform::Rotate as ComputedRotate;
 use values::computed::transform::Translate as ComputedTranslate;
 use values::computed::transform::Scale as ComputedScale;
 use values::generics::transform::{self, Rotate, Translate, Scale, Transform, TransformOperation};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
-use values::generics::font::FontSettings as GenericFontSettings;
+use values::generics::font::{FontSettings as GenericFontSettings, FontTag, VariationValue};
 use values::computed::font::FontVariationSettings;
-use values::generics::font::VariationValue;
 use values::generics::effects::Filter;
 use values::generics::position as generic_position;
 use values::generics::svg::{SVGLength,  SvgLengthOrPercentageOrNumber, SVGPaint};
 use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
-use values::specified::font::FontTag;
 use void::{self, Void};
 
 /// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
 pub trait RepeatableListAnimatable: Animate {}
 
 /// Returns true if this nsCSSPropertyID is one of the animatable properties.
 #[cfg(feature = "gecko")]
 pub fn nscsspropertyid_is_animatable(property: nsCSSPropertyID) -> bool {
--- a/servo/components/style/values/animated/effects.rs
+++ b/servo/components/style/values/animated/effects.rs
@@ -8,17 +8,17 @@ use properties::longhands::box_shadow::c
 use properties::longhands::filter::computed_value::T as ComputedFilterList;
 use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
 use std::cmp;
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
 use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use values::animated::color::RGBA;
 use values::computed::{Angle, Number};
-use values::computed::length::{Length, NonNegativeLength};
+use values::computed::length::Length;
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::effects::BoxShadow as GenericBoxShadow;
 use values::generics::effects::Filter as GenericFilter;
 use values::generics::effects::SimpleShadow as GenericSimpleShadow;
 
 /// An animated value for the `box-shadow` property.
 pub type BoxShadowList = ShadowList<BoxShadow>;
 
@@ -28,33 +28,33 @@ pub type TextShadowList = ShadowList<Sim
 /// An animated value for shadow lists.
 ///
 /// <https://drafts.csswg.org/css-transitions/#animtype-shadow-list>
 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 #[derive(Clone, Debug, PartialEq)]
 pub struct ShadowList<Shadow>(Vec<Shadow>);
 
 /// An animated value for a single `box-shadow`.
-pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, NonNegativeLength, Length>;
+pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>;
 
 /// An animated value for the `filter` property.
 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 #[derive(Clone, Debug, PartialEq)]
 pub struct FilterList(pub Vec<Filter>);
 
 /// An animated value for a single `filter`.
 #[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Number, NonNegativeLength, SimpleShadow>;
+pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>;
 
 /// An animated value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Number, NonNegativeLength, Impossible>;
+pub type Filter = GenericFilter<Angle, Number, Length, Impossible>;
 
 /// An animated value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, NonNegativeLength>;
+pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;
 
 impl ToAnimatedValue for ComputedBoxShadowList {
     type AnimatedValue = BoxShadowList;
 
     #[inline]
     fn to_animated_value(self) -> Self::AnimatedValue {
         ShadowList(self.0.to_animated_value())
     }
--- a/servo/components/style/values/animated/mod.rs
+++ b/servo/components/style/values/animated/mod.rs
@@ -12,17 +12,16 @@ use app_units::Au;
 use euclid::{Point2D, Size2D};
 use smallvec::SmallVec;
 use values::computed::Angle as ComputedAngle;
 use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
 #[cfg(feature = "servo")]
 use values::computed::ComputedUrl;
 use values::computed::MaxLength as ComputedMaxLength;
 use values::computed::MozLength as ComputedMozLength;
-use values::computed::NonNegativeLength as ComputedNonNegativeLength;
 use values::specified::url::SpecifiedUrl;
 
 pub mod color;
 pub mod effects;
 
 /// Animate from one value to another.
 ///
 /// This trait is derivable with `#[derive(Animate)]`. The derived
@@ -256,30 +255,16 @@ macro_rules! trivial_to_animated_value {
 trivial_to_animated_value!(Au);
 trivial_to_animated_value!(ComputedAngle);
 trivial_to_animated_value!(SpecifiedUrl);
 #[cfg(feature = "servo")]
 trivial_to_animated_value!(ComputedUrl);
 trivial_to_animated_value!(bool);
 trivial_to_animated_value!(f32);
 
-impl ToAnimatedValue for ComputedNonNegativeLength {
-    type AnimatedValue = Self;
-
-    #[inline]
-    fn to_animated_value(self) -> Self {
-        self
-    }
-
-    #[inline]
-    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
-        ComputedNonNegativeLength::new(animated.px().max(0.))
-    }
-}
-
 impl ToAnimatedValue for ComputedBorderCornerRadius {
     type AnimatedValue = Self;
 
     #[inline]
     fn to_animated_value(self) -> Self {
         self
     }
 
@@ -375,8 +360,21 @@ where
     #[inline]
     fn to_animated_zero(&self) -> Result<Self, ()> {
         match *self {
             Some(ref value) => Ok(Some(value.to_animated_zero()?)),
             None => Ok(None),
         }
     }
 }
+
+impl<T> ToAnimatedZero for Size2D<T>
+where
+    T: ToAnimatedZero,
+{
+    #[inline]
+    fn to_animated_zero(&self) -> Result<Self, ()> {
+        Ok(Size2D::new(
+            self.width.to_animated_zero()?,
+            self.height.to_animated_zero()?,
+        ))
+    }
+}
--- a/servo/components/style/values/computed/border.rs
+++ b/servo/components/style/values/computed/border.rs
@@ -64,24 +64,16 @@ impl BorderSpacing {
 
 impl BorderCornerRadius {
     /// Returns `0 0`.
     pub fn zero() -> Self {
         GenericBorderCornerRadius(Size::new(LengthOrPercentage::zero(), LengthOrPercentage::zero()))
     }
 }
 
-impl ToAnimatedZero for BorderSpacing {
-    #[inline]
-    fn to_animated_zero(&self) -> Result<Self, ()> {
-        // FIXME(emilio): Why?
-        Err(())
-    }
-}
-
 impl ToAnimatedZero for BorderCornerRadius {
     #[inline]
     fn to_animated_zero(&self) -> Result<Self, ()> {
         // FIXME(nox): Why?
         Err(())
     }
 }
 
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -18,17 +18,18 @@ use std::fmt::{self, Write};
 #[cfg(feature = "gecko")]
 use std::hash::{Hash, Hasher};
 #[cfg(feature = "servo")]
 use std::slice;
 use style_traits::{CssWriter, ParseError, ToCss};
 use values::CSSFloat;
 use values::animated::{ToAnimatedValue, ToAnimatedZero};
 use values::computed::{Context, NonNegativeLength, ToComputedValue, Integer, Number};
-use values::generics::font::{FontSettings, FeatureTagValue, VariationValue};
+use values::generics::font::{FontSettings, FeatureTagValue};
+use values::generics::font::{KeywordInfo as GenericKeywordInfo, VariationValue};
 use values::specified::font as specified;
 use values::specified::length::{FontBaseSize, NoCalcLength};
 
 pub use values::computed::Length as MozScriptMinSize;
 pub use values::specified::font::{XTextZoom, XLang, MozScriptSizeMultiplier, FontSynthesis};
 
 /// As of CSS Fonts Module Level 3, only the following values are
 /// valid: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
@@ -44,60 +45,18 @@ pub struct FontWeight(pub u16);
 /// The computed value of font-size
 pub struct FontSize {
     /// The size.
     pub size: NonNegativeLength,
     /// If derived from a keyword, the keyword and additional transformations applied to it
     pub keyword_info: Option<KeywordInfo>,
 }
 
-#[derive(Animate, ComputeSquaredDistance, MallocSizeOf, ToAnimatedValue, ToAnimatedZero)]
-#[derive(Clone, Copy, Debug, PartialEq)]
-/// Additional information for keyword-derived font sizes.
-pub struct KeywordInfo {
-    /// The keyword used
-    pub kw: specified::KeywordSize,
-    /// A factor to be multiplied by the computed size of the keyword
-    pub factor: f32,
-    /// An additional Au offset to add to the kw*factor in the case of calcs
-    pub offset: NonNegativeLength,
-}
-
-impl KeywordInfo {
-    /// Computes the final size for this font-size keyword, accounting for
-    /// text-zoom.
-    pub fn to_computed_value(&self, context: &Context) -> NonNegativeLength {
-        let base = context.maybe_zoom_text(self.kw.to_computed_value(context));
-        base.scale_by(self.factor) + context.maybe_zoom_text(self.offset)
-    }
-
-    /// Given a parent keyword info (self), apply an additional factor/offset to it
-    pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self {
-        KeywordInfo {
-            kw: self.kw,
-            factor: self.factor * factor,
-            offset: self.offset.scale_by(factor) + offset,
-        }
-    }
-
-    /// KeywordInfo value for font-size: medium
-    pub fn medium() -> Self {
-        specified::KeywordSize::Medium.into()
-    }
-}
-
-impl From<specified::KeywordSize> for KeywordInfo {
-    fn from(x: specified::KeywordSize) -> Self {
-        KeywordInfo {
-            kw: x,
-            factor: 1.,
-            offset: Au(0).into(),
-        }
-    }
-}
+/// Additional information for computed keyword-derived font sizes.
+pub type KeywordInfo = GenericKeywordInfo<NonNegativeLength>;
 
 impl FontWeight {
     /// Value for normal
     pub fn normal() -> Self {
         FontWeight(400)
     }
 
     /// Value for bold
--- a/servo/components/style/values/computed/length.rs
+++ b/servo/components/style/values/computed/length.rs
@@ -810,16 +810,30 @@ impl LengthOrNumber {
 }
 
 /// Either a computed `<length>` or the `normal` keyword.
 pub type LengthOrNormal = Either<Length, Normal>;
 
 /// A wrapper of Length, whose value must be >= 0.
 pub type NonNegativeLength = NonNegative<Length>;
 
+impl ToAnimatedValue for NonNegativeLength {
+    type AnimatedValue = Length;
+
+    #[inline]
+    fn to_animated_value(self) -> Self::AnimatedValue {
+        self.0
+    }
+
+    #[inline]
+    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
+        NonNegativeLength::new(animated.px().max(0.))
+    }
+}
+
 impl NonNegativeLength {
     /// Create a NonNegativeLength.
     #[inline]
     pub fn new(px: CSSFloat) -> Self {
         NonNegative(Length::new(px.max(0.)))
     }
 
     /// Return a zero value.
--- a/servo/components/style/values/generics/border.rs
+++ b/servo/components/style/values/generics/border.rs
@@ -38,17 +38,17 @@ impl<L> BorderCornerRadius<L> {
     /// Trivially create a `BorderCornerRadius`.
     pub fn new(w: L, h: L) -> Self {
         BorderCornerRadius(Size::new(w, h))
     }
 }
 
 /// A generic value for the `border-spacing` property.
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf)]
-#[derive(PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
+#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)]
 pub struct BorderSpacing<L>(pub Size<L>);
 
 impl<L> BorderSpacing<L> {
     /// Trivially create a `BorderCornerRadius`.
     pub fn new(w: L, h: L) -> Self {
         BorderSpacing(Size::new(w, h))
     }
 }
--- a/servo/components/style/values/generics/font.rs
+++ b/servo/components/style/values/generics/font.rs
@@ -1,21 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Generic types for font stuff.
 
+use app_units::Au;
+use byteorder::{ReadBytesExt, BigEndian};
 use cssparser::Parser;
 use num_traits::One;
 use parser::{Parse, ParserContext};
 use std::fmt::{self, Write};
-use style_traits::{CssWriter, ParseError, ToCss};
+use std::io::Cursor;
+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
-use values::specified::font::FontTag;
 
 /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value
 #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
 pub struct FeatureTagValue<Integer> {
     /// A four-character tag, packed into a u32 (one byte per character).
     pub tag: FontTag,
     /// The actual value.
     pub value: Integer,
@@ -112,8 +114,149 @@ impl<T: ToCss> ToCss for FontSettings<T>
             }
             first = false;
             item.to_css(dest)?;
         }
 
         Ok(())
     }
 }
+
+/// A font four-character tag, represented as a u32 for convenience.
+///
+/// See:
+///   https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
+///   https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
+///
+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
+pub struct FontTag(pub u32);
+
+impl ToCss for FontTag {
+    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+    where
+        W: Write,
+    {
+        use byteorder::{BigEndian, ByteOrder};
+        use std::str;
+
+        let mut raw = [0u8; 4];
+        BigEndian::write_u32(&mut raw, self.0);
+        str::from_utf8(&raw).unwrap_or_default().to_css(dest)
+    }
+}
+
+impl Parse for FontTag {
+    fn parse<'i, 't>(
+        _context: &ParserContext,
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        let location = input.current_source_location();
+        let tag = input.expect_string()?;
+
+        // allowed strings of length 4 containing chars: <U+20, U+7E>
+        if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
+            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
+        }
+
+        let mut raw = Cursor::new(tag.as_bytes());
+        Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
+    }
+}
+
+#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf)]
+#[derive(PartialEq, ToAnimatedValue, ToAnimatedZero)]
+/// Additional information for keyword-derived font sizes.
+pub struct KeywordInfo<Length> {
+    /// The keyword used
+    pub kw: KeywordSize,
+    /// A factor to be multiplied by the computed size of the keyword
+    pub factor: f32,
+    /// An additional Au offset to add to the kw*factor in the case of calcs
+    pub offset: Length,
+}
+
+impl<L> KeywordInfo<L>
+where
+    Au: Into<L>,
+{
+    /// KeywordInfo value for font-size: medium
+    pub fn medium() -> Self {
+        KeywordSize::Medium.into()
+    }
+}
+
+impl<L> From<KeywordSize> for KeywordInfo<L>
+where
+    Au: Into<L>,
+{
+    fn from(x: KeywordSize) -> Self {
+        KeywordInfo {
+            kw: x,
+            factor: 1.,
+            offset: Au(0).into(),
+        }
+    }
+}
+
+/// CSS font keywords
+#[derive(Animate, ComputeSquaredDistance, MallocSizeOf, ToAnimatedValue, ToAnimatedZero)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[allow(missing_docs)]
+pub enum KeywordSize {
+    XXSmall = 1, // This is to enable the NonZero optimization
+                 // which simplifies the representation of Option<KeywordSize>
+                 // in bindgen
+    XSmall,
+    Small,
+    Medium,
+    Large,
+    XLarge,
+    XXLarge,
+    // This is not a real font keyword and will not parse
+    // HTML font-size 7 corresponds to this value
+    XXXLarge,
+}
+
+impl KeywordSize {
+    /// Convert to an HTML <font size> value
+    pub fn html_size(&self) -> u8 {
+        match *self {
+            KeywordSize::XXSmall => 0,
+            KeywordSize::XSmall => 1,
+            KeywordSize::Small => 2,
+            KeywordSize::Medium => 3,
+            KeywordSize::Large => 4,
+            KeywordSize::XLarge => 5,
+            KeywordSize::XXLarge => 6,
+            KeywordSize::XXXLarge => 7,
+        }
+    }
+}
+
+impl Default for KeywordSize {
+    fn default() -> Self {
+        KeywordSize::Medium
+    }
+}
+
+impl ToCss for KeywordSize {
+    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+    where
+        W: Write,
+    {
+        dest.write_str(match *self {
+            KeywordSize::XXSmall => "xx-small",
+            KeywordSize::XSmall => "x-small",
+            KeywordSize::Small => "small",
+            KeywordSize::Medium => "medium",
+            KeywordSize::Large => "large",
+            KeywordSize::XLarge => "x-large",
+            KeywordSize::XXLarge => "xx-large",
+            KeywordSize::XXXLarge => {
+                debug_assert!(
+                    false,
+                    "We should never serialize specified values set via HTML presentation attributes"
+                );
+                "-servo-xxx-large"
+            },
+        })
+    }
+}
--- a/servo/components/style/values/generics/size.rs
+++ b/servo/components/style/values/generics/size.rs
@@ -9,17 +9,17 @@ use euclid::Size2D;
 use parser::ParserContext;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ParseError, ToCss};
 use values::animated::ToAnimatedValue;
 
 /// A generic size, for `border-*-radius` longhand properties, or
 /// `border-spacing`.
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
-#[derive(MallocSizeOf, PartialEq, ToComputedValue)]
+#[derive(MallocSizeOf, PartialEq, ToAnimatedZero, ToComputedValue)]
 pub struct Size<L>(pub Size2D<L>);
 
 impl<L> Size<L> {
     #[inline]
     /// Create a new `Size` for an area of given width and height.
     pub fn new(width: L, height: L) -> Size<L> {
         Size(Size2D::new(width, height))
     }
--- a/servo/components/style/values/specified/font.rs
+++ b/servo/components/style/values/specified/font.rs
@@ -16,17 +16,18 @@ use parser::{Parse, ParserContext};
 use properties::longhands::system_font::SystemFont;
 #[allow(unused_imports)]
 use std::ascii::AsciiExt;
 use std::fmt::{self, Write};
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 use values::CustomIdent;
 use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue};
 use values::computed::font::{SingleFontFamily, FontFamilyList, FamilyName};
-use values::generics::font::{FontSettings, FeatureTagValue, VariationValue};
+use values::generics::font::{FontSettings, FontTag, FeatureTagValue};
+use values::generics::font::{KeywordInfo as GenericKeywordInfo, KeywordSize, VariationValue};
 use values::specified::{AllowQuirks, Integer, LengthOrPercentage, NoCalcLength, Number};
 use values::specified::length::{AU_PER_PT, AU_PER_PX, FontBaseSize};
 
 const DEFAULT_SCRIPT_MIN_SIZE_PT: u32 = 8;
 const DEFAULT_SCRIPT_SIZE_MULTIPLIER: f64 = 0.71;
 
 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToCss)]
 /// A specified font-weight value
@@ -129,17 +130,17 @@ pub enum FontSize {
     /// will be 1 (with offset 0), but we cascade keywordness even
     /// after font-relative (percent and em) values
     /// have been applied, which is where the ratio
     /// comes in. The offset comes in if we cascaded a calc value,
     /// where the font-relative portion (em and percentage) will
     /// go into the ratio, and the remaining units all computed together
     /// will go into the offset.
     /// See bug 1355707.
-    Keyword(computed::KeywordInfo),
+    Keyword(KeywordInfo),
     /// font-size: smaller
     Smaller,
     /// font-size: larger
     Larger,
     /// Derived from a specified system font.
     System(SystemFont)
 }
 
@@ -335,88 +336,50 @@ impl Parse for FontSizeAdjust {
         if input.try(|input| input.expect_ident_matching("none")).is_ok() {
             return Ok(FontSizeAdjust::None);
         }
 
         Ok(FontSizeAdjust::Number(Number::parse_non_negative(context, input)?))
     }
 }
 
-/// CSS font keywords
-#[derive(Animate, ComputeSquaredDistance, MallocSizeOf, ToAnimatedValue, ToAnimatedZero)]
-#[derive(Clone, Copy, Debug, PartialEq)]
-#[allow(missing_docs)]
-pub enum KeywordSize {
-    XXSmall = 1, // This is to enable the NonZero optimization
-                 // which simplifies the representation of Option<KeywordSize>
-                 // in bindgen
-    XSmall,
-    Small,
-    Medium,
-    Large,
-    XLarge,
-    XXLarge,
-    // This is not a real font keyword and will not parse
-    // HTML font-size 7 corresponds to this value
-    XXXLarge,
+/// Additional information for specified keyword-derived font sizes.
+pub type KeywordInfo = GenericKeywordInfo<NonNegativeLength>;
+
+impl KeywordInfo {
+    /// Computes the final size for this font-size keyword, accounting for
+    /// text-zoom.
+    pub fn to_computed_value(&self, context: &Context) -> NonNegativeLength {
+        let base = context.maybe_zoom_text(self.kw.to_computed_value(context));
+        base.scale_by(self.factor) + context.maybe_zoom_text(self.offset)
+    }
+
+    /// Given a parent keyword info (self), apply an additional factor/offset to it
+    pub fn compose(self, factor: f32, offset: NonNegativeLength) -> Self {
+        KeywordInfo {
+            kw: self.kw,
+            factor: self.factor * factor,
+            offset: self.offset.scale_by(factor) + offset,
+        }
+    }
 }
 
 impl KeywordSize {
-    /// Parse a keyword size
+    /// Parses a keyword size.
     pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
         try_match_ident_ignore_ascii_case! { input,
             "xx-small" => Ok(KeywordSize::XXSmall),
             "x-small" => Ok(KeywordSize::XSmall),
             "small" => Ok(KeywordSize::Small),
             "medium" => Ok(KeywordSize::Medium),
             "large" => Ok(KeywordSize::Large),
             "x-large" => Ok(KeywordSize::XLarge),
             "xx-large" => Ok(KeywordSize::XXLarge),
         }
     }
-
-    /// Convert to an HTML <font size> value
-    pub fn html_size(&self) -> u8 {
-        match *self {
-            KeywordSize::XXSmall => 0,
-            KeywordSize::XSmall => 1,
-            KeywordSize::Small => 2,
-            KeywordSize::Medium => 3,
-            KeywordSize::Large => 4,
-            KeywordSize::XLarge => 5,
-            KeywordSize::XXLarge => 6,
-            KeywordSize::XXXLarge => 7,
-        }
-    }
-}
-
-impl Default for KeywordSize {
-    fn default() -> Self {
-        KeywordSize::Medium
-    }
-}
-
-impl ToCss for KeywordSize {
-    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
-    where
-        W: Write,
-    {
-        dest.write_str(match *self {
-            KeywordSize::XXSmall => "xx-small",
-            KeywordSize::XSmall => "x-small",
-            KeywordSize::Small => "small",
-            KeywordSize::Medium => "medium",
-            KeywordSize::Large => "large",
-            KeywordSize::XLarge => "x-large",
-            KeywordSize::XXLarge => "xx-large",
-            KeywordSize::XXXLarge => unreachable!("We should never serialize \
-                                      specified values set via
-                                      HTML presentation attributes"),
-        })
-    }
 }
 
 /// This is the ratio applied for font-size: larger
 /// and smaller by both Firefox and Chrome
 const LARGER_FONT_SIZE_RATIO: f32 = 1.2;
 
 /// The default font size.
 pub const FONT_MEDIUM_PX: i32 = 16;
@@ -667,17 +630,17 @@ impl FontSize {
         } else {
             None
         }
     }
 
     #[inline]
     /// Get initial value for specified font size.
     pub fn medium() -> Self {
-        FontSize::Keyword(computed::KeywordInfo::medium())
+        FontSize::Keyword(KeywordInfo::medium())
     }
 
     /// Parses a font-size, with quirks.
     pub fn parse_quirky<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
         allow_quirks: AllowQuirks
     ) -> Result<FontSize, ParseError<'i>> {
@@ -1940,60 +1903,16 @@ impl Parse for FontLanguageOverride {
             return Ok(FontLanguageOverride::Normal)
         }
 
         let string = input.expect_string()?;
         Ok(FontLanguageOverride::Override(string.as_ref().to_owned().into_boxed_str()))
     }
 }
 
-/// A font four-character tag, represented as a u32 for convenience.
-///
-/// See:
-///   https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
-///   https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
-///
-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
-pub struct FontTag(pub u32);
-
-impl Parse for FontTag {
-    fn parse<'i, 't>(
-        _context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        use byteorder::{ReadBytesExt, BigEndian};
-        use std::io::Cursor;
-
-        let location = input.current_source_location();
-        let tag = input.expect_string()?;
-
-        // allowed strings of length 4 containing chars: <U+20, U+7E>
-        if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
-            return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
-        }
-
-        let mut raw = Cursor::new(tag.as_bytes());
-        Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
-    }
-}
-
-impl ToCss for FontTag {
-    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
-    where
-        W: Write,
-    {
-        use byteorder::{BigEndian, ByteOrder};
-        use std::str;
-
-        let mut raw = [0u8; 4];
-        BigEndian::write_u32(&mut raw, self.0);
-        str::from_utf8(&raw).unwrap_or_default().to_css(dest)
-    }
-}
-
 /// This property provides low-level control over OpenType or TrueType font
 /// variations.
 pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
 
 fn parse_one_feature_value<'i, 't>(
     context: &ParserContext,
     input: &mut Parser<'i, 't>,
 ) -> Result<Integer, ParseError<'i>> {
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -197,27 +197,27 @@ class GeckoInstance(object):
         else:
             profile_args = self.profile_args
             profile_path = profile
 
             # If a path to a profile is given then clone it
             if isinstance(profile_path, basestring):
                 profile_args["path_from"] = profile_path
                 profile_args["path_to"] = tempfile.mkdtemp(
-                    suffix=".{}".format(profile_name or os.path.basename(profile_path)),
+                    suffix=u".{}".format(profile_name or os.path.basename(profile_path)),
                     dir=self.workspace)
                 # The target must not exist yet
                 os.rmdir(profile_args["path_to"])
 
                 profile = Profile.clone(**profile_args)
 
             # Otherwise create a new profile
             else:
                 profile_args["profile"] = tempfile.mkdtemp(
-                    suffix=".{}".format(profile_name or "mozrunner"),
+                    suffix=u".{}".format(profile_name or "mozrunner"),
                     dir=self.workspace)
                 profile = Profile(**profile_args)
                 profile.create_new = True
 
         if isinstance(self.profile, Profile):
             self.profile.cleanup()
 
         self._profile = profile
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
@@ -2,21 +2,16 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import, print_function
 
 from marionette_driver.errors import SessionNotCreatedException
 from marionette_harness import MarionetteTestCase
 
-# Unlike python 3, python 2 doesn't have a proper implementation of realpath or
-# samefile for Windows. However this function, which does exactly what we want,
-# was added to python 2 to fix an issue with tcl installations and symlinks.
-from FixTk import convert_path
-
 
 class TestCapabilities(MarionetteTestCase):
 
     def setUp(self):
         super(TestCapabilities, self).setUp()
         self.caps = self.marionette.session_capabilities
         with self.marionette.using_context("chrome"):
             self.appinfo = self.marionette.execute_script("""
@@ -57,19 +52,19 @@ class TestCapabilities(MarionetteTestCas
         self.assertEqual(self.caps["moz:processID"], self.appinfo["processID"])
         self.assertEqual(self.marionette.process_id, self.appinfo["processID"])
 
         self.assertIn("moz:profile", self.caps)
         if self.marionette.instance is not None:
             if self.caps["browserName"] == "fennec":
                 current_profile = self.marionette.instance.runner.device.app_ctx.remote_profile
             else:
-                current_profile = convert_path(self.marionette.instance.runner.profile.profile)
-            self.assertEqual(convert_path(str(self.caps["moz:profile"])), current_profile)
-            self.assertEqual(convert_path(str(self.marionette.profile)), current_profile)
+                current_profile = self.marionette.profile_path
+            # Bug 1438461 - mozprofile uses lower-case letters even on case-sensitive filesystems
+            self.assertEqual(self.caps["moz:profile"].lower(), current_profile.lower())
 
         self.assertIn("moz:accessibilityChecks", self.caps)
         self.assertFalse(self.caps["moz:accessibilityChecks"])
 
         self.assertIn("moz:useNonSpecCompliantPointerOrigin", self.caps)
         self.assertFalse(self.caps["moz:useNonSpecCompliantPointerOrigin"])
 
         self.assertIn("moz:webdriverClick", self.caps)
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_profile_management.py
@@ -1,8 +1,10 @@
+# coding=UTF-8
+
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import absolute_import
 
 import os
 import shutil
@@ -167,16 +169,34 @@ class TestSwitchProfileWithoutWorkspace(
     def test_new_named_profile(self):
         self.marionette.instance.switch_profile("foobar")
         self.marionette.start_session()
 
         self.assertNotEqual(self.profile_path, self.orig_profile_path)
         self.assertIn("foobar", self.profile_path)
         self.assertFalse(os.path.exists(self.orig_profile_path))
 
+    def test_new_named_profile_unicode(self):
+        """Test using unicode string with 1-4 bytes encoding works."""
+        self.marionette.instance.switch_profile(u"$¢€🍪")
+        self.marionette.start_session()
+
+        self.assertNotEqual(self.profile_path, self.orig_profile_path)
+        self.assertIn(u"$¢€🍪", self.profile_path)
+        self.assertFalse(os.path.exists(self.orig_profile_path))
+
+    def test_new_named_profile_unicode_escape_characters(self):
+        """Test using escaped unicode string with 1-4 bytes encoding works."""
+        self.marionette.instance.switch_profile(u"\u0024\u00A2\u20AC\u1F36A")
+        self.marionette.start_session()
+
+        self.assertNotEqual(self.profile_path, self.orig_profile_path)
+        self.assertIn(u"\u0024\u00A2\u20AC\u1F36A", self.profile_path)
+        self.assertFalse(os.path.exists(self.orig_profile_path))
+
     def test_clone_existing_profile(self):
         self.marionette.instance.switch_profile(clone_from=self.external_profile)
         self.marionette.start_session()
 
         self.assertIn(os.path.basename(self.external_profile.profile), self.profile_path)
         self.assertTrue(os.path.exists(self.external_profile.profile))
 
     def test_replace_with_current_profile(self):
--- a/toolkit/components/extensions/ExtensionSettingsStore.jsm
+++ b/toolkit/components/extensions/ExtensionSettingsStore.jsm
@@ -83,20 +83,22 @@ function initialize() {
       dataPostProcessor,
     });
     _initializePromise = _store.load();
   }
   return _initializePromise;
 }
 
 // Test-only method to force reloading of the JSON file.
-async function reloadFile(finalize) {
-  if (finalize) {
-    await _store.finalize();
+async function reloadFile(saveChanges) {
+  if (!saveChanges) {
+    // Disarm the saver so that the current changes are dropped.
+    _store._saver.disarm();
   }
+  await _store.finalize();
   _initializePromise = null;
   return initialize();
 }
 
 // Checks that the store is ready and that the requested type exists.
 function ensureType(type) {
   if (!_store.dataReady) {
     throw new Error(
@@ -504,17 +506,18 @@ this.ExtensionSettingsStore = {
   },
 
   /**
    * Test-only method to force reloading of the JSON file.
    *
    * Note that this method simply clears the local variable that stores the
    * file, so the next time the file is accessed it will be reloaded.
    *
-   * @param   {boolean} finalize
-   *          When false, skip finalizing the store (writing current state to file).
+   * @param   {boolean} saveChanges
+   *          When false, discard any changes that have been made since the last
+   *          time the store was saved.
    * @returns {Promise}
    *          A promise that resolves once the settings store has been cleared.
    */
-  _reloadFile(finalize = true) {
-    return reloadFile(finalize);
+  _reloadFile(saveChanges = true) {
+    return reloadFile(saveChanges);
   },
 };