Merge mozilla-inbound to mozilla-central a=merge
authorDaniel Varga <dvarga@mozilla.com>
Sat, 08 Sep 2018 06:53:43 +0300
changeset 491038 da268c77ac76
parent 491000 0cf3f2b65be0 (current diff)
parent 491037 9735b9bf7b46 (diff)
child 491039 f00e66757346
child 491046 a246d79a637d
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone64.0a1
first release with
nightly linux32
da268c77ac76 / 64.0a1 / 20180908100402 / files
nightly linux64
da268c77ac76 / 64.0a1 / 20180908100402 / files
nightly mac
da268c77ac76 / 64.0a1 / 20180908100402 / files
nightly win32
da268c77ac76 / 64.0a1 / 20180908100402 / files
nightly win64
da268c77ac76 / 64.0a1 / 20180908100402 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central a=merge
mobile/android/chrome/content/content.js
security/manager/ssl/RootHashes.inc.orig
security/manager/tools/KnownRootHashes.json.orig
--- a/.eslintignore
+++ b/.eslintignore
@@ -365,15 +365,16 @@ toolkit/modules/tests/xpcshell/test_task
 # External code:
 browser/components/payments/res/vendor/*
 toolkit/components/microformats/test/**
 toolkit/components/microformats/microformat-shiv.js
 toolkit/components/reader/Readability.js
 toolkit/components/reader/JSDOMParser.js
 
 # Uses preprocessing
+toolkit/components/reader/Readerable.jsm
 toolkit/content/widgets/wizard.xml
 toolkit/modules/AppConstants.jsm
 toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
 
 # Third party
 toolkit/modules/third_party/**
 third_party/**
--- a/browser/actors/AboutReaderChild.jsm
+++ b/browser/actors/AboutReaderChild.jsm
@@ -7,16 +7,18 @@
 var EXPORTED_SYMBOLS = ["AboutReaderChild"];
 
 ChromeUtils.import("resource://gre/modules/ActorChild.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AboutReader",
                                "resource://gre/modules/AboutReader.jsm");
 ChromeUtils.defineModuleGetter(this, "ReaderMode",
                                "resource://gre/modules/ReaderMode.jsm");
+ChromeUtils.defineModuleGetter(this, "Readerable",
+                               "resource://gre/modules/Readerable.jsm");
 
 class AboutReaderChild extends ActorChild {
   constructor(mm) {
     super(mm);
 
     this._articlePromise = null;
     this._isLeavingReaderableReaderMode = false;
   }
@@ -97,17 +99,17 @@ class AboutReaderChild extends ActorChil
 
   /**
    * NB: this function will update the state of the reader button asynchronously
    * after the next mozAfterPaint call (assuming reader mode is enabled and
    * this is a suitable document). Calling it on things which won't be
    * painted is not going to work.
    */
   updateReaderButton(forceNonArticle) {
-    if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
+    if (!Readerable.isEnabledForParseOnLoad || this.isAboutReader ||
         !this.content || !(this.content.document instanceof this.content.HTMLDocument) ||
         this.content.document.mozSyntheticDocument) {
       return;
     }
 
     this.scheduleReadabilityCheckPostPaint(forceNonArticle);
   }
 
@@ -136,15 +138,15 @@ class AboutReaderChild extends ActorChil
     // are any painted rects.
     if (!event.clientRects.length) {
       return;
     }
 
     this.cancelPotentialPendingReadabilityCheck();
     // Only send updates when there are articles; there's no point updating with
     // |false| all the time.
-    if (ReaderMode.isProbablyReaderable(this.content.document)) {
+    if (Readerable.isProbablyReaderable(this.content.document)) {
       this.mm.sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
     } else if (forceNonArticle) {
       this.mm.sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
     }
   }
 }
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -36,19 +36,21 @@ endif
 
 PROGRAMS_DEST = $(DIST)/bin
 
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(filter-out WINNT,$(OS_ARCH)))
 
 ifdef COMPILE_ENVIRONMENT
+ifndef MOZ_NO_PIE_COMPAT
 libs::
 	cp -p $(DIST)/bin/$(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
 endif
+endif
 
 GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)
 
 endif
 
 # channel-prefs.js is handled separate from other prefs due to bug 756325
 # DO NOT change the content of channel-prefs.js without taking the appropriate
 # steps. See bug 1431342.
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -24,17 +24,22 @@ with Files("moz.build"):
 with Files("Makefile.in"):
     BUG_COMPONENT = ("Firefox Build System", "General")
 
 with Files("profile/channel-prefs.js"):
     BUG_COMPONENT = ("Firefox", "Installer")
 with Files("profile/firefox.js"):
     BUG_COMPONENT = ("Firefox", "General")
 
-GeckoProgram(CONFIG['MOZ_APP_NAME'])
+if CONFIG['MOZ_NO_PIE_COMPAT']:
+    GeckoProgram(CONFIG['MOZ_APP_NAME'] + '-bin')
+
+    DIRS += ['no-pie']
+else:
+    GeckoProgram(CONFIG['MOZ_APP_NAME'])
 
 SOURCES += [
     'nsBrowserApp.cpp',
 ]
 
 # Neither channel-prefs.js nor firefox.exe want to end up in dist/bin/browser.
 DIST_SUBDIR = ""
 
new file mode 100644
--- /dev/null
+++ b/browser/app/no-pie/NoPie.c
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char* argv[])
+{
+  // Ideally, we'd use mozilla::BinaryPath, but that pulls in stdc++compat,
+  // and further causes trouble linking with LTO.
+  char path[PATH_MAX + 4];
+  ssize_t len = readlink("/proc/self/exe", path, PATH_MAX - 1);
+  if (len < 0) {
+    fprintf(stderr, "Couldn't find the application directory.\n");
+    return 255;
+  }
+  strcpy(path + len, "-bin");
+  execv(path, argv);
+  // execv never returns. If it did, there was an error.
+  fprintf(stderr, "Exec failed with error: %s\n", strerror(errno));
+  return 255;
+}
new file mode 100644
--- /dev/null
+++ b/browser/app/no-pie/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+Program(CONFIG['MOZ_APP_NAME'])
+
+SOURCES += [
+    'NoPie.c',
+]
+
+# For some reason, LTO messes things up. We don't care anyways.
+CFLAGS += [
+    '-fno-lto',
+]
+
+# Use OS_LIBS instead of LDFLAGS to "force" the flag to come after -pie
+# from MOZ_PROGRAM_LDFLAGS.
+OS_LIBS += [
+    '-no-pie'
+]
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -51,17 +51,17 @@ const whitelist = {
     "resource:///actors/AboutReaderChild.jsm",
     "resource:///actors/BrowserTabChild.jsm",
     "resource:///modules/ContentMetaHandler.jsm",
     "resource:///actors/LinkHandlerChild.jsm",
     "resource:///actors/PageStyleChild.jsm",
     "resource://gre/modules/ActorChild.jsm",
     "resource://gre/modules/ActorManagerChild.jsm",
     "resource://gre/modules/E10SUtils.jsm",
-    "resource://gre/modules/ReaderMode.jsm",
+    "resource://gre/modules/Readerable.jsm",
     "resource://gre/modules/WebProgressChild.jsm",
 
     // Pocket
     "chrome://pocket/content/AboutPocket.jsm",
 
     // Telemetry
     "resource://gre/modules/TelemetryController.jsm", // bug 1470339
     "resource://gre/modules/TelemetrySession.jsm", // bug 1470339
--- a/browser/moz.configure
+++ b/browser/moz.configure
@@ -3,9 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 imply_option('MOZ_PLACES', True)
 imply_option('MOZ_SERVICES_HEALTHREPORT', True)
 imply_option('MOZ_SERVICES_SYNC', True)
 
+with only_when(target_is_linux & compile_environment):
+    option(env='MOZ_NO_PIE_COMPAT',
+           help='Enable non-PIE wrapper')
+
+    set_config('MOZ_NO_PIE_COMPAT',
+               depends_if('MOZ_NO_PIE_COMPAT')(lambda _: True))
+
 include('../toolkit/moz.configure')
--- a/build/autoconf/compiler-opts.m4
+++ b/build/autoconf/compiler-opts.m4
@@ -203,39 +203,18 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -
          if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
              DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
          fi
     else
         DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
     fi
 fi
 
-# On OSX, the linker defaults to building PIE programs when targeting OSX 10.7.
-# On other Unix systems, some file managers (Nautilus) can't start PIE programs
-if test "$OS_TARGET" = Android; then
-    # bionic in Android >= 4.1 supports PIE, and we target those versions.
-    MOZ_PIE=1
-else
-    MOZ_PIE=
-fi
-
-MOZ_ARG_ENABLE_BOOL(pie,
-[  --enable-pie           Enable Position Independent Executables],
-    MOZ_PIE=1,
-    MOZ_PIE= )
-
-if test "$GNU_CC$CLANG_CC" -a -n "$MOZ_PIE"; then
-    AC_MSG_CHECKING([for PIE support])
-    _SAVE_LDFLAGS=$LDFLAGS
-    LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS -pie"
-    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
-                  [MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
-                  AC_MSG_RESULT([no])
-                  AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
-    LDFLAGS=$_SAVE_LDFLAGS
+if test "$GNU_CC$CLANG_CC"; then
+    MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"
 fi
 
 AC_SUBST(MOZ_PROGRAM_LDFLAGS)
 
 dnl ASan assumes no symbols are being interposed, and when that happens,
 dnl it's not happy with it. Unconveniently, since Firefox is exporting
 dnl libffi symbols and Gtk+3 pulls system libffi via libwayland-client,
 dnl system libffi interposes libffi symbols that ASan assumes are in
--- a/build/autoconf/sanitize.m4
+++ b/build/autoconf/sanitize.m4
@@ -25,17 +25,17 @@ if test -n "$MOZ_ASAN"; then
         if test "$OS_ARCH" = "WINNT"; then
             CFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CFLAGS"
             CXXFLAGS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/asan_blacklist_win.txt $CXXFLAGS"
         fi
     fi
     CFLAGS="-fsanitize=address $CFLAGS"
     CXXFLAGS="-fsanitize=address $CXXFLAGS"
     if test -z "$CLANG_CL"; then
-        LDFLAGS="-fsanitize=address $LDFLAGS"
+        LDFLAGS="-fsanitize=address -rdynamic $LDFLAGS"
     fi
     AC_DEFINE(MOZ_ASAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_ASAN)
 
 dnl ========================================================
 dnl = Use Memory Sanitizer
@@ -43,17 +43,17 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(memory-sanitizer,
 [  --enable-memory-sanitizer       Enable Memory Sanitizer (default=no)],
     MOZ_MSAN=1,
     MOZ_MSAN= )
 if test -n "$MOZ_MSAN"; then
     CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CFLAGS"
     CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CXXFLAGS"
     if test -z "$CLANG_CL"; then
-        LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $LDFLAGS"
+        LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -rdynamic $LDFLAGS"
     fi
     AC_DEFINE(MOZ_MSAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_MSAN)
 
 dnl ========================================================
 dnl = Use Thread Sanitizer
@@ -61,17 +61,17 @@ dnl ====================================
 MOZ_ARG_ENABLE_BOOL(thread-sanitizer,
 [  --enable-thread-sanitizer       Enable Thread Sanitizer (default=no)],
    MOZ_TSAN=1,
    MOZ_TSAN= )
 if test -n "$MOZ_TSAN"; then
     CFLAGS="-fsanitize=thread $CFLAGS"
     CXXFLAGS="-fsanitize=thread $CXXFLAGS"
     if test -z "$CLANG_CL"; then
-        LDFLAGS="-fsanitize=thread $LDFLAGS"
+        LDFLAGS="-fsanitize=thread -rdynamic $LDFLAGS"
     fi
     AC_DEFINE(MOZ_TSAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_TSAN)
 
 dnl ========================================================
 dnl = Use UndefinedBehavior Sanitizer to find integer overflows
@@ -89,26 +89,26 @@ MOZ_ARG_ENABLE_BOOL(unsigned-overflow-sa
 if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
     MOZ_UBSAN=1
     SANITIZER_BLACKLISTS=""
     if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE"; then
         SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_signed_overflow_blacklist.txt $SANITIZER_BLACKLISTS"
         CFLAGS="-fsanitize=signed-integer-overflow $CFLAGS"
         CXXFLAGS="-fsanitize=signed-integer-overflow $CXXFLAGS"
         if test -z "$CLANG_CL"; then
-            LDFLAGS="-fsanitize=signed-integer-overflow $LDFLAGS"
+            LDFLAGS="-fsanitize=signed-integer-overflow -rdynamic $LDFLAGS"
         fi
         AC_DEFINE(MOZ_SIGNED_OVERFLOW_SANITIZE)
     fi
     if test -n "$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
         SANITIZER_BLACKLISTS="-fsanitize-blacklist=$_topsrcdir/build/sanitizers/ubsan_unsigned_overflow_blacklist.txt $SANITIZER_BLACKLISTS"
         CFLAGS="-fsanitize=unsigned-integer-overflow $CFLAGS"
         CXXFLAGS="-fsanitize=unsigned-integer-overflow $CXXFLAGS"
         if test -z "$CLANG_CL"; then
-            LDFLAGS="-fsanitize=unsigned-integer-overflow $LDFLAGS"
+            LDFLAGS="-fsanitize=unsigned-integer-overflow -rdynamic $LDFLAGS"
         fi
         AC_DEFINE(MOZ_UNSIGNED_OVERFLOW_SANITIZE)
     fi
     CFLAGS="$SANITIZER_BLACKLISTS $CFLAGS"
     CXXFLAGS="$SANITIZER_BLACKLISTS $CXXFLAGS"
     AC_DEFINE(MOZ_UBSAN)
     MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
--- a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
+++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp
@@ -1,10 +1,10 @@
 #include <functional>
-#define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
+#define MOZ_STRONG_REF
 #define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 
 struct RefCountedBase {
   void AddRef();
   void Release();
 };
 
 template <class T>
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -197,17 +197,16 @@ def old_configure_options(*options):
     '--enable-memory-sanitizer',
     '--enable-mobile-optimize',
     '--enable-necko-wifi',
     '--enable-negotiateauth',
     '--enable-nfc',
     '--enable-nspr-build',
     '--enable-official-branding',
     '--enable-parental-controls',
-    '--enable-pie',
     '--enable-posix-nspr-emulation',
     '--enable-pref-extensions',
     '--enable-raw',
     '--enable-readline',
     '--enable-reflow-perf',
     '--enable-sandbox',
     '--enable-signmar',
     '--enable-startup-notification',
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1474,17 +1474,16 @@ def security_hardening_cflags(hardening_
     return namespace(
         flags=flags,
         js_flags=js_flags,
     )
 
 
 add_old_configure_assignment('MOZ_HARDENING_CFLAGS', security_hardening_cflags.flags)
 add_old_configure_assignment('MOZ_HARDENING_CFLAGS_JS', security_hardening_cflags.js_flags)
-imply_option('--enable-pie', depends_if('--enable-hardening')(lambda v: v))
 
 # Code Coverage
 # ==============================================================
 
 js_option('--enable-coverage', env='MOZ_CODE_COVERAGE',
           help='Enable code coverage')
 
 
--- a/build/mozconfig.no-compile
+++ b/build/mozconfig.no-compile
@@ -21,8 +21,9 @@ unset MAKECAB
 unset TOOLCHAIN_PREFIX
 unset BINDGEN_CFLAGS
 unset LLVM_CONFIG
 unset WIN64_LINK
 unset WIN64_LIB
 unset ENABLE_CLANG_PLUGIN
 
 unset MOZ_STDCXX_COMPAT
+unset MOZ_NO_PIE_COMPAT
--- a/build/unix/mozconfig.asan
+++ b/build/unix/mozconfig.asan
@@ -1,14 +1,12 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 
-. "$topsrcdir/build/unix/mozconfig.linux"
+. "$topsrcdir/build/unix/mozconfig.unix"
 
-# Enabling the clang plugin triggers leaks. bug 1487622
-unset ENABLE_CLANG_PLUGIN
 export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 #
 # Enable ASan specific code and build workarounds
 ac_add_options --enable-address-sanitizer
 
 # Mandatory options required for ASan builds (both on Linux and Mac)
 export MOZ_DEBUG_SYMBOLS=1
 ac_add_options --enable-debug-symbols
--- a/build/unix/mozconfig.linux
+++ b/build/unix/mozconfig.linux
@@ -1,25 +1,3 @@
-if [ "x$IS_NIGHTLY" = "xyes" ]; then
-  # Some nightlies (eg: Mulet) don't want these set.
-  MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
-fi
-
-. "$topsrcdir/build/mozconfig.common"
-
-TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
-
-if [ -n "$FORCE_GCC" -o -n "$MOZ_PGO" ]; then
-    CC="$TOOLTOOL_DIR/gcc/bin/gcc"
-    CXX="$TOOLTOOL_DIR/gcc/bin/g++"
+. "$topsrcdir/build/unix/mozconfig.unix"
 
-    # We want to make sure we use binutils and other binaries in the tooltool
-    # package.
-    mk_add_options "export PATH=$TOOLTOOL_DIR/gcc/bin:$PATH"
-else
-    CC="$TOOLTOOL_DIR/clang/bin/clang"
-    CXX="$TOOLTOOL_DIR/clang/bin/clang++"
-    export ENABLE_CLANG_PLUGIN=1
-
-    mk_add_options "export PATH=$TOOLTOOL_DIR/binutils/bin:$PATH"
-fi
-
-. "$topsrcdir/build/unix/mozconfig.stdcxx"
+export MOZ_NO_PIE_COMPAT=1
--- a/build/unix/mozconfig.lto
+++ b/build/unix/mozconfig.lto
@@ -3,11 +3,8 @@ MOZ_AUTOMATION_L10N_CHECK=0
 . "$topsrcdir/build/unix/mozconfig.linux"
 
 # Use Clang as specified in manifest
 export AR="$topsrcdir/clang/bin/llvm-ar"
 export NM="$topsrcdir/clang/bin/llvm-nm"
 export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
 
 ac_add_options --enable-lto
-# Until it's either made the default or we figure a way to remove the
-# copy locations that LTO induces in non-PIE executables.
-ac_add_options --enable-pie
--- a/build/unix/mozconfig.tsan
+++ b/build/unix/mozconfig.tsan
@@ -1,23 +1,22 @@
 MOZ_AUTOMATION_L10N_CHECK=0
 
-. "$topsrcdir/build/unix/mozconfig.linux"
+. "$topsrcdir/build/unix/mozconfig.unix"
 
 export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 
 # Enable TSan specific code and build workarounds
 ac_add_options --enable-thread-sanitizer
 
 # The ThreadSanitizer is not compatible with sandboxing
 # (see bug 1182565)
 ac_add_options --disable-sandbox
 
 # These are required by TSan
 ac_add_options --disable-jemalloc
 ac_add_options --disable-crashreporter
 ac_add_options --disable-elf-hack
-ac_add_options --enable-pie
 
 # Keep symbols to symbolize TSan traces
 ac_add_options --disable-install-strip
 # -gline-tables-only results in significantly smaller binaries.
 ac_add_options --enable-debug-symbols="-gline-tables-only"
copy from build/unix/mozconfig.linux
copy to build/unix/mozconfig.unix
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1498,16 +1498,17 @@ WebRenderCommandBuilder::PopOverrideForA
   mClipManager.PopOverrideForASR(aASR);
 }
 
 Maybe<wr::ImageKey>
 WebRenderCommandBuilder::CreateImageKey(nsDisplayItem* aItem,
                                         ImageContainer* aContainer,
                                         mozilla::wr::DisplayListBuilder& aBuilder,
                                         mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                        mozilla::wr::ImageRendering aRendering,
                                         const StackingContextHelper& aSc,
                                         gfx::IntSize& aSize,
                                         const Maybe<LayoutDeviceRect>& aAsyncImageBounds)
 {
   RefPtr<WebRenderImageData> imageData = CreateOrRecycleWebRenderUserData<WebRenderImageData>(aItem);
   MOZ_ASSERT(imageData);
 
   if (aContainer->IsAsync()) {
@@ -1525,17 +1526,17 @@ WebRenderCommandBuilder::CreateImageKey(
     // layers-free image handling and that breaks frame consistency.
     imageData->CreateAsyncImageWebRenderCommands(aBuilder,
                                                  aContainer,
                                                  aSc,
                                                  rect,
                                                  scBounds,
                                                  transform,
                                                  scaleToSize,
-                                                 wr::ImageRendering::Auto,
+                                                 aRendering,
                                                  wr::MixBlendMode::Normal,
                                                  !aItem->BackfaceIsHidden());
     return Nothing();
   }
 
   AutoLockImage autoLock(aContainer);
   if (!autoLock.HasImage()) {
     return Nothing();
@@ -1549,32 +1550,32 @@ WebRenderCommandBuilder::CreateImageKey(
 bool
 WebRenderCommandBuilder::PushImage(nsDisplayItem* aItem,
                                    ImageContainer* aContainer,
                                    mozilla::wr::DisplayListBuilder& aBuilder,
                                    mozilla::wr::IpcResourceUpdateQueue& aResources,
                                    const StackingContextHelper& aSc,
                                    const LayoutDeviceRect& aRect)
 {
+  mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
+    nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer,
-                                           aBuilder, aResources,
-                                           aSc, size, Some(aRect));
+  Maybe<wr::ImageKey> key = CreateImageKey(
+    aItem, aContainer, aBuilder, aResources, rendering, aSc, size, Some(aRect));
   if (aContainer->IsAsync()) {
     // Async ImageContainer does not create ImageKey, instead it uses Pipeline.
     MOZ_ASSERT(key.isNothing());
     return true;
   }
   if (!key) {
     return false;
   }
 
   auto r = wr::ToRoundedLayoutRect(aRect);
-  gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
-  aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::ToImageRendering(sampleFilter), key.value());
+  aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), rendering, key.value());
 
   return true;
 }
 
 bool
 BuildLayer(nsDisplayItem* aItem,
            BlobItemData* aData,
            nsDisplayListBuilder* aDisplayListBuilder,
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -60,16 +60,17 @@ public:
   void PushOverrideForASR(const ActiveScrolledRoot* aASR,
                           const Maybe<wr::WrClipId>& aClipId);
   void PopOverrideForASR(const ActiveScrolledRoot* aASR);
 
   Maybe<wr::ImageKey> CreateImageKey(nsDisplayItem* aItem,
                                      ImageContainer* aContainer,
                                      mozilla::wr::DisplayListBuilder& aBuilder,
                                      mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                     mozilla::wr::ImageRendering aRendering,
                                      const StackingContextHelper& aSc,
                                      gfx::IntSize& aSize,
                                      const Maybe<LayoutDeviceRect>& aAsyncImageBounds);
 
   WebRenderUserDataRefTable* GetWebRenderUserDataTable() { return &mWebRenderUserDatas; }
 
   bool PushImage(nsDisplayItem* aItem,
                  ImageContainer* aContainer,
--- a/image/test/reftest/downscaling/reftest.list
+++ b/image/test/reftest/downscaling/reftest.list
@@ -21,22 +21,22 @@
 # Also note that Mac OS X has its own system-level downscaling algorithm, so
 # tests here may need Mac-specific "fuzzy-if(cocoaWidget,...)" annotations.
 # Similarly, modern versions of Windows have slightly different downscaling
 # behavior than other platforms, and may require "fuzzy-if(winWidget,...)".
 
 
 # RUN TESTS NOT AFFECTED BY DOWNSCALE-DURING-DECODE:
 # ==================================================
-fuzzy-if(skiaContent,0-14,0-416) fuzzy-if(webrender,14-14,397-473) == downscale-svg-1a.html downscale-svg-1-ref.html?80
-fuzzy(0-80,0-468) fuzzy-if(webrender,65-65,579-580) == downscale-svg-1b.html downscale-svg-1-ref.html?72
-fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-62) fuzzy-if(skiaContent,0-8,0-292) fuzzy-if(webrender,14-14,316-316) == downscale-svg-1c.html downscale-svg-1-ref.html?64
-fuzzy(0-17,0-208) fuzzy-if(webrender,83-84,274-325) == downscale-svg-1d.html downscale-svg-1-ref.html?53
-fuzzy(0-80,0-216) fuzzy-if(skiaContent,0-110,0-181) fuzzy-if(webrender,84-84,216-216) == downscale-svg-1e.html downscale-svg-1-ref.html?40
-fuzzy(0-51,0-90) fuzzy-if(skiaContent,0-142,0-77) fuzzy-if(webrender,62-62,98-98) == downscale-svg-1f.html downscale-svg-1-ref.html?24
+fuzzy-if(skiaContent,0-14,0-416) fuzzy-if(webrender,1-1,2-2) == downscale-svg-1a.html downscale-svg-1-ref.html?80
+fuzzy(0-80,0-468) fuzzy-if(webrender,65-65,468-468) == downscale-svg-1b.html downscale-svg-1-ref.html?72
+fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-62) fuzzy-if(skiaContent,0-8,0-292) fuzzy-if(webrender,1-1,2-2) == downscale-svg-1c.html downscale-svg-1-ref.html?64
+fuzzy(0-17,0-208) fuzzy-if(webrender,7-7,208-208) == downscale-svg-1d.html downscale-svg-1-ref.html?53
+fuzzy(0-80,0-216) fuzzy-if(skiaContent,0-110,0-181) fuzzy-if(webrender,54-54,178-178) == downscale-svg-1e.html downscale-svg-1-ref.html?40
+fuzzy(0-51,0-90) fuzzy-if(skiaContent,0-142,0-77) fuzzy-if(webrender,64-64,31-31) == downscale-svg-1f.html downscale-svg-1-ref.html?24
 
 # RUN TESTS WITH DOWNSCALE-DURING-DECODE DISABLED:
 # ================================================
 default-preferences pref(image.downscale-during-decode.enabled,false)
 
 fuzzy-if(winWidget,0-16,0-20) fuzzy-if(cocoaWidget,0-106,0-31) == downscale-1.html downscale-1-ref.html
 
 fuzzy(0-20,0-999) != downscale-2a.html?203,52,left about:blank
--- a/ipc/glue/CrashReporterClient.cpp
+++ b/ipc/glue/CrashReporterClient.cpp
@@ -38,20 +38,24 @@ CrashReporterClient::AppendAppNotes(cons
 {
   StaticMutexAutoLock lock(sLock);
   mMetadata->AppendAppNotes(aData);
 }
 
 /* static */ void
 CrashReporterClient::InitSingletonWithShmem(const Shmem& aShmem)
 {
-  StaticMutexAutoLock lock(sLock);
+  {
+    StaticMutexAutoLock lock(sLock);
 
-  MOZ_ASSERT(!sClientSingleton);
-  sClientSingleton = new CrashReporterClient(aShmem);
+    MOZ_ASSERT(!sClientSingleton);
+    sClientSingleton = new CrashReporterClient(aShmem);
+  }
+
+  CrashReporter::NotifyCrashReporterClientCreated();
 }
 
 /* static */ void
 CrashReporterClient::DestroySingleton()
 {
   StaticMutexAutoLock lock(sLock);
   sClientSingleton = nullptr;
 }
--- a/js/public/CompileOptions.h
+++ b/js/public/CompileOptions.h
@@ -244,17 +244,17 @@ class JS_PUBLIC_API(OwningCompileOptions
     JSObject* element() const override { return elementRoot; }
     JSString* elementAttributeName() const override { return elementAttributeNameRoot; }
     JSScript* introductionScript() const override { return introductionScriptRoot; }
 
     /** Set this to a copy of |rhs|.  Return false on OOM. */
     bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
 
     /* These setters make copies of their string arguments and are fallible. */
-    bool setFile(JSContext* cx, const char* f);
+    MOZ_MUST_USE bool setFile(JSContext* cx, const char* f);
     MOZ_MUST_USE bool setFileAndLine(JSContext* cx, const char* f, unsigned l);
     MOZ_MUST_USE bool setSourceMapURL(JSContext* cx, const char16_t* s);
     MOZ_MUST_USE bool setIntroducerFilename(JSContext* cx, const char* s);
 
     /* These setters are infallible, and can be chained. */
 
     OwningCompileOptions& setLine(unsigned l) {
         lineno = l;
--- a/js/src/ds/LifoAlloc.cpp
+++ b/js/src/ds/LifoAlloc.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ds/LifoAlloc.h"
 
+#include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "ds/MemoryProtectionExceptionHandler.h"
 
 #ifdef LIFO_CHUNK_PROTECT
 # include "gc/Memory.h"
 #endif
 
@@ -137,33 +138,27 @@ LifoAlloc::freeAll()
 
 LifoAlloc::UniqueBumpChunk
 LifoAlloc::newChunkWithCapacity(size_t n)
 {
     MOZ_ASSERT(fallibleScope_, "[OOM] Cannot allocate a new chunk in an infallible scope.");
 
     // Compute the size which should be requested in order to be able to fit |n|
     // bytes in a newly allocated chunk, or default to |defaultChunkSize_|.
-    uint8_t* u8begin = nullptr;
-    uint8_t* u8end = u8begin + detail::BumpChunkReservedSpace;
-    u8end = detail::BumpChunk::nextAllocEnd(detail::BumpChunk::nextAllocBase(u8end), n);
-    size_t allocSizeWithCanaries = u8end - u8begin;
 
-    // Guard for overflow.
-    if (allocSizeWithCanaries < n ||
-        (allocSizeWithCanaries & (size_t(1) << (BitSize<size_t>::value - 1))))
+    size_t minSize;
+    if (MOZ_UNLIKELY(!detail::BumpChunk::allocSizeWithRedZone(n, &minSize) ||
+                     (minSize & (size_t(1) << (BitSize<size_t>::value - 1)))))
     {
         return nullptr;
     }
 
-    size_t chunkSize;
-    if (allocSizeWithCanaries > defaultChunkSize_)
-        chunkSize = RoundUpPow2(allocSizeWithCanaries);
-    else
-        chunkSize = defaultChunkSize_;
+    const size_t chunkSize = minSize > defaultChunkSize_
+                             ?  RoundUpPow2(minSize)
+                             : defaultChunkSize_;
 
     // Create a new BumpChunk, and allocate space for it.
     UniqueBumpChunk result = detail::BumpChunk::newWithCapacity(chunkSize);
     if (!result)
         return nullptr;
     MOZ_ASSERT(result->computedSizeOfIncludingThis() == chunkSize);
     return result;
 }
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -12,16 +12,17 @@
 #include "mozilla/MemoryChecking.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 
 #include <new>
+#include <stddef.h> // size_t
 
 // This data structure supports stacky LIFO allocation (mark/release and
 // LifoAllocScope). It does not maintain one contiguous segment; instead, it
 // maintains a bunch of linked memory segments. In order to prevent malloc/free
 // thrashing, unused segments are deallocated when garbage collection occurs.
 
 #include "jsutil.h"
 
@@ -191,17 +192,18 @@ class SingleLinkedList
         return result;
     }
 };
 
 static const size_t LIFO_ALLOC_ALIGN = 8;
 
 MOZ_ALWAYS_INLINE
 uint8_t*
-AlignPtr(uint8_t* orig) {
+AlignPtr(uint8_t* orig)
+{
     static_assert(mozilla::IsPowerOfTwo(LIFO_ALLOC_ALIGN),
                   "LIFO_ALLOC_ALIGN must be a power of two");
 
     uint8_t* result = (uint8_t*) AlignBytes(uintptr_t(orig), LIFO_ALLOC_ALIGN);
     MOZ_ASSERT(uintptr_t(result) % LIFO_ALLOC_ALIGN == 0);
     return result;
 }
 
@@ -410,16 +412,21 @@ class BumpChunk : public SingleLinkedLis
 
     // Release the memory allocated in this chunk since the corresponding mark
     // got created. This function does not call any of the destructors.
     void release(Mark m) {
         MOZ_RELEASE_ASSERT(contains(m));
         setBump(m.bump_);
     }
 
+    // Given an amount, compute the total size of a chunk for it: reserved
+    // space before |begin()|, space for |amount| bytes, and red-zone space
+    // after those bytes that will ultimately end at |capacity_|.
+    static inline MOZ_MUST_USE bool allocSizeWithRedZone(size_t amount, size_t* size);
+
     // Given a bump chunk pointer, find the next base/end pointers. This is
     // useful for having consistent allocations, and iterating over known size
     // allocations.
     static uint8_t* nextAllocBase(uint8_t* e) {
         return detail::AlignPtr(e);
     }
     static uint8_t* nextAllocEnd(uint8_t* b, size_t n) {
         return b + n + RedZoneSize;
@@ -468,16 +475,33 @@ class BumpChunk : public SingleLinkedLis
 #endif
 };
 
 // Space reserved for the BumpChunk internal data, and the alignment of the
 // first allocation content. This can be used to ensure there is enough space
 // for the next allocation (see LifoAlloc::newChunkWithCapacity).
 static constexpr size_t BumpChunkReservedSpace = AlignBytes(sizeof(BumpChunk), LIFO_ALLOC_ALIGN);
 
+/* static */ inline MOZ_MUST_USE bool
+BumpChunk::allocSizeWithRedZone(size_t amount, size_t* size)
+{
+    constexpr size_t SpaceBefore = BumpChunkReservedSpace;
+    static_assert((SpaceBefore % LIFO_ALLOC_ALIGN) == 0,
+                   "reserved space presumed already aligned");
+
+    constexpr size_t SpaceAfter = RedZoneSize; // may be zero
+
+    constexpr size_t SpaceBeforeAndAfter = SpaceBefore + SpaceAfter;
+    static_assert(SpaceBeforeAndAfter >= SpaceBefore,
+                  "intermediate addition must not overflow");
+
+    *size = SpaceBeforeAndAfter + amount;
+    return MOZ_LIKELY(*size >= SpaceBeforeAndAfter);
+}
+
 inline const uint8_t*
 BumpChunk::begin() const
 {
     return base() + BumpChunkReservedSpace;
 }
 
 inline uint8_t*
 BumpChunk::begin()
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -10420,16 +10420,17 @@ CodeGenerator::link(JSContext* cx, Compi
                 const uint8_t* optsAttemptsTableAddr = trackedOptimizationsMap_ +
                                                        trackedOptimizationsAttemptsTableOffset_;
                 const IonTrackedOptimizationsAttemptsTable* optsAttemptsTable =
                     (const IonTrackedOptimizationsAttemptsTable*) optsAttemptsTableAddr;
                 entry.initTrackedOptimizations(optsRegionTable, optsTypesTable, optsAttemptsTable,
                                                allTypes);
             } else {
                 cx->recoverFromOutOfMemory();
+                js_delete(allTypes);
             }
         }
 
         // Add entry to the global table.
         JitcodeGlobalTable* globalTable = cx->runtime()->jitRuntime()->getJitcodeGlobalTable();
         if (!globalTable->addEntry(entry)) {
             // Memory may have been allocated for the entry.
             entry.destroy();
--- a/js/src/jit/arm64/AtomicOperations-arm64-msvc.h
+++ b/js/src/jit/arm64/AtomicOperations-arm64-msvc.h
@@ -56,17 +56,19 @@ js::jit::AtomicOperations::isLockfree8()
 
     return true;
 }
 
 inline void
 js::jit::AtomicOperations::fenceSeqCst()
 {
     _ReadWriteBarrier();
-    MemoryBarrier();
+    // MemoryBarrier is defined in winnt.h, which we don't want to include here.
+    // This expression is the expansion of MemoryBarrier.
+    __dmb(_ARM64_BARRIER_SY);
 }
 
 template<typename T>
 inline T
 js::jit::AtomicOperations::loadSeqCst(T* addr)
 {
     MOZ_ASSERT(tier1Constraints(addr));
     _ReadWriteBarrier();
--- a/js/src/vm/BytecodeUtil.h
+++ b/js/src/vm/BytecodeUtil.h
@@ -59,38 +59,27 @@ enum {
     JOF_SCOPE           = 20,       /* unsigned 32-bit scope index */
     JOF_ENVCOORD        = 21,       /* embedded ScopeCoordinate immediate */
     JOF_TYPEMASK        = 0x001f,   /* mask for above immediate types */
 
     JOF_NAME            = 1 << 5,   /* name operation */
     JOF_PROP            = 2 << 5,   /* obj.prop operation */
     JOF_ELEM            = 3 << 5,   /* obj[index] operation */
     JOF_MODEMASK        = 3 << 5,   /* mask for above addressing modes */
+
     JOF_PROPSET         = 1 << 7,   /* property/element/name set operation */
     JOF_PROPINIT        = 1 << 8,   /* property/element/name init operation */
-    /* 1 << 9 is unused */
-    /* 1 << 10 is unused */
-    /* 1 << 11 is unused */
-    /* 1 << 12 is unused */
-    /* 1 << 13 is unused */
-    JOF_DETECTING       = 1 << 14,  /* object detection for warning-quelling */
-    /* 1 << 15 is unused */
-    JOF_LEFTASSOC       = 1 << 16,  /* left-associative operator */
-    /* 1 << 17 is unused */
-    /* 1 << 18 is unused */
-    JOF_CHECKSLOPPY     = 1 << 19,  /* Op can only be generated in sloppy mode */
-    JOF_CHECKSTRICT     = 1 << 20,  /* Op can only be generated in strict mode */
-    JOF_INVOKE          = 1 << 21,  /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
+    JOF_DETECTING       = 1 << 9,   /* object detection for warning-quelling */
+    JOF_CHECKSLOPPY     = 1 << 10,  /* Op can only be generated in sloppy mode */
+    JOF_CHECKSTRICT     = 1 << 11,  /* Op can only be generated in strict mode */
+    JOF_INVOKE          = 1 << 12,  /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
                                        JSOP_NEW, JSOP_EVAL, JSOP_CALLITER */
-    /* 1 << 22 is unused */
-    /* 1 << 23 is unused */
-    /* 1 << 24 is unused */
-    JOF_GNAME           = 1 << 25,  /* predicted global name */
-    JOF_TYPESET         = 1 << 26,  /* has an entry in a script's type sets */
-    JOF_ARITH           = 1 << 27   /* unary or binary arithmetic opcode */
+    JOF_GNAME           = 1 << 13,  /* predicted global name */
+    JOF_TYPESET         = 1 << 14,  /* has an entry in a script's type sets */
+    JOF_ARITH           = 1 << 15   /* unary or binary arithmetic opcode */
 };
 
 /* Shorthand for type from format. */
 
 static inline uint32_t
 JOF_TYPE(uint32_t fmt)
 {
     return fmt & JOF_TYPEMASK;
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -239,73 +239,73 @@ 1234567890123456789012345678901234567890
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of the operation applied to the two operands, converting
      * both to 32-bit signed integers if necessary.
      *   Category: Operators
      *   Type: Bitwise Logical Operators
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
-    macro(JSOP_BITOR,     15, "bitor",      "|",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_BITXOR,    16, "bitxor",     "^",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_BITAND,    17, "bitand",     "&",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_BITOR,     15, "bitor",      "|",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_BITXOR,    16, "bitxor",     "^",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_BITAND,    17, "bitand",     "&",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the top two values from the stack and pushes the result of
      * comparing them.
      *   Category: Operators
      *   Type: Comparison Operators
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
-    macro(JSOP_EQ,        18, "eq",         "==",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
-    macro(JSOP_NE,        19, "ne",         "!=",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
-    macro(JSOP_LT,        20, "lt",         "<",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_LE,        21, "le",         "<=",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_GT,        22, "gt",         ">",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_GE,        23, "ge",         ">=",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_EQ,        18, "eq",         "==",         1,  2,  1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
+    macro(JSOP_NE,        19, "ne",         "!=",         1,  2,  1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
+    macro(JSOP_LT,        20, "lt",         "<",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_LE,        21, "le",         "<=",         1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_GT,        22, "gt",         ">",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_GE,        23, "ge",         ">=",         1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of the operation applied to the operands.
      *   Category: Operators
      *   Type: Bitwise Shift Operators
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
-    macro(JSOP_LSH,       24, "lsh",        "<<",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_RSH,       25, "rsh",        ">>",         1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_LSH,       24, "lsh",        "<<",         1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_RSH,       25, "rsh",        ">>",         1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * 'lval >>> rval'.
      *   Category: Operators
      *   Type: Bitwise Shift Operators
      *   Operands:
      *   Stack: lval, rval => (lval >>> rval)
      */ \
-    macro(JSOP_URSH,      26, "ursh",       ">>>",        1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_URSH,      26, "ursh",       ">>>",        1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of 'lval + rval'.
      *   Category: Operators
      *   Type: Arithmetic Operators
      *   Operands:
      *   Stack: lval, rval => (lval + rval)
      */ \
-    macro(JSOP_ADD,       27, "add",        "+",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_ADD,       27, "add",        "+",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the top two values 'lval' and 'rval' from the stack, then pushes
      * the result of applying the arithmetic operation to them.
      *   Category: Operators
      *   Type: Arithmetic Operators
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
-    macro(JSOP_SUB,       28, "sub",        "-",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_MUL,       29, "mul",        "*",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_DIV,       30, "div",        "/",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_MOD,       31, "mod",        "%",          1,  2,  1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_SUB,       28, "sub",        "-",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_MUL,       29, "mul",        "*",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_DIV,       30, "div",        "/",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
+    macro(JSOP_MOD,       31, "mod",        "%",          1,  2,  1, JOF_BYTE|JOF_ARITH) \
     /*
      * Pops the value 'val' from the stack, then pushes '!val'.
      *   Category: Operators
      *   Type: Logical Operators
      *   Operands:
      *   Stack: val => (!val)
      */ \
     macro(JSOP_NOT,       32, "not",        "!",          1,  1,  1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
@@ -530,17 +530,17 @@ 1234567890123456789012345678901234567890
     /*
      * Pops the top two values on the stack as 'propval' and 'obj', pushes
      * 'propval' property of 'obj' onto the stack.
      *   Category: Literals
      *   Type: Object
      *   Operands:
      *   Stack: obj, propval => obj[propval]
      */ \
-    macro(JSOP_GETELEM,   55, "getelem",    NULL,         1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+    macro(JSOP_GETELEM,   55, "getelem",    NULL,         1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET) \
     /*
      * Pops the top three values on the stack as 'val', 'propval' and 'obj',
      * sets 'propval' property of 'obj' as 'val', pushes 'val' onto the
      * stack.
      *   Category: Literals
      *   Type: Object
      *   Operands:
      *   Stack: obj, propval, val => val
@@ -635,26 +635,26 @@ 1234567890123456789012345678901234567890
     /*
      * Converts the top of stack value into a boolean, if the result is 'true',
      * jumps to a 32-bit offset from the current bytecode.
      *   Category: Statements
      *   Type: Jumps
      *   Operands: int32_t offset
      *   Stack: cond => cond
      */ \
-    macro(JSOP_OR,        68, "or",         NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
+    macro(JSOP_OR,        68, "or",         NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING) \
     /*
      * Converts the top of stack value into a boolean, if the result is 'false',
      * jumps to a 32-bit offset from the current bytecode.
      *   Category: Statements
      *   Type: Jumps
      *   Operands: int32_t offset
      *   Stack: cond => cond
      */ \
-    macro(JSOP_AND,       69, "and",        NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
+    macro(JSOP_AND,       69, "and",        NULL,         5,  1,  1, JOF_JUMP|JOF_DETECTING) \
     \
     /*
      * Pops the top of stack value as 'i', if 'low <= i <= high',
      * jumps to a 32-bit offset: 'offset[i - low]' from the current bytecode, unless the offset is zero (missing case)
      * jumps to a 32-bit offset: 'len' from the current bytecode otherwise
      *
      * This opcode has variable length.
      *   Category: Statements
@@ -680,18 +680,18 @@ 1234567890123456789012345678901234567890
     /*
      * Pops the top two values from the stack, then pushes the result of
      * applying the operator to the two values.
      *   Category: Operators
      *   Type: Comparison Operators
      *   Operands:
      *   Stack: lval, rval => (lval OP rval)
      */ \
-    macro(JSOP_STRICTEQ,  72, "stricteq",   "===",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
-    macro(JSOP_STRICTNE,  73, "strictne",   "!==",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
+    macro(JSOP_STRICTEQ,  72, "stricteq",   "===",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_ARITH) \
+    macro(JSOP_STRICTNE,  73, "strictne",   "!==",        1,  2,  1, JOF_BYTE|JOF_DETECTING|JOF_ARITH) \
     \
     /*
      * Sometimes we know when emitting that an operation will always throw.
      *
      * Throws the indicated JSMSG.
      *
      *   Category: Statements
      *   Type: Exception Handling
@@ -1117,27 +1117,27 @@ 1234567890123456789012345678901234567890
      * 'id in obj'.  This will throw a 'TypeError' if 'obj' is not an object.
      *
      * Note that 'obj' is the top value.
      *   Category: Operators
      *   Type: Special Operators
      *   Operands:
      *   Stack: id, obj => (id in obj)
      */ \
-    macro(JSOP_IN,        113,js_in_str,    js_in_str,    1,  2,  1, JOF_BYTE|JOF_LEFTASSOC) \
+    macro(JSOP_IN,        113,js_in_str,    js_in_str,    1,  2,  1, JOF_BYTE) \
     /*
      * Pops the top two values 'obj' and 'ctor' from the stack, then pushes
      * 'obj instanceof ctor'.  This will throw a 'TypeError' if 'obj' is not an
      * object.
      *   Category: Operators
      *   Type: Special Operators
      *   Operands:
      *   Stack: obj, ctor => (obj instanceof ctor)
      */ \
-    macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE|JOF_LEFTASSOC) \
+    macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE) \
     \
     /*
      * Invokes debugger.
      *   Category: Statements
      *   Type: Debugger
      *   Operands:
      *   Stack: =>
      */ \
@@ -1275,17 +1275,17 @@ 1234567890123456789012345678901234567890
     /*
      * LIKE JSOP_GETELEM but takes receiver on stack, and the propval is
      * evaluated before the obj.
      *   Category: Literals
      *   Type: Object
      *   Operands:
      *   Stack: receiver, propval, obj => obj[propval]
      */ \
-    macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+    macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1,  3,  1, JOF_BYTE|JOF_ELEM|JOF_TYPESET) \
     macro(JSOP_UNUSED126, 126, "unused126", NULL, 5,  0,  1, JOF_UINT32) \
     \
     /*
      * Defines the given function on the current scope.
      *
      * This is used for global scripts and also in some cases for function
      * scripts where use of dynamic scoping inhibits optimization.
      *   Category: Variables and Scopes
@@ -1976,17 +1976,17 @@ 1234567890123456789012345678901234567890
      * 'propval' property of 'obj' onto the stack.
      *
      * Like JSOP_GETELEM but for call context.
      *   Category: Literals
      *   Type: Object
      *   Operands:
      *   Stack: obj, propval => obj[propval]
      */ \
-    macro(JSOP_CALLELEM,      193, "callelem",   NULL,    1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
+    macro(JSOP_CALLELEM,      193, "callelem",   NULL,    1,  2,  1, JOF_BYTE |JOF_ELEM|JOF_TYPESET) \
     \
     /*
      * '__proto__: v' inside an object initializer.
      *
      * Pops the top two values on the stack as 'newProto' and 'obj', sets
      * prototype of 'obj' as 'newProto', pushes 'true' onto the stack if
      * succeeded, 'false' if not.
      *   Category: Literals
--- a/js/xpconnect/loader/ChromeScriptLoader.cpp
+++ b/js/xpconnect/loader/ChromeScriptLoader.cpp
@@ -12,16 +12,17 @@
 #include "nsThreadUtils.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "js/CompilationAndEvaluation.h"
 #include "js/SourceBufferHolder.h"
 #include "js/Utility.h"
 
+#include "mozilla/Attributes.h"
 #include "mozilla/dom/ChromeUtils.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ScriptLoader.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/SystemGroup.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsCycleCollectionParticipant.h"
 
@@ -38,33 +39,29 @@ public:
     // class to implement cycle collection.
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
     NS_DECL_NSIRUNNABLE
 
     AsyncScriptCompiler(JSContext* aCx,
                         nsIGlobalObject* aGlobal,
                         const nsACString& aURL,
-                        const CompileScriptOptionsDictionary& aOptions,
                         Promise* aPromise)
       : mozilla::Runnable("AsyncScriptCompiler")
       , mOptions(aCx)
       , mURL(aURL)
       , mGlobalObject(aGlobal)
       , mPromise(aPromise)
-      , mCharset(aOptions.mCharset)
       , mToken(nullptr)
       , mScriptLength(0)
-    {
-        mOptions.setNoScriptRval(!aOptions.mHasReturnValue)
-                .setCanLazilyParse(aOptions.mLazilyParse)
-                .setFile(aCx, mURL.get());
-    }
+    {}
 
-    nsresult Start(nsIPrincipal* aPrincipal);
+    MOZ_MUST_USE nsresult Start(JSContext* aCx,
+                                const CompileScriptOptionsDictionary& aOptions,
+                                nsIPrincipal* aPrincipal);
 
     inline void
     SetToken(JS::OffThreadToken* aToken)
     {
         mToken = aToken;
     }
 
 protected:
@@ -92,18 +89,29 @@ private:
     size_t                      mScriptLength;
 };
 
 NS_IMPL_QUERY_INTERFACE_INHERITED(AsyncScriptCompiler, Runnable, nsIIncrementalStreamLoaderObserver)
 NS_IMPL_ADDREF_INHERITED(AsyncScriptCompiler, Runnable)
 NS_IMPL_RELEASE_INHERITED(AsyncScriptCompiler, Runnable)
 
 nsresult
-AsyncScriptCompiler::Start(nsIPrincipal* aPrincipal)
+AsyncScriptCompiler::Start(JSContext* aCx,
+                           const CompileScriptOptionsDictionary& aOptions,
+                           nsIPrincipal* aPrincipal)
 {
+    mCharset = aOptions.mCharset;
+
+    mOptions.setNoScriptRval(!aOptions.mHasReturnValue)
+            .setCanLazilyParse(aOptions.mLazilyParse);
+
+    if (NS_WARN_IF(!mOptions.setFile(aCx, mURL.get()))) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
     nsCOMPtr<nsIURI> uri;
     nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIChannel> channel;
     rv = NS_NewChannel(getter_AddRefs(channel),
                        uri, aPrincipal,
                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
@@ -274,19 +282,19 @@ ChromeUtils::CompileScript(GlobalObject&
     MOZ_ASSERT(global);
 
     RefPtr<Promise> promise = Promise::Create(global, aRv);
     if (aRv.Failed()) {
         return nullptr;
     }
 
     NS_ConvertUTF16toUTF8 url(aURL);
-    RefPtr<AsyncScriptCompiler> compiler = new AsyncScriptCompiler(aGlobal.Context(), global, url, aOptions, promise);
+    RefPtr<AsyncScriptCompiler> compiler = new AsyncScriptCompiler(aGlobal.Context(), global, url, promise);
 
-    nsresult rv = compiler->Start(aGlobal.GetSubjectPrincipal());
+    nsresult rv = compiler->Start(aGlobal.Context(), aOptions, aGlobal.GetSubjectPrincipal());
     if (NS_FAILED(rv)) {
         promise->MaybeReject(rv);
     }
 
     return promise.forget();
 }
 
 PrecompiledScript::PrecompiledScript(nsISupports* aParent, Handle<JSScript*> aScript,
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -581,16 +581,39 @@ nsXPCWrappedJSClass::DelegatedQueryInter
             return NS_NOINTERFACE;
         }
 
         NS_ADDREF(root);
         *aInstancePtr = (void*) static_cast<nsISupportsWeakReference*>(root);
         return NS_OK;
     }
 
+    // If we're asked to QI to nsISimpleEnumerator and the wrapped object does not have a
+    // QueryInterface method, assume it is a JS iterator, and wrap it into an equivalent
+    // nsISimpleEnumerator.
+    if (aIID.Equals(NS_GET_IID(nsISimpleEnumerator))) {
+        bool found;
+        XPCJSContext* xpccx = ccx.GetContext();
+        if (JS_HasPropertyById(aes.cx(), obj,
+                               xpccx->GetStringID(xpccx->IDX_QUERY_INTERFACE),
+                               &found) && !found) {
+            nsresult rv;
+            nsCOMPtr<nsIJSEnumerator> jsEnum;
+            if (!XPCConvert::JSObject2NativeInterface(aes.cx(),
+                                                      getter_AddRefs(jsEnum), obj,
+                                                      &NS_GET_IID(nsIJSEnumerator),
+                                                      nullptr, &rv)) {
+                return rv;
+            }
+            nsCOMPtr<nsISimpleEnumerator> res = new XPCWrappedJSIterator(jsEnum);
+            res.forget(aInstancePtr);
+            return NS_OK;
+        }
+    }
+
     // Checks for any existing wrapper explicitly constructed for this iid.
     // This includes the current 'self' wrapper. This also deals with the
     // nsISupports case (for which it returns mRoot).
     // Also check if asking for an interface from which one of our wrappers inherits.
     if (nsXPCWrappedJS* sibling = self->FindOrFindInherited(aIID)) {
         NS_ADDREF(sibling);
         *aInstancePtr = sibling->GetXPTCStub();
         return NS_OK;
@@ -606,39 +629,16 @@ nsXPCWrappedJSClass::DelegatedQueryInter
 
         // Do the same thing we do for the "check for any existing wrapper" case above.
         if (NS_SUCCEEDED(rv) && wrapper) {
             *aInstancePtr = wrapper.forget().take()->GetXPTCStub();
         }
         return rv;
     }
 
-    // If we're asked to QI to nsISimpleEnumerator and the wrapped object does not have a
-    // QueryInterface method, assume it is a JS iterator, and wrap it into an equivalent
-    // nsISimpleEnumerator.
-    if (aIID.Equals(NS_GET_IID(nsISimpleEnumerator))) {
-        bool found;
-        XPCJSContext* xpccx = ccx.GetContext();
-        if (JS_HasPropertyById(aes.cx(), obj,
-                               xpccx->GetStringID(xpccx->IDX_QUERY_INTERFACE),
-                               &found) && !found) {
-            nsresult rv;
-            nsCOMPtr<nsIJSEnumerator> jsEnum;
-            if (!XPCConvert::JSObject2NativeInterface(aes.cx(),
-                                                      getter_AddRefs(jsEnum), obj,
-                                                      &NS_GET_IID(nsIJSEnumerator),
-                                                      nullptr, &rv)) {
-                return rv;
-            }
-            nsCOMPtr<nsISimpleEnumerator> res = new XPCWrappedJSIterator(jsEnum);
-            res.forget(aInstancePtr);
-            return NS_OK;
-        }
-    }
-
     // else we do the more expensive stuff...
 
     // check if the JSObject claims to implement this interface
     RootedObject jsobj(ccx, CallQueryInterfaceOnJSObject(ccx, obj, objScope, aIID));
     if (jsobj) {
         // We can't use XPConvert::JSObject2NativeInterface() here
         // since that can find a XPCWrappedNative directly on the
         // proto chain, and we don't want that here. We need to find
--- a/js/xpconnect/tests/unit/test_wrapped_js_enumerator.js
+++ b/js/xpconnect/tests/unit/test_wrapped_js_enumerator.js
@@ -4,54 +4,68 @@
 // equivalent nsISimpleEnumerator objects.
 
 const Variant = Components.Constructor("@mozilla.org/variant;1",
                                        "nsIWritableVariant",
                                        "setFromVariant");
 const SupportsInterfacePointer = Components.Constructor(
   "@mozilla.org/supports-interface-pointer;1", "nsISupportsInterfacePointer");
 
-function wrapEnumerator(iter) {
+function wrapEnumerator1(iter) {
   var ip = SupportsInterfacePointer();
   ip.data = iter;
   return ip.data.QueryInterface(Ci.nsISimpleEnumerator);
 }
 
+function wrapEnumerator2(iter) {
+  var ip = SupportsInterfacePointer();
+  ip.data = {
+    QueryInterface: ChromeUtils.generateQI([Ci.nsIFilePicker]),
+    get files() {
+      return iter;
+    },
+  };
+  return ip.data.QueryInterface(Ci.nsIFilePicker).files;
+}
+
+
 function enumToArray(iter) {
   let result = [];
   while (iter.hasMoreElements()) {
     result.push(iter.getNext().QueryInterface(Ci.nsIVariant));
   }
   return result;
 }
 
 add_task(async function test_wrapped_js_enumerator() {
   let array = [1, 2, 3, 4];
 
-  // Test a plain JS iterator. This should automatically be wrapped into
-  // an equivalent nsISimpleEnumerator.
-  {
-    let iter = wrapEnumerator(array.values());
-    let result = enumToArray(iter);
+  for (let wrapEnumerator of [wrapEnumerator1, wrapEnumerator2]) {
+    // Test a plain JS iterator. This should automatically be wrapped into
+    // an equivalent nsISimpleEnumerator.
+    {
+      let iter = wrapEnumerator(array.values());
+      let result = enumToArray(iter);
 
-    deepEqual(result, array, "Got correct result");
-  }
+      deepEqual(result, array, "Got correct result");
+    }
 
-  // Test an object with a QueryInterface method, which implements
-  // nsISimpleEnumerator. This should be wrapped and used directly.
-  {
-    let obj = {
-      QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
-      _idx: 0,
-      hasMoreElements() {
-        return this._idx < array.length;
-      },
-      getNext() {
-        return Variant(array[this._idx++]);
-      },
-    };
+    // Test an object with a QueryInterface method, which implements
+    // nsISimpleEnumerator. This should be wrapped and used directly.
+    {
+      let obj = {
+        QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
+        _idx: 0,
+        hasMoreElements() {
+          return this._idx < array.length;
+        },
+        getNext() {
+          return Variant(array[this._idx++]);
+        },
+      };
 
-    let iter = wrapEnumerator(obj);
-    let result = enumToArray(iter);
+      let iter = wrapEnumerator(obj);
+      let result = enumToArray(iter);
 
-    deepEqual(result, array, "Got correct result");
+      deepEqual(result, array, "Got correct result");
+    }
   }
 });
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -480,30 +480,29 @@ BulletRenderer::CreateWebRenderCommandsF
     nsLayoutUtils::ComputeImageContainerDrawingParameters(mImage, aItem->Frame(), destRect,
                                                           aSc, flags, svgContext);
   RefPtr<layers::ImageContainer> container =
     mImage->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
   if (!container) {
     return false;
   }
 
+  mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
+    nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container, aBuilder, aResources,
-                                                                      aSc, size, Nothing());
+  Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
+    aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
   if (key.isNothing()) {
     return true;  // Nothing to do
   }
 
   wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
 
-  aBuilder.PushImage(dest,
-                     dest,
-                     !aItem->BackfaceIsHidden(),
-                     wr::ImageRendering::Auto,
-                     key.value());
+  aBuilder.PushImage(
+    dest, dest, !aItem->BackfaceIsHidden(), rendering, key.value());
 
   return true;
 }
 
 bool
 BulletRenderer::CreateWebRenderCommandsForPath(nsDisplayItem* aItem,
                                                wr::DisplayListBuilder& aBuilder,
                                                wr::IpcResourceUpdateQueue& aResources,
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3854,19 +3854,28 @@ nsCSSBorderImageRenderer::CreateWebRende
         nsLayoutUtils::ComputeImageContainerDrawingParameters(
           img, aForFrame, destRect, aSc, flags, svgContext);
       RefPtr<layers::ImageContainer> container =
         img->GetImageContainerAtSize(aManager, decodeSize, svgContext, flags);
       if (!container) {
         return;
       }
 
+      mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
+        nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
       gfx::IntSize size;
-      Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
-        aItem, container, aBuilder, aResources, aSc, size, Nothing());
+      Maybe<wr::ImageKey> key =
+        aManager->CommandBuilder().CreateImageKey(aItem,
+                                                  container,
+                                                  aBuilder,
+                                                  aResources,
+                                                  rendering,
+                                                  aSc,
+                                                  size,
+                                                  Nothing());
       if (key.isNothing()) {
         return;
       }
 
       aBuilder.PushBorderImage(
         dest,
         clip,
         !aItem->BackfaceIsHidden(),
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -644,47 +644,81 @@ nsImageRenderer::BuildWebRenderDisplayIt
       RefPtr<layers::ImageContainer> container =
         mImageContainer->GetImageContainerAtSize(
           aManager, decodeSize, svgContext, containerFlags);
       if (!container) {
         NS_WARNING("Failed to get image container");
         return ImgDrawResult::NOT_READY;
       }
 
+      mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
+        nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
       gfx::IntSize size;
-      Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
-        aItem, container, aBuilder, aResources, aSc, size, Nothing());
+      Maybe<wr::ImageKey> key =
+        aManager->CommandBuilder().CreateImageKey(aItem,
+                                                  container,
+                                                  aBuilder,
+                                                  aResources,
+                                                  rendering,
+                                                  aSc,
+                                                  size,
+                                                  Nothing());
 
       if (key.isNothing()) {
         return ImgDrawResult::NOT_READY;
       }
 
       nsPoint firstTilePos = nsLayoutUtils::GetBackgroundFirstTilePos(
         aDest.TopLeft(), aFill.TopLeft(), aRepeatSize);
       LayoutDeviceRect fillRect =
         LayoutDeviceRect::FromAppUnits(nsRect(firstTilePos.x,
                                               firstTilePos.y,
                                               aFill.XMost() - firstTilePos.x,
                                               aFill.YMost() - firstTilePos.y),
                                        appUnitsPerDevPixel);
       wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
+
+      wr::LayoutRect roundedDest = wr::ToRoundedLayoutRect(destRect);
+      auto stretchSize = wr::ToLayoutSize(destRect.Size());
+
+      // WebRender special cases situations where stretchSize == fillSize to
+      // infer that it shouldn't use repeat sampling. This makes sure
+      // we hit those special cases when not repeating.
+
+      switch (mExtendMode) {
+        case ExtendMode::CLAMP:
+          fill = roundedDest;
+          stretchSize = roundedDest.size;
+          break;
+        case ExtendMode::REPEAT_Y:
+          fill.origin.x = roundedDest.origin.x;
+          fill.size.width = roundedDest.size.width;
+          stretchSize.width = roundedDest.size.width;
+          break;
+        case ExtendMode::REPEAT_X:
+          fill.origin.y = roundedDest.origin.y;
+          fill.size.height = roundedDest.size.height;
+          stretchSize.height = roundedDest.size.height;
+          break;
+        default:
+          break;
+      }
+
       wr::LayoutRect clip = wr::ToRoundedLayoutRect(
         LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
 
       LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
         aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
 
-      SamplingFilter samplingFilter =
-        nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
       aBuilder.PushImage(fill,
                          clip,
                          !aItem->BackfaceIsHidden(),
-                         wr::ToLayoutSize(destRect.Size()),
+                         stretchSize,
                          wr::ToLayoutSize(gapSize),
-                         wr::ToImageRendering(samplingFilter),
+                         rendering,
                          key.value());
       break;
     }
     default:
       break;
   }
 
   return mImage->IsComplete() ? ImgDrawResult::SUCCESS
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -454,30 +454,34 @@ nsImageBoxFrame::CreateWebRenderCommands
                                                           aSc, containerFlags, svgContext);
   RefPtr<layers::ImageContainer> container =
     imgCon->GetImageContainerAtSize(aManager, decodeSize, svgContext, containerFlags);
   if (!container) {
     NS_WARNING("Failed to get image container");
     return Nothing();
   }
 
+  mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
+    nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
   gfx::IntSize size;
-  Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container,
-                                                                      aBuilder, aResources,
-                                                                      aSc, size, Nothing());
+  Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
+    aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
   if (key.isNothing()) {
     return Some(ImgDrawResult::NOT_READY);
   }
   wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
 
   LayoutDeviceSize gapSize(0, 0);
-  SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
-  aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),
-                     wr::ToLayoutSize(fillRect.Size()), wr::ToLayoutSize(gapSize),
-                     wr::ToImageRendering(sampleFilter), key.value());
+  aBuilder.PushImage(fill,
+                     fill,
+                     !BackfaceIsHidden(),
+                     wr::ToLayoutSize(fillRect.Size()),
+                     wr::ToLayoutSize(gapSize),
+                     rendering,
+                     key.value());
 
   return Some(ImgDrawResult::SUCCESS);
 }
 
 nsRect
 nsImageBoxFrame::GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint)
 {
   nsCOMPtr<imgIContainer> imgCon;
--- a/mfbt/Attributes.h
+++ b/mfbt/Attributes.h
@@ -725,36 +725,33 @@
      /* in debug builds, these classes do have non-trivial constructors. */
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class")))
 #  else
 #    define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \
             MOZ_TRIVIAL_CTOR_DTOR
 #  endif
 #  define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
 #  define MOZ_IS_SMARTPTR_TO_REFCOUNTED __attribute__((annotate("moz_is_smartptr_to_refcounted")))
-#  define MOZ_IS_REFPTR __attribute__((annotate("moz_is_refptr"))) \
-                        MOZ_IS_SMARTPTR_TO_REFCOUNTED
+#  define MOZ_IS_REFPTR MOZ_IS_SMARTPTR_TO_REFCOUNTED
 #  define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
-#  define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
-#  define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
-#  define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
+#  define MOZ_OWNING_REF
+#  define MOZ_NON_OWNING_REF
+#  define MOZ_UNSAFE_REF(reason)
 #  define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
 #  define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
 #  define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
 #  define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable")))
 #  define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
 #  define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members")))
 #  define MOZ_NO_DANGLING_ON_TEMPORARIES __attribute__((annotate("moz_no_dangling_on_temporaries")))
 #  define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
     __attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
 #  define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
-#  define MOZ_INIT_OUTSIDE_CTOR \
-    __attribute__((annotate("moz_ignore_ctor_initialization")))
-#  define MOZ_IS_CLASS_INIT \
-    __attribute__((annotate("moz_is_class_init")))
+#  define MOZ_INIT_OUTSIDE_CTOR
+#  define MOZ_IS_CLASS_INIT
 #  define MOZ_NON_PARAM \
     __attribute__((annotate("moz_non_param")))
 #  define MOZ_REQUIRED_BASE_METHOD \
     __attribute__((annotate("moz_required_base_method")))
 #  define MOZ_MUST_RETURN_FROM_CALLER \
     __attribute__((annotate("moz_must_return_from_caller")))
 #  define MOZ_MAY_CALL_AFTER_MUST_RETURN \
     __attribute__((annotate("moz_may_call_after_must_return")))
--- a/mfbt/RecordReplay.cpp
+++ b/mfbt/RecordReplay.cpp
@@ -42,18 +42,16 @@ namespace recordreplay {
 
 #define FOR_EACH_INTERFACE_VOID(Macro)                          \
   Macro(InternalBeginOrderedAtomicAccess, (), ())               \
   Macro(InternalEndOrderedAtomicAccess, (), ())                 \
   Macro(InternalBeginPassThroughThreadEvents, (), ())           \
   Macro(InternalEndPassThroughThreadEvents, (), ())             \
   Macro(InternalBeginDisallowThreadEvents, (), ())              \
   Macro(InternalEndDisallowThreadEvents, (), ())                \
-  Macro(InternalBeginCaptureEventStacks, (), ())                \
-  Macro(InternalEndCaptureEventStacks, (), ())                  \
   Macro(InternalRecordReplayBytes,                              \
         (void* aData, size_t aSize), (aData, aSize))            \
   Macro(NotifyUnrecordedWait,                                   \
         (const std::function<void()>& aCallback), (aCallback))  \
   Macro(MaybeWaitForCheckpointSave, (), ())                     \
   Macro(InternalInvalidateRecording, (const char* aWhy), (aWhy)) \
   Macro(InternalDestroyPLDHashTableCallbacks,                   \
         (const PLDHashTableOps* aOps), (aOps))                  \
--- a/mfbt/RecordReplay.h
+++ b/mfbt/RecordReplay.h
@@ -162,28 +162,16 @@ static inline bool AreThreadEventsDisall
 
 // RAII class for a region where thread events are disallowed.
 struct MOZ_RAII AutoDisallowThreadEvents
 {
   AutoDisallowThreadEvents() { BeginDisallowThreadEvents(); }
   ~AutoDisallowThreadEvents() { EndDisallowThreadEvents(); }
 };
 
-// Mark a region where thread events should have stack information captured.
-// These stacks help in tracking down record/replay inconsistencies.
-static inline void BeginCaptureEventStacks();
-static inline void EndCaptureEventStacks();
-
-// RAII class for a region where thread event stacks should be captured.
-struct MOZ_RAII AutoCaptureEventStacks
-{
-  AutoCaptureEventStacks() { BeginCaptureEventStacks(); }
-  ~AutoCaptureEventStacks() { EndCaptureEventStacks(); }
-};
-
 // Record or replay a value in the current thread's event stream.
 static inline size_t RecordReplayValue(size_t aValue);
 
 // Record or replay the contents of a range of memory in the current thread's
 // event stream.
 static inline void RecordReplayBytes(void* aData, size_t aSize);
 
 // During recording or replay, mark the recording as unusable. There are some
@@ -425,18 +413,16 @@ NoteContentParse(const void* aToken,
 MOZ_MakeRecordReplayWrapperVoid(BeginOrderedAtomicAccess, (), ())
 MOZ_MakeRecordReplayWrapperVoid(EndOrderedAtomicAccess, (), ())
 MOZ_MakeRecordReplayWrapperVoid(BeginPassThroughThreadEvents, (), ())
 MOZ_MakeRecordReplayWrapperVoid(EndPassThroughThreadEvents, (), ())
 MOZ_MakeRecordReplayWrapper(AreThreadEventsPassedThrough, bool, false, (), ())
 MOZ_MakeRecordReplayWrapperVoid(BeginDisallowThreadEvents, (), ())
 MOZ_MakeRecordReplayWrapperVoid(EndDisallowThreadEvents, (), ())
 MOZ_MakeRecordReplayWrapper(AreThreadEventsDisallowed, bool, false, (), ())
-MOZ_MakeRecordReplayWrapperVoid(BeginCaptureEventStacks, (), ())
-MOZ_MakeRecordReplayWrapperVoid(EndCaptureEventStacks, (), ())
 MOZ_MakeRecordReplayWrapper(RecordReplayValue, size_t, aValue, (size_t aValue), (aValue))
 MOZ_MakeRecordReplayWrapperVoid(RecordReplayBytes, (void* aData, size_t aSize), (aData, aSize))
 MOZ_MakeRecordReplayWrapper(HasDivergedFromRecording, bool, false, (), ())
 MOZ_MakeRecordReplayWrapper(GeneratePLDHashTableCallbacks,
                             const PLDHashTableOps*, aOps, (const PLDHashTableOps* aOps), (aOps))
 MOZ_MakeRecordReplayWrapper(UnwrapPLDHashTableCallbacks,
                             const PLDHashTableOps*, aOps, (const PLDHashTableOps* aOps), (aOps))
 MOZ_MakeRecordReplayWrapperVoid(DestroyPLDHashTableCallbacks,
--- a/mobile/android/chrome/content/content.js
+++ b/mobile/android/chrome/content/content.js
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "AboutReader", "resource://gre/modules/AboutReader.jsm");
 ChromeUtils.defineModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
+ChromeUtils.defineModuleGetter(this, "Readerable", "resource://gre/modules/Readerable.jsm");
 ChromeUtils.defineModuleGetter(this, "LoginManagerContent", "resource://gre/modules/LoginManagerContent.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
   return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
 });
 XPCOMUtils.defineLazyGetter(this, "gNSSErrorsBundle", function() {
   return Services.strings.createBundle("chrome://pipnss/locale/nsserrors.properties");
 });
@@ -481,17 +482,17 @@ var AboutReaderListener = {
         this.updateReaderButton();
         break;
     }
   },
   updateReaderButton: function(forceNonArticle) {
     // Do not show Reader View icon on error pages (bug 1320900)
     if (this.isErrorPage) {
         sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
-    } else if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
+    } else if (!Readerable.isEnabledForParseOnLoad || this.isAboutReader ||
         !(content.document instanceof content.HTMLDocument) ||
         content.document.mozSyntheticDocument) {
 
     } else {
         this.scheduleReadabilityCheckPostPaint(forceNonArticle);
     }
   },
 
@@ -517,21 +518,22 @@ var AboutReaderListener = {
     // possible that this page hasn't been laid out yet, in which case we
     // should wait until we get an event that does relate to our layout. We
     // determine whether any of our content got painted by checking if there
     // are any painted rects.
     if (!event.clientRects.length) {
       return;
     }
 
+    Services.console.logStringMessage(`ON PAINT WHEN WAITED FOR\n`);
     this.cancelPotentialPendingReadabilityCheck();
 
     // Only send updates when there are articles; there's no point updating with
     // |false| all the time.
-    if (ReaderMode.isProbablyReaderable(content.document)) {
+    if (Readerable.isProbablyReaderable(content.document)) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
     } else if (forceNonArticle) {
       sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
     }
   },
 };
 AboutReaderListener.init();
 
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -170,25 +170,21 @@ net_NewIncrementalDownload(nsISupports *
 
 #include "nsMIMEHeaderParamImpl.h"
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEHeaderParamImpl)
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "nsRequestObserverProxy.h"
 #include "nsSimpleStreamListener.h"
-#include "nsDirIndexParser.h"
-#include "nsDirIndex.h"
 
 typedef mozilla::net::nsRequestObserverProxy nsRequestObserverProxy;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsRequestObserverProxy)
 typedef mozilla::net::nsSimpleStreamListener nsSimpleStreamListener;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleStreamListener)
-NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDirIndexParser, Init)
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsDirIndex)
 
 ///////////////////////////////////////////////////////////////////////////////
 
 #include "nsStreamListenerTee.h"
 typedef mozilla::net::nsStreamListenerTee nsStreamListenerTee;
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamListenerTee)
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -699,23 +695,21 @@ NS_DEFINE_NAMED_CID(NS_MIMEINPUTSTREAM_C
 NS_DEFINE_NAMED_CID(NS_PROTOCOLPROXYSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_STREAMCONVERTERSERVICE_CID);
 #if defined(XP_WIN)
 NS_DEFINE_NAMED_CID(NS_NAMEDPIPESERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_DASHBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_FTPDIRLISTINGCONVERTER_CID);
 NS_DEFINE_NAMED_CID(NS_NSINDEXEDTOHTMLCONVERTER_CID);
-NS_DEFINE_NAMED_CID(NS_DIRINDEXPARSER_CID);
 NS_DEFINE_NAMED_CID(NS_MULTIMIXEDCONVERTER_CID);
 NS_DEFINE_NAMED_CID(NS_UNKNOWNDECODER_CID);
 NS_DEFINE_NAMED_CID(NS_BINARYDETECTOR_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPCOMPRESSCONVERTER_CID);
 NS_DEFINE_NAMED_CID(MOZITXTTOHTMLCONV_CID);
-NS_DEFINE_NAMED_CID(NS_DIRINDEX_CID);
 NS_DEFINE_NAMED_CID(NS_MIMEHEADERPARAM_CID);
 NS_DEFINE_NAMED_CID(NS_FILEPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPSPROTOCOLHANDLER_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPBASICAUTH_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPDIGESTAUTH_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPNTLMAUTH_CID);
 NS_DEFINE_NAMED_CID(NS_HTTPAUTHMANAGER_CID);
@@ -819,23 +813,21 @@ static const mozilla::Module::CIDEntry k
     { &kNS_PROTOCOLPROXYSERVICE_CID, true, nullptr, nsProtocolProxyServiceConstructor },
     { &kNS_STREAMCONVERTERSERVICE_CID, false, nullptr, CreateNewStreamConvServiceFactory },
 #if defined (XP_WIN)
     { &kNS_NAMEDPIPESERVICE_CID, false, NULL, mozilla::net::NamedPipeServiceConstructor },
 #endif
     { &kNS_DASHBOARD_CID, false, nullptr, mozilla::net::DashboardConstructor },
     { &kNS_FTPDIRLISTINGCONVERTER_CID, false, nullptr, CreateNewFTPDirListingConv },
     { &kNS_NSINDEXEDTOHTMLCONVERTER_CID, false, nullptr, nsIndexedToHTML::Create },
-    { &kNS_DIRINDEXPARSER_CID, false, nullptr, nsDirIndexParserConstructor },
     { &kNS_MULTIMIXEDCONVERTER_CID, false, nullptr, CreateNewMultiMixedConvFactory },
     { &kNS_UNKNOWNDECODER_CID, false, nullptr, CreateNewUnknownDecoderFactory },
     { &kNS_BINARYDETECTOR_CID, false, nullptr, CreateNewBinaryDetectorFactory },
     { &kNS_HTTPCOMPRESSCONVERTER_CID, false, nullptr, CreateNewHTTPCompressConvFactory },
     { &kMOZITXTTOHTMLCONV_CID, false, nullptr, CreateNewTXTToHTMLConvFactory },
-    { &kNS_DIRINDEX_CID, false, nullptr, nsDirIndexConstructor },
     { &kNS_MIMEHEADERPARAM_CID, false, nullptr, nsMIMEHeaderParamImplConstructor },
     { &kNS_FILEPROTOCOLHANDLER_CID, false, nullptr, nsFileProtocolHandlerConstructor },
     { &kNS_HTTPPROTOCOLHANDLER_CID, false, nullptr, mozilla::net::nsHttpHandlerConstructor },
     { &kNS_HTTPSPROTOCOLHANDLER_CID, false, nullptr, mozilla::net::nsHttpsHandlerConstructor },
     { &kNS_HTTPBASICAUTH_CID, false, nullptr, mozilla::net::nsHttpBasicAuthConstructor },
     { &kNS_HTTPDIGESTAUTH_CID, false, nullptr, mozilla::net::nsHttpDigestAuthConstructor },
     { &kNS_HTTPNTLMAUTH_CID, false, nullptr, mozilla::net::nsHttpNTLMAuthConstructor },
     { &kNS_HTTPAUTHMANAGER_CID, false, nullptr, mozilla::net::nsHttpAuthManagerConstructor },
@@ -938,30 +930,28 @@ static const mozilla::Module::ContractID
     { NS_PROTOCOLPROXYSERVICE_CONTRACTID, &kNS_PROTOCOLPROXYSERVICE_CID },
     { NS_STREAMCONVERTERSERVICE_CONTRACTID, &kNS_STREAMCONVERTERSERVICE_CID },
 #if defined(XP_WIN)
     { NS_NAMEDPIPESERVICE_CONTRACTID, &kNS_NAMEDPIPESERVICE_CID },
 #endif
     { NS_DASHBOARD_CONTRACTID, &kNS_DASHBOARD_CID },
     { NS_ISTREAMCONVERTER_KEY FTP_TO_INDEX, &kNS_FTPDIRLISTINGCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY INDEX_TO_HTML, &kNS_NSINDEXEDTOHTMLCONVERTER_CID },
-    { NS_DIRINDEXPARSER_CONTRACTID, &kNS_DIRINDEXPARSER_CID },
     { NS_ISTREAMCONVERTER_KEY MULTI_MIXED_X, &kNS_MULTIMIXEDCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY MULTI_BYTERANGES, &kNS_MULTIMIXEDCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY MULTI_MIXED, &kNS_MULTIMIXEDCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY UNKNOWN_CONTENT, &kNS_UNKNOWNDECODER_CID },
     { NS_BINARYDETECTOR_CONTRACTID, &kNS_BINARYDETECTOR_CID },
     { NS_ISTREAMCONVERTER_KEY GZIP_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY XGZIP_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY BROTLI_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY COMPRESS_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY XCOMPRESS_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { NS_ISTREAMCONVERTER_KEY DEFLATE_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
     { MOZ_TXTTOHTMLCONV_CONTRACTID, &kMOZITXTTOHTMLCONV_CID },
-    { "@mozilla.org/dirIndex;1", &kNS_DIRINDEX_CID },
     { NS_MIMEHEADERPARAM_CONTRACTID, &kNS_MIMEHEADERPARAM_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file", &kNS_FILEPROTOCOLHANDLER_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &kNS_HTTPPROTOCOLHANDLER_CID },
     { NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "https", &kNS_HTTPSPROTOCOLHANDLER_CID },
     { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "basic", &kNS_HTTPBASICAUTH_CID },
     { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "digest", &kNS_HTTPDIGESTAUTH_CID },
     { NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX "ntlm", &kNS_HTTPNTLMAUTH_CID },
     { NS_HTTPAUTHMANAGER_CONTRACTID, &kNS_HTTPAUTHMANAGER_CID },
--- a/netwerk/streamconv/converters/nsDirIndex.h
+++ b/netwerk/streamconv/converters/nsDirIndex.h
@@ -1,19 +1,20 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#ifndef nsDirIndex_h__
+#define nsDirIndex_h__
+
 #include "nsIDirIndex.h"
 #include "nsString.h"
 #include "mozilla/Attributes.h"
 
-/* CID: {f6913e2e-1dd1-11b2-84be-f455dee342af} */
-
 class nsDirIndex final : public nsIDirIndex {
 
 private:
     ~nsDirIndex() = default;
 
 public:
     nsDirIndex();
 
@@ -23,8 +24,10 @@ public:
 protected:
     uint32_t mType;
     nsCString mContentType;
     nsCString mLocation;
     nsString mDescription;
     int64_t mSize;
     PRTime mLastModified;
 };
+
+#endif
--- a/netwerk/streamconv/converters/nsDirIndexParser.cpp
+++ b/netwerk/streamconv/converters/nsDirIndexParser.cpp
@@ -7,16 +7,17 @@
 
 #include "nsDirIndexParser.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/dom/FallbackEncoding.h"
 #include "mozilla/Encoding.h"
 #include "prprf.h"
 #include "nsCRT.h"
+#include "nsDirIndex.h"
 #include "nsEscape.h"
 #include "nsIDirIndex.h"
 #include "nsIInputStream.h"
 #include "nsITextToSubURI.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla;
 
@@ -390,19 +391,17 @@ nsDirIndexParser::ProcessData(nsIRequest
           if (buf[2] == '0' && buf[3] == ':') {
             // 200. Define field names
             rv = ParseFormat(buf + 4);
             if (NS_FAILED(rv)) {
               return rv;
             }
           } else if (buf[2] == '1' && buf[3] == ':') {
             // 201. Field data
-            nsCOMPtr<nsIDirIndex> idx = do_CreateInstance("@mozilla.org/dirIndex;1",&rv);
-            if (NS_FAILED(rv))
-              return rv;
+            nsCOMPtr<nsIDirIndex> idx = new nsDirIndex();
 
             rv = ParseData(idx, ((char *)buf) + 4, lineLen - 4);
             if (NS_FAILED(rv)) {
               return rv;
             }
 
             mListener->OnIndexAvailable(aRequest, aCtxt, idx);
           }
--- a/netwerk/streamconv/converters/nsDirIndexParser.h
+++ b/netwerk/streamconv/converters/nsDirIndexParser.h
@@ -4,35 +4,46 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NSDIRINDEX_H_
 #define __NSDIRINDEX_H_
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIDirIndexListener.h"
+#include "mozilla/RefPtr.h"
 
 class nsIDirIndex;
 class nsITextToSubURI;
 
 /* CID: {a0d6ad32-1dd1-11b2-aa55-a40187b54036} */
 
 class nsDirIndexParser : public nsIDirIndexParser {
 
 private:
     virtual ~nsDirIndexParser();
 
+    nsDirIndexParser();
+    nsresult Init();
+
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSIDIRINDEXPARSER
 
-    nsDirIndexParser();
-    nsresult Init();
+    static already_AddRefed<nsIDirIndexParser>
+    CreateInstance()
+    {
+      RefPtr<nsDirIndexParser> parser = new nsDirIndexParser();
+      if (NS_FAILED(parser->Init())) {
+        return nullptr;
+      }
+      return parser.forget();
+    }
 
     enum fieldType {
         FIELD_UNKNOWN = 0, // MUST be 0
         FIELD_FILENAME,
         FIELD_DESCRIPTION,
         FIELD_CONTENTLENGTH,
         FIELD_LASTMODIFIED,
         FIELD_CONTENTTYPE,
--- a/netwerk/streamconv/converters/nsIndexedToHTML.cpp
+++ b/netwerk/streamconv/converters/nsIndexedToHTML.cpp
@@ -17,16 +17,17 @@
 #include "nsEscape.h"
 #include "nsIDirIndex.h"
 #include "nsURLHelper.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefLocalizedString.h"
 #include "nsIStringBundle.h"
 #include "nsITextToSubURI.h"
+#include "nsDirIndexParser.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsString.h"
 #include <algorithm>
 #include "nsIChannel.h"
 #include "mozilla/Unused.h"
 
 using mozilla::intl::LocaleService;
 
@@ -146,18 +147,18 @@ nsIndexedToHTML::DoOnStartRequest(nsIReq
     // resource:// url, instead of the jar:file:// url it resolves to.
     if (!isResource) {
         rv = channel->GetURI(getter_AddRefs(uri));
         if (NS_FAILED(rv)) return rv;
     }
 
     channel->SetContentType(NS_LITERAL_CSTRING("text/html"));
 
-    mParser = do_CreateInstance("@mozilla.org/dirIndexParser;1",&rv);
-    if (NS_FAILED(rv)) return rv;
+    mParser = nsDirIndexParser::CreateInstance();
+    if (!mParser) return NS_ERROR_FAILURE;
 
     rv = mParser->SetListener(this);
     if (NS_FAILED(rv)) return rv;
 
     rv = mParser->OnStartRequest(request, aContext);
     if (NS_FAILED(rv)) return rv;
 
     nsAutoCString baseUri, titleUri;
--- a/netwerk/streamconv/nsIDirIndex.idl
+++ b/netwerk/streamconv/nsIDirIndex.idl
@@ -65,18 +65,8 @@ interface nsIDirIndex : nsISupports
     /**
      * Last-modified time in seconds-since-epoch.
      * -1 means unknown - this is valid, because there were no
      * ftp servers in 1969
      */
     attribute PRTime lastModified;
 };
 
-%{C++
-
-#define NS_DIRINDEX_CID \
-/* { f6913e2e-1dd1-11b2-84be-f455dee342af } */ \
-{ 0xf6913e2e, \
-  0x1dd1, \
-  0x11b2, \
-  { 0x84, 0xbe, 0xf4, 0x55, 0xde, 0xe3, 0x42, 0xaf } \
-}
-%}
--- a/netwerk/streamconv/nsIDirIndexListener.idl
+++ b/netwerk/streamconv/nsIDirIndexListener.idl
@@ -33,20 +33,16 @@ interface nsIDirIndexListener : nsISuppo
      * @param info - new info to add
      */
     void onInformationAvailable(in nsIRequest aRequest,
                                 in nsISupports aCtxt,
                                 in AString aInfo);
 
 };
 
-%{C++
-#define NS_IDIRINDEXLISTENER_KEY         "@mozilla.org/dirIndexListener;1"
-%}
-
 /**
  * A parser for application/http-index-format
  */
 [scriptable, uuid(38e3066c-1dd2-11b2-9b59-8be515c1ee3f)]
 interface nsIDirIndexParser : nsIStreamListener {
     /**
      * The interface to use as a callback for new entries
      */
@@ -60,20 +56,8 @@ interface nsIDirIndexParser : nsIStreamL
     readonly attribute string comment;
 
     /**
      * The encoding to use
      */
     attribute string encoding;
 };
 
-%{C++
-#define NS_DIRINDEXPARSER_CID \
-{ /* a0d6ad32-1dd1-11b2-aa55-a40187b54036 */ \
-    0xa0d6ad32, \
-    0x1dd1, \
-    0x11b2, \
-    { 0xaa, 0x55, 0xa4, 0x01, 0x87, 0xb5, 0x40, 0x36 } \
-}
-
-#define NS_DIRINDEXPARSER_CONTRACTID "@mozilla.org/dirIndexParser;1"
-
-%}
deleted file mode 100644
--- a/security/manager/ssl/RootHashes.inc.orig
+++ /dev/null
@@ -1,1207 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*****************************************************************************/
-/* This is an automatically generated file. If you're not                    */
-/* RootCertificateTelemetryUtils.cpp, you shouldn't be #including it.        */
-/*****************************************************************************/
-
-#define HASH_LEN 32
-struct CertAuthorityHash {
-  // See bug 1338873 about making these fields const.
-  uint8_t hash[HASH_LEN];
-  int32_t binNumber;
-};
-
-static const struct CertAuthorityHash ROOT_TABLE[] = {
-  {
-    /* Entrust_Root_Certification_Authority___EC1 */
-    { 0x02, 0xED, 0x0E, 0xB2, 0x8C, 0x14, 0xDA, 0x45, 0x16, 0x5C, 0x56, 0x67, 0x91, 0x70, 0x0D, 0x64,
-      0x51, 0xD7, 0xFB, 0x56, 0xF0, 0xB2, 0xAB, 0x1D, 0x3B, 0x8E, 0xB0, 0x70, 0xE5, 0x6E, 0xDF, 0xF5 },
-      164 /* Bin Number */
-  },
-  {
-    /* AffirmTrust_Commercial */
-    { 0x03, 0x76, 0xAB, 0x1D, 0x54, 0xC5, 0xF9, 0x80, 0x3C, 0xE4, 0xB2, 0xE2, 0x01, 0xA0, 0xEE, 0x7E,
-      0xEF, 0x7B, 0x57, 0xB6, 0x36, 0xE8, 0xA9, 0x3C, 0x9B, 0x8D, 0x48, 0x60, 0xC9, 0x6F, 0x5F, 0xA7 },
-      109 /* Bin Number */
-  },
-  {
-    /* ACEDICOM_Root */
-    { 0x03, 0x95, 0x0F, 0xB4, 0x9A, 0x53, 0x1F, 0x3E, 0x19, 0x91, 0x94, 0x23, 0x98, 0xDF, 0xA9, 0xE0,
-      0xEA, 0x32, 0xD7, 0xBA, 0x1C, 0xDD, 0x9B, 0xC8, 0x5D, 0xB5, 0x7E, 0xD9, 0x40, 0x0B, 0x43, 0x4A },
-      98 /* Bin Number */
-  },
-  {
-    /* Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068 */
-    { 0x04, 0x04, 0x80, 0x28, 0xBF, 0x1F, 0x28, 0x64, 0xD4, 0x8F, 0x9A, 0xD4, 0xD8, 0x32, 0x94, 0x36,
-      0x6A, 0x82, 0x88, 0x56, 0x55, 0x3F, 0x3B, 0x14, 0x30, 0x3F, 0x90, 0x14, 0x7F, 0x5D, 0x40, 0xEF },
-      102 /* Bin Number */
-  },
-  {
-    /* Chambers_of_Commerce_Root___2008 */
-    { 0x06, 0x3E, 0x4A, 0xFA, 0xC4, 0x91, 0xDF, 0xD3, 0x32, 0xF3, 0x08, 0x9B, 0x85, 0x42, 0xE9, 0x46,
-      0x17, 0xD8, 0x93, 0xD7, 0xFE, 0x94, 0x4E, 0x10, 0xA7, 0x93, 0x7E, 0xE2, 0x9D, 0x96, 0x93, 0xC0 },
-      104 /* Bin Number */
-  },
-  {
-    /* DST_Root_CA_X3 */
-    { 0x06, 0x87, 0x26, 0x03, 0x31, 0xA7, 0x24, 0x03, 0xD9, 0x09, 0xF1, 0x05, 0xE6, 0x9B, 0xCF, 0x0D,
-      0x32, 0xE1, 0xBD, 0x24, 0x93, 0xFF, 0xC6, 0xD9, 0x20, 0x6D, 0x11, 0xBC, 0xD6, 0x77, 0x07, 0x39 },
-      52 /* Bin Number */
-  },
-  {
-    /* TrustCor_RootCert_CA_2 */
-    { 0x07, 0x53, 0xE9, 0x40, 0x37, 0x8C, 0x1B, 0xD5, 0xE3, 0x83, 0x6E, 0x39, 0x5D, 0xAE, 0xA5, 0xCB,
-      0x83, 0x9E, 0x50, 0x46, 0xF1, 0xBD, 0x0E, 0xAE, 0x19, 0x51, 0xCF, 0x10, 0xFE, 0xC7, 0xC9, 0x65 },
-      191 /* Bin Number */
-  },
-  {
-    /* AddTrust_Public_CA_Root */
-    { 0x07, 0x91, 0xCA, 0x07, 0x49, 0xB2, 0x07, 0x82, 0xAA, 0xD3, 0xC7, 0xD7, 0xBD, 0x0C, 0xDF, 0xC9,
-      0x48, 0x58, 0x35, 0x84, 0x3E, 0xB2, 0xD7, 0x99, 0x60, 0x09, 0xCE, 0x43, 0xAB, 0x6C, 0x69, 0x27 },
-      16 /* Bin Number */
-  },
-  {
-    /* OU_Equifax_Secure_Certificate_Authority_O_Equifax_C_US */
-    { 0x08, 0x29, 0x7A, 0x40, 0x47, 0xDB, 0xA2, 0x36, 0x80, 0xC7, 0x31, 0xDB, 0x6E, 0x31, 0x76, 0x53,
-      0xCA, 0x78, 0x48, 0xE1, 0xBE, 0xBD, 0x3A, 0x0B, 0x01, 0x79, 0xA7, 0x07, 0xF9, 0x2C, 0xF1, 0x78 },
-      4 /* Bin Number */
-  },
-  {
-    /* AffirmTrust_Networking */
-    { 0x0A, 0x81, 0xEC, 0x5A, 0x92, 0x97, 0x77, 0xF1, 0x45, 0x90, 0x4A, 0xF3, 0x8D, 0x5D, 0x50, 0x9F,
-      0x66, 0xB5, 0xE2, 0xC5, 0x8F, 0xCD, 0xB5, 0x31, 0x05, 0x8B, 0x0E, 0x17, 0xF3, 0xF0, 0xB4, 0x1B },
-      110 /* Bin Number */
-  },
-  {
-    /* Chambers_of_Commerce_Root */
-    { 0x0C, 0x25, 0x8A, 0x12, 0xA5, 0x67, 0x4A, 0xEF, 0x25, 0xF2, 0x8B, 0xA7, 0xDC, 0xFA, 0xEC, 0xEE,
-      0xA3, 0x48, 0xE5, 0x41, 0xE6, 0xF5, 0xCC, 0x4E, 0xE6, 0x3B, 0x71, 0xB3, 0x61, 0x60, 0x6A, 0xC3 },
-      39 /* Bin Number */
-  },
-  {
-    /* COMODO_Certification_Authority */
-    { 0x0C, 0x2C, 0xD6, 0x3D, 0xF7, 0x80, 0x6F, 0xA3, 0x99, 0xED, 0xE8, 0x09, 0x11, 0x6B, 0x57, 0x5B,
-      0xF8, 0x79, 0x89, 0xF0, 0x65, 0x18, 0xF9, 0x80, 0x8C, 0x86, 0x05, 0x03, 0x17, 0x8B, 0xAF, 0x66 },
-      63 /* Bin Number */
-  },
-  {
-    /* Buypass_Class_2_CA_1 */
-    { 0x0F, 0x4E, 0x9C, 0xDD, 0x26, 0x4B, 0x02, 0x55, 0x50, 0xD1, 0x70, 0x80, 0x63, 0x40, 0x21, 0x4F,
-      0xE9, 0x44, 0x34, 0xC9, 0xB0, 0x2F, 0x69, 0x7E, 0xC7, 0x10, 0xFC, 0x5F, 0xEA, 0xFB, 0x5E, 0x38 },
-      80 /* Bin Number */
-  },
-  {
-    /* Class_2_Primary_CA */
-    { 0x0F, 0x99, 0x3C, 0x8A, 0xEF, 0x97, 0xBA, 0xAF, 0x56, 0x87, 0x14, 0x0E, 0xD5, 0x9A, 0xD1, 0x82,
-      0x1B, 0xB4, 0xAF, 0xAC, 0xF0, 0xAA, 0x9A, 0x58, 0xB5, 0xD5, 0x7A, 0x33, 0x8A, 0x3A, 0xFB, 0xCB },
-      51 /* Bin Number */
-  },
-  {
-    /* Global_Chambersign_Root___2008 */
-    { 0x13, 0x63, 0x35, 0x43, 0x93, 0x34, 0xA7, 0x69, 0x80, 0x16, 0xA0, 0xD3, 0x24, 0xDE, 0x72, 0x28,
-      0x4E, 0x07, 0x9D, 0x7B, 0x52, 0x20, 0xBB, 0x8F, 0xBD, 0x74, 0x78, 0x16, 0xEE, 0xBE, 0xBA, 0xCA },
-      105 /* Bin Number */
-  },
-  {
-    /* OU_Starfield_Class_2_Certification_Authority_O__Starfield_Technologies__Inc___C_US */
-    { 0x14, 0x65, 0xFA, 0x20, 0x53, 0x97, 0xB8, 0x76, 0xFA, 0xA6, 0xF0, 0xA9, 0x95, 0x8E, 0x55, 0x90,
-      0xE4, 0x0F, 0xCC, 0x7F, 0xAA, 0x4F, 0xB7, 0xC2, 0xC8, 0x67, 0x75, 0x21, 0xFB, 0x5F, 0xB6, 0x58 },
-      44 /* Bin Number */
-  },
-  {
-    /* Certplus_Root_CA_G1 */
-    { 0x15, 0x2A, 0x40, 0x2B, 0xFC, 0xDF, 0x2C, 0xD5, 0x48, 0x05, 0x4D, 0x22, 0x75, 0xB3, 0x9C, 0x7F,
-      0xCA, 0x3E, 0xC0, 0x97, 0x80, 0x78, 0xB0, 0xF0, 0xEA, 0x76, 0xE5, 0x61, 0xA6, 0xC7, 0x43, 0x3E },
-      176 /* Bin Number */
-  },
-  {
-    /* Network_Solutions_Certificate_Authority */
-    { 0x15, 0xF0, 0xBA, 0x00, 0xA3, 0xAC, 0x7A, 0xF3, 0xAC, 0x88, 0x4C, 0x07, 0x2B, 0x10, 0x11, 0xA0,
-      0x77, 0xBD, 0x77, 0xC0, 0x97, 0xF4, 0x01, 0x64, 0xB2, 0xF8, 0x59, 0x8A, 0xBD, 0x83, 0x86, 0x0C },
-      64 /* Bin Number */
-  },
-  {
-    /* Baltimore_CyberTrust_Root */
-    { 0x16, 0xAF, 0x57, 0xA9, 0xF6, 0x76, 0xB0, 0xAB, 0x12, 0x60, 0x95, 0xAA, 0x5E, 0xBA, 0xDE, 0xF2,
-      0x2A, 0xB3, 0x11, 0x19, 0xD6, 0x44, 0xAC, 0x95, 0xCD, 0x4B, 0x93, 0xDB, 0xF3, 0xF2, 0x6A, 0xEB },
-      11 /* Bin Number */
-  },
-  {
-    /* COMODO_ECC_Certification_Authority */
-    { 0x17, 0x93, 0x92, 0x7A, 0x06, 0x14, 0x54, 0x97, 0x89, 0xAD, 0xCE, 0x2F, 0x8F, 0x34, 0xF7, 0xF0,
-      0xB6, 0x6D, 0x0F, 0x3A, 0xE3, 0xA3, 0xB8, 0x4D, 0x21, 0xEC, 0x15, 0xDB, 0xBA, 0x4F, 0xAD, 0xC7 },
-      66 /* Bin Number */
-  },
-  {
-    /* GlobalSign */
-    { 0x17, 0x9F, 0xBC, 0x14, 0x8A, 0x3D, 0xD0, 0x0F, 0xD2, 0x4E, 0xA1, 0x34, 0x58, 0xCC, 0x43, 0xBF,
-      0xA7, 0xF5, 0x9C, 0x81, 0x82, 0xD7, 0x83, 0xA5, 0x13, 0xF6, 0xEB, 0xEC, 0x10, 0x0C, 0x89, 0x24 },
-      158 /* Bin Number */
-  },
-  {
-    /* Amazon_Root_CA_3 */
-    { 0x18, 0xCE, 0x6C, 0xFE, 0x7B, 0xF1, 0x4E, 0x60, 0xB2, 0xE3, 0x47, 0xB8, 0xDF, 0xE8, 0x68, 0xCB,
-      0x31, 0xD0, 0x2E, 0xBB, 0x3A, 0xDA, 0x27, 0x15, 0x69, 0xF5, 0x03, 0x43, 0xB4, 0x6D, 0xB3, 0xA4 },
-      185 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_CA_3 */
-    { 0x18, 0xF1, 0xFC, 0x7F, 0x20, 0x5D, 0xF8, 0xAD, 0xDD, 0xEB, 0x7F, 0xE0, 0x07, 0xDD, 0x57, 0xE3,
-      0xAF, 0x37, 0x5A, 0x9C, 0x4D, 0x8D, 0x73, 0x54, 0x6B, 0xF4, 0xF1, 0xFE, 0xD1, 0xE1, 0x8D, 0x35 },
-      33 /* Bin Number */
-  },
-  {
-    /* Amazon_Root_CA_2 */
-    { 0x1B, 0xA5, 0xB2, 0xAA, 0x8C, 0x65, 0x40, 0x1A, 0x82, 0x96, 0x01, 0x18, 0xF8, 0x0B, 0xEC, 0x4F,
-      0x62, 0x30, 0x4D, 0x83, 0xCE, 0xC4, 0x71, 0x3A, 0x19, 0xC3, 0x9C, 0x01, 0x1E, 0xA4, 0x6D, 0xB4 },
-      184 /* Bin Number */
-  },
-  {
-    /* China_Internet_Network_Information_Center_EV_Certificates_Root */
-    { 0x1C, 0x01, 0xC6, 0xF4, 0xDB, 0xB2, 0xFE, 0xFC, 0x22, 0x55, 0x8B, 0x2B, 0xCA, 0x32, 0x56, 0x3F,
-      0x49, 0x84, 0x4A, 0xCF, 0xC3, 0x2B, 0x7B, 0xE4, 0xB0, 0xFF, 0x59, 0x9F, 0x9E, 0x8C, 0x7A, 0xF7 },
-      133 /* Bin Number */
-  },
-  {
-    /* Swisscom_Root_CA_1 */
-    { 0x21, 0xDB, 0x20, 0x12, 0x36, 0x60, 0xBB, 0x2E, 0xD4, 0x18, 0x20, 0x5D, 0xA1, 0x1E, 0xE7, 0xA8,
-      0x5A, 0x65, 0xE2, 0xBC, 0x6E, 0x55, 0xB5, 0xAF, 0x7E, 0x78, 0x99, 0xC8, 0xA2, 0x66, 0xD9, 0x2E },
-      47 /* Bin Number */
-  },
-  {
-    /* SSL_com_EV_Root_Certification_Authority_ECC */
-    { 0x22, 0xA2, 0xC1, 0xF7, 0xBD, 0xED, 0x70, 0x4C, 0xC1, 0xE7, 0x01, 0xB5, 0xF4, 0x08, 0xC3, 0x10,
-      0x88, 0x0F, 0xE9, 0x56, 0xB5, 0xDE, 0x2A, 0x4A, 0x44, 0xF9, 0x9C, 0x87, 0x3A, 0x25, 0xA7, 0xC8 },
-      196 /* Bin Number */
-  },
-  {
-    /* VeriSign_Universal_Root_Certification_Authority */
-    { 0x23, 0x99, 0x56, 0x11, 0x27, 0xA5, 0x71, 0x25, 0xDE, 0x8C, 0xEF, 0xEA, 0x61, 0x0D, 0xDF, 0x2F,
-      0xA0, 0x78, 0xB5, 0xC8, 0x06, 0x7F, 0x4E, 0x82, 0x82, 0x90, 0xBF, 0xB8, 0x60, 0xE8, 0x4B, 0x3C },
-      90 /* Bin Number */
-  },
-  {
-    /* Izenpe_com */
-    { 0x25, 0x30, 0xCC, 0x8E, 0x98, 0x32, 0x15, 0x02, 0xBA, 0xD9, 0x6F, 0x9B, 0x1F, 0xBA, 0x1B, 0x09,
-      0x9E, 0x2D, 0x29, 0x9E, 0x0F, 0x45, 0x48, 0xBB, 0x91, 0x4F, 0x36, 0x3B, 0xC0, 0xD4, 0x53, 0x1F },
-      103 /* Bin Number */
-  },
-  {
-    /* OpenTrust_Root_CA_G2 */
-    { 0x27, 0x99, 0x58, 0x29, 0xFE, 0x6A, 0x75, 0x15, 0xC1, 0xBF, 0xE8, 0x48, 0xF9, 0xC4, 0x76, 0x1D,
-      0xB1, 0x6C, 0x22, 0x59, 0x29, 0x25, 0x7B, 0xF4, 0x0D, 0x08, 0x94, 0xF2, 0x9E, 0xA8, 0xBA, 0xF2 },
-      179 /* Bin Number */
-  },
-  {
-    /* Certinomis___Root_CA */
-    { 0x2A, 0x99, 0xF5, 0xBC, 0x11, 0x74, 0xB7, 0x3C, 0xBB, 0x1D, 0x62, 0x08, 0x84, 0xE0, 0x1C, 0x34,
-      0xE5, 0x1C, 0xCB, 0x39, 0x78, 0xDA, 0x12, 0x5F, 0x0E, 0x33, 0x26, 0x88, 0x83, 0xBF, 0x41, 0x58 },
-      168 /* Bin Number */
-  },
-  {
-    /* GlobalSign */
-    { 0x2C, 0xAB, 0xEA, 0xFE, 0x37, 0xD0, 0x6C, 0xA2, 0x2A, 0xBA, 0x73, 0x91, 0xC0, 0x03, 0x3D, 0x25,
-      0x98, 0x29, 0x52, 0xC4, 0x53, 0x64, 0x73, 0x49, 0x76, 0x3A, 0x3A, 0xB5, 0xAD, 0x6C, 0xCF, 0x69 },
-      197 /* Bin Number */
-  },
-  {
-    /* Starfield_Root_Certificate_Authority___G2 */
-    { 0x2C, 0xE1, 0xCB, 0x0B, 0xF9, 0xD2, 0xF9, 0xE1, 0x02, 0x99, 0x3F, 0xBE, 0x21, 0x51, 0x52, 0xC3,
-      0xB2, 0xDD, 0x0C, 0xAB, 0xDE, 0x1C, 0x68, 0xE5, 0x31, 0x9B, 0x83, 0x91, 0x54, 0xDB, 0xB7, 0xF5 },
-      107 /* Bin Number */
-  },
-  {
-    /* OU_ApplicationCA_O_Japanese_Government_C_JP */
-    { 0x2D, 0x47, 0x43, 0x7D, 0xE1, 0x79, 0x51, 0x21, 0x5A, 0x12, 0xF3, 0xC5, 0x8E, 0x51, 0xC7, 0x29,
-      0xA5, 0x80, 0x26, 0xEF, 0x1F, 0xCC, 0x0A, 0x5F, 0xB3, 0xD9, 0xDC, 0x01, 0x2F, 0x60, 0x0D, 0x19 },
-      85 /* Bin Number */
-  },
-  {
-    /* SSL_com_EV_Root_Certification_Authority_RSA_R2 */
-    { 0x2E, 0x7B, 0xF1, 0x6C, 0xC2, 0x24, 0x85, 0xA7, 0xBB, 0xE2, 0xAA, 0x86, 0x96, 0x75, 0x07, 0x61,
-      0xB0, 0xAE, 0x39, 0xBE, 0x3B, 0x2F, 0xE9, 0xD0, 0xCC, 0x6D, 0x4E, 0xF7, 0x34, 0x91, 0x42, 0x5C },
-      195 /* Bin Number */
-  },
-  {
-    /* IdenTrust_Public_Sector_Root_CA_1 */
-    { 0x30, 0xD0, 0x89, 0x5A, 0x9A, 0x44, 0x8A, 0x26, 0x20, 0x91, 0x63, 0x55, 0x22, 0xD1, 0xF5, 0x20,
-      0x10, 0xB5, 0x86, 0x7A, 0xCA, 0xE1, 0x2C, 0x78, 0xEF, 0x95, 0x8F, 0xD4, 0xF4, 0x38, 0x9F, 0x2F },
-      162 /* Bin Number */
-  },
-  {
-    /* DigiCert_Global_Root_G3 */
-    { 0x31, 0xAD, 0x66, 0x48, 0xF8, 0x10, 0x41, 0x38, 0xC7, 0x38, 0xF3, 0x9E, 0xA4, 0x32, 0x01, 0x33,
-      0x39, 0x3E, 0x3A, 0x18, 0xCC, 0x02, 0x29, 0x6E, 0xF9, 0x7C, 0x2A, 0xC9, 0xEF, 0x67, 0x31, 0xD0 },
-      150 /* Bin Number */
-  },
-  {
-    /* Microsec_e_Szigno_Root_CA */
-    { 0x32, 0x7A, 0x3D, 0x76, 0x1A, 0xBA, 0xDE, 0xA0, 0x34, 0xEB, 0x99, 0x84, 0x06, 0x27, 0x5C, 0xB1,
-      0xA4, 0x77, 0x6E, 0xFD, 0xAE, 0x2F, 0xDF, 0x6D, 0x01, 0x68, 0xEA, 0x1C, 0x4F, 0x55, 0x67, 0xD0 },
-      70 /* Bin Number */
-  },
-  {
-    /* SSL_com_Root_Certification_Authority_ECC */
-    { 0x34, 0x17, 0xBB, 0x06, 0xCC, 0x60, 0x07, 0xDA, 0x1B, 0x96, 0x1C, 0x92, 0x0B, 0x8A, 0xB4, 0xCE,
-      0x3F, 0xAD, 0x82, 0x0E, 0x4A, 0xA3, 0x0B, 0x9A, 0xCB, 0xC4, 0xA7, 0x4E, 0xBD, 0xCE, 0xBC, 0x65 },
-      194 /* Bin Number */
-  },
-  {
-    /* EBG_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_ */
-    { 0x35, 0xAE, 0x5B, 0xDD, 0xD8, 0xF7, 0xAE, 0x63, 0x5C, 0xFF, 0xBA, 0x56, 0x82, 0xA8, 0xF0, 0x0B,
-      0x95, 0xF4, 0x84, 0x62, 0xC7, 0x10, 0x8E, 0xE9, 0xA0, 0xE5, 0x29, 0x2B, 0x07, 0x4A, 0xAF, 0xB2 },
-      82 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Primary_Certification_Authority */
-    { 0x37, 0xD5, 0x10, 0x06, 0xC5, 0x12, 0xEA, 0xAB, 0x62, 0x64, 0x21, 0xF1, 0xEC, 0x8C, 0x92, 0x01,
-      0x3F, 0xC5, 0xF8, 0x2A, 0xE9, 0x8E, 0xE5, 0x33, 0xEB, 0x46, 0x19, 0xB8, 0xDE, 0xB4, 0xD0, 0x6C },
-      58 /* Bin Number */
-  },
-  {
-    /* Staat_der_Nederlanden_Root_CA___G3 */
-    { 0x3C, 0x4F, 0xB0, 0xB9, 0x5A, 0xB8, 0xB3, 0x00, 0x32, 0xF4, 0x32, 0xB8, 0x6F, 0x53, 0x5F, 0xE1,
-      0x72, 0xC1, 0x85, 0xD0, 0xFD, 0x39, 0x86, 0x58, 0x37, 0xCF, 0x36, 0x18, 0x7F, 0xA6, 0xF4, 0x28 },
-      159 /* Bin Number */
-  },
-  {
-    /* Microsec_e_Szigno_Root_CA_2009 */
-    { 0x3C, 0x5F, 0x81, 0xFE, 0xA5, 0xFA, 0xB8, 0x2C, 0x64, 0xBF, 0xA2, 0xEA, 0xEC, 0xAF, 0xCD, 0xE8,
-      0xE0, 0x77, 0xFC, 0x86, 0x20, 0xA7, 0xCA, 0xE5, 0x37, 0x16, 0x3D, 0xF3, 0x6E, 0xDB, 0xF3, 0x78 },
-      99 /* Bin Number */
-  },
-  {
-    /* PSCProcert */
-    { 0x3C, 0xFC, 0x3C, 0x14, 0xD1, 0xF6, 0x84, 0xFF, 0x17, 0xE3, 0x8C, 0x43, 0xCA, 0x44, 0x0C, 0x00,
-      0xB9, 0x67, 0xEC, 0x93, 0x3E, 0x8B, 0xFE, 0x06, 0x4C, 0xA1, 0xD7, 0x2C, 0x90, 0xF2, 0xAD, 0xB0 },
-      132 /* Bin Number */
-  },
-  {
-    /* EE_Certification_Centre_Root_CA */
-    { 0x3E, 0x84, 0xBA, 0x43, 0x42, 0x90, 0x85, 0x16, 0xE7, 0x75, 0x73, 0xC0, 0x99, 0x2F, 0x09, 0x79,
-      0xCA, 0x08, 0x4E, 0x46, 0x85, 0x68, 0x1F, 0xF1, 0x95, 0xCC, 0xBA, 0x8A, 0x22, 0x9B, 0x8A, 0x76 },
-      128 /* Bin Number */
-  },
-  {
-    /* DigiCert_Assured_ID_Root_CA */
-    { 0x3E, 0x90, 0x99, 0xB5, 0x01, 0x5E, 0x8F, 0x48, 0x6C, 0x00, 0xBC, 0xEA, 0x9D, 0x11, 0x1E, 0xE7,
-      0x21, 0xFA, 0xBA, 0x35, 0x5A, 0x89, 0xBC, 0xF1, 0xDF, 0x69, 0x56, 0x1E, 0x3D, 0xC6, 0x32, 0x5C },
-      48 /* Bin Number */
-  },
-  {
-    /* Trusted_Certificate_Services */
-    { 0x3F, 0x06, 0xE5, 0x56, 0x81, 0xD4, 0x96, 0xF5, 0xBE, 0x16, 0x9E, 0xB5, 0x38, 0x9F, 0x9F, 0x2B,
-      0x8F, 0xF6, 0x1E, 0x17, 0x08, 0xDF, 0x68, 0x81, 0x72, 0x48, 0x49, 0xCD, 0x5D, 0x27, 0xCB, 0x69 },
-      30 /* Bin Number */
-  },
-  {
-    /* OISTE_WISeKey_Global_Root_GA_CA */
-    { 0x41, 0xC9, 0x23, 0x86, 0x6A, 0xB4, 0xCA, 0xD6, 0xB7, 0xAD, 0x57, 0x80, 0x81, 0x58, 0x2E, 0x02,
-      0x07, 0x97, 0xA6, 0xCB, 0xDF, 0x4F, 0xFF, 0x78, 0xCE, 0x83, 0x96, 0xB3, 0x89, 0x37, 0xD7, 0xF5 },
-      69 /* Bin Number */
-  },
-  {
-    /* Secure_Global_CA */
-    { 0x42, 0x00, 0xF5, 0x04, 0x3A, 0xC8, 0x59, 0x0E, 0xBB, 0x52, 0x7D, 0x20, 0x9E, 0xD1, 0x50, 0x30,
-      0x29, 0xFB, 0xCB, 0xD4, 0x1C, 0xA1, 0xB5, 0x06, 0xEC, 0x27, 0xF1, 0x5A, 0xDE, 0x7D, 0xAC, 0x69 },
-      62 /* Bin Number */
-  },
-  {
-    /* DigiCert_Global_Root_CA */
-    { 0x43, 0x48, 0xA0, 0xE9, 0x44, 0x4C, 0x78, 0xCB, 0x26, 0x5E, 0x05, 0x8D, 0x5E, 0x89, 0x44, 0xB4,
-      0xD8, 0x4F, 0x96, 0x62, 0xBD, 0x26, 0xDB, 0x25, 0x7F, 0x89, 0x34, 0xA4, 0x43, 0xC7, 0x01, 0x61 },
-      49 /* Bin Number */
-  },
-  {
-    /* Entrust_Root_Certification_Authority___G2 */
-    { 0x43, 0xDF, 0x57, 0x74, 0xB0, 0x3E, 0x7F, 0xEF, 0x5F, 0xE4, 0x0D, 0x93, 0x1A, 0x7B, 0xED, 0xF1,
-      0xBB, 0x2E, 0x6B, 0x42, 0x73, 0x8C, 0x4E, 0x6D, 0x38, 0x41, 0x10, 0x3D, 0x3A, 0xA7, 0xF3, 0x39 },
-      163 /* Bin Number */
-  },
-  {
-    /* T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_ */
-    { 0x44, 0x04, 0xE3, 0x3B, 0x5E, 0x14, 0x0D, 0xCF, 0x99, 0x80, 0x51, 0xFD, 0xFC, 0x80, 0x28, 0xC7,
-      0xC8, 0x16, 0x15, 0xC5, 0xEE, 0x73, 0x7B, 0x11, 0x1B, 0x58, 0x82, 0x33, 0xA9, 0xB5, 0x35, 0xA0 },
-      54 /* Bin Number */
-  },
-  {
-    /* Hellenic_Academic_and_Research_Institutions_ECC_RootCA_2015 */
-    { 0x44, 0xB5, 0x45, 0xAA, 0x8A, 0x25, 0xE6, 0x5A, 0x73, 0xCA, 0x15, 0xDC, 0x27, 0xFC, 0x36, 0xD2,
-      0x4C, 0x1C, 0xB9, 0x95, 0x3A, 0x06, 0x65, 0x39, 0xB1, 0x15, 0x82, 0xDC, 0x48, 0x7B, 0x48, 0x33 },
-      175 /* Bin Number */
-  },
-  {
-    /* Go_Daddy_Root_Certificate_Authority___G2 */
-    { 0x45, 0x14, 0x0B, 0x32, 0x47, 0xEB, 0x9C, 0xC8, 0xC5, 0xB4, 0xF0, 0xD7, 0xB5, 0x30, 0x91, 0xF7,
-      0x32, 0x92, 0x08, 0x9E, 0x6E, 0x5A, 0x63, 0xE2, 0x74, 0x9D, 0xD3, 0xAC, 0xA9, 0x19, 0x8E, 0xDA },
-      106 /* Bin Number */
-  },
-  {
-    /* TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi___Surum_1 */
-    { 0x46, 0xED, 0xC3, 0x68, 0x90, 0x46, 0xD5, 0x3A, 0x45, 0x3F, 0xB3, 0x10, 0x4A, 0xB8, 0x0D, 0xCA,
-      0xEC, 0x65, 0x8B, 0x26, 0x60, 0xEA, 0x16, 0x29, 0xDD, 0x7E, 0x86, 0x79, 0x90, 0x64, 0x87, 0x16 },
-      188 /* Bin Number */
-  },
-  {
-    /* T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s__H5 */
-    { 0x49, 0x35, 0x1B, 0x90, 0x34, 0x44, 0xC1, 0x85, 0xCC, 0xDC, 0x5C, 0x69, 0x3D, 0x24, 0xD8, 0x55,
-      0x5C, 0xB2, 0x08, 0xD6, 0xA8, 0x14, 0x13, 0x07, 0x69, 0x9F, 0x4A, 0xF0, 0x63, 0x19, 0x9D, 0x78 },
-      166 /* Bin Number */
-  },
-  {
-    /* D_TRUST_Root_Class_3_CA_2_2009 */
-    { 0x49, 0xE7, 0xA4, 0x42, 0xAC, 0xF0, 0xEA, 0x62, 0x87, 0x05, 0x00, 0x54, 0xB5, 0x25, 0x64, 0xB6,
-      0x50, 0xE4, 0xF4, 0x9E, 0x42, 0xE3, 0x48, 0xD6, 0xAA, 0x38, 0xE0, 0x39, 0xE9, 0x57, 0xB1, 0xC1 },
-      130 /* Bin Number */
-  },
-  {
-    /* thawte_Primary_Root_CA___G3 */
-    { 0x4B, 0x03, 0xF4, 0x58, 0x07, 0xAD, 0x70, 0xF2, 0x1B, 0xFC, 0x2C, 0xAE, 0x71, 0xC9, 0xFD, 0xE4,
-      0x60, 0x4C, 0x06, 0x4C, 0xF5, 0xFF, 0xB6, 0x86, 0xBA, 0xE5, 0xDB, 0xAA, 0xD7, 0xFD, 0xD3, 0x4C },
-      88 /* Bin Number */
-  },
-  {
-    /* Certification_Authority_of_WoSign */
-    { 0x4B, 0x22, 0xD5, 0xA6, 0xAE, 0xC9, 0x9F, 0x3C, 0xDB, 0x79, 0xAA, 0x5E, 0xC0, 0x68, 0x38, 0x47,
-      0x9C, 0xD5, 0xEC, 0xBA, 0x71, 0x64, 0xF7, 0xF2, 0x2D, 0xC1, 0xD6, 0x5F, 0x63, 0xD8, 0x57, 0x08 },
-      152 /* Bin Number */
-  },
-  {
-    /* Staat_der_Nederlanden_EV_Root_CA */
-    { 0x4D, 0x24, 0x91, 0x41, 0x4C, 0xFE, 0x95, 0x67, 0x46, 0xEC, 0x4C, 0xEF, 0xA6, 0xCF, 0x6F, 0x72,
-      0xE2, 0x8A, 0x13, 0x29, 0x43, 0x2F, 0x9D, 0x8A, 0x90, 0x7A, 0xC4, 0xCB, 0x5D, 0xAD, 0xC1, 0x5A },
-      160 /* Bin Number */
-  },
-  {
-    /* USERTrust_ECC_Certification_Authority */
-    { 0x4F, 0xF4, 0x60, 0xD5, 0x4B, 0x9C, 0x86, 0xDA, 0xBF, 0xBC, 0xFC, 0x57, 0x12, 0xE0, 0x40, 0x0D,
-      0x2B, 0xED, 0x3F, 0xBC, 0x4D, 0x4F, 0xBD, 0xAA, 0x86, 0xE0, 0x6A, 0xDC, 0xD2, 0xA9, 0xAD, 0x7A },
-      156 /* Bin Number */
-  },
-  {
-    /* ComSign_Secured_CA */
-    { 0x50, 0x79, 0x41, 0xC7, 0x44, 0x60, 0xA0, 0xB4, 0x70, 0x86, 0x22, 0x0D, 0x4E, 0x99, 0x32, 0x57,
-      0x2A, 0xB5, 0xD1, 0xB5, 0xBB, 0xCB, 0x89, 0x80, 0xAB, 0x1C, 0xB1, 0x76, 0x51, 0xA8, 0x44, 0xD2 },
-      76 /* Bin Number */
-  },
-  {
-    /* OU_Security_Communication_RootCA2_O__SECOM_Trust_Systems_CO__LTD___C_JP */
-    { 0x51, 0x3B, 0x2C, 0xEC, 0xB8, 0x10, 0xD4, 0xCD, 0xE5, 0xDD, 0x85, 0x39, 0x1A, 0xDF, 0xC6, 0xC2,
-      0xDD, 0x60, 0xD8, 0x7B, 0xB7, 0x36, 0xD2, 0xB5, 0x21, 0x48, 0x4A, 0xA4, 0x7A, 0x0E, 0xBE, 0xF6 },
-      118 /* Bin Number */
-  },
-  {
-    /* COMODO_RSA_Certification_Authority */
-    { 0x52, 0xF0, 0xE1, 0xC4, 0xE5, 0x8E, 0xC6, 0x29, 0x29, 0x1B, 0x60, 0x31, 0x7F, 0x07, 0x46, 0x71,
-      0xB8, 0x5D, 0x7E, 0xA8, 0x0D, 0x5B, 0x07, 0x27, 0x34, 0x63, 0x53, 0x4B, 0x32, 0xB4, 0x02, 0x34 },
-      154 /* Bin Number */
-  },
-  {
-    /* LuxTrust_Global_Root_2 */
-    { 0x54, 0x45, 0x5F, 0x71, 0x29, 0xC2, 0x0B, 0x14, 0x47, 0xC4, 0x18, 0xF9, 0x97, 0x16, 0x8F, 0x24,
-      0xC5, 0x8F, 0xC5, 0x02, 0x3B, 0xF5, 0xDA, 0x5B, 0xE2, 0xEB, 0x6E, 0x1D, 0xD8, 0x90, 0x2E, 0xD5 },
-      187 /* Bin Number */
-  },
-  {
-    /* DigiCert_Trusted_Root_G4 */
-    { 0x55, 0x2F, 0x7B, 0xDC, 0xF1, 0xA7, 0xAF, 0x9E, 0x6C, 0xE6, 0x72, 0x01, 0x7F, 0x4F, 0x12, 0xAB,
-      0xF7, 0x72, 0x40, 0xC7, 0x8E, 0x76, 0x1A, 0xC2, 0x03, 0xD1, 0xD9, 0xD2, 0x0A, 0xC8, 0x99, 0x88 },
-      151 /* Bin Number */
-  },
-  {
-    /* Actalis_Authentication_Root_CA */
-    { 0x55, 0x92, 0x60, 0x84, 0xEC, 0x96, 0x3A, 0x64, 0xB9, 0x6E, 0x2A, 0xBE, 0x01, 0xCE, 0x0B, 0xA8,
-      0x6A, 0x64, 0xFB, 0xFE, 0xBC, 0xC7, 0xAA, 0xB5, 0xAF, 0xC1, 0x55, 0xB3, 0x7F, 0xD7, 0x60, 0x66 },
-      121 /* Bin Number */
-  },
-  {
-    /* Starfield_Services_Root_Certificate_Authority___G2 */
-    { 0x56, 0x8D, 0x69, 0x05, 0xA2, 0xC8, 0x87, 0x08, 0xA4, 0xB3, 0x02, 0x51, 0x90, 0xED, 0xCF, 0xED,
-      0xB1, 0x97, 0x4A, 0x60, 0x6A, 0x13, 0xC6, 0xE5, 0x29, 0x0F, 0xCB, 0x2A, 0xE6, 0x3E, 0xDA, 0xB5 },
-      108 /* Bin Number */
-  },
-  {
-    /* OpenTrust_Root_CA_G1 */
-    { 0x56, 0xC7, 0x71, 0x28, 0xD9, 0x8C, 0x18, 0xD9, 0x1B, 0x4C, 0xFD, 0xFF, 0xBC, 0x25, 0xEE, 0x91,
-      0x03, 0xD4, 0x75, 0x8E, 0xA2, 0xAB, 0xAD, 0x82, 0x6A, 0x90, 0xF3, 0x45, 0x7D, 0x46, 0x0E, 0xB4 },
-      178 /* Bin Number */
-  },
-  {
-    /* TWCA_Global_Root_CA */
-    { 0x59, 0x76, 0x90, 0x07, 0xF7, 0x68, 0x5D, 0x0F, 0xCD, 0x50, 0x87, 0x2F, 0x9F, 0x95, 0xD5, 0x75,
-      0x5A, 0x5B, 0x2B, 0x45, 0x7D, 0x81, 0xF3, 0x69, 0x2B, 0x61, 0x0A, 0x98, 0x67, 0x2F, 0x0E, 0x1B },
-      139 /* Bin Number */
-  },
-  {
-    /* TrustCor_ECA_1 */
-    { 0x5A, 0x88, 0x5D, 0xB1, 0x9C, 0x01, 0xD9, 0x12, 0xC5, 0x75, 0x93, 0x88, 0x93, 0x8C, 0xAF, 0xBB,
-      0xDF, 0x03, 0x1A, 0xB2, 0xD4, 0x8E, 0x91, 0xEE, 0x15, 0x58, 0x9B, 0x42, 0x97, 0x1D, 0x03, 0x9C },
-      192 /* Bin Number */
-  },
-  {
-    /* Certum_Trusted_Network_CA */
-    { 0x5C, 0x58, 0x46, 0x8D, 0x55, 0xF5, 0x8E, 0x49, 0x7E, 0x74, 0x39, 0x82, 0xD2, 0xB5, 0x00, 0x10,
-      0xB6, 0xD1, 0x65, 0x37, 0x4A, 0xCF, 0x83, 0xA7, 0xD4, 0xA3, 0x2D, 0xB7, 0x68, 0xC4, 0x40, 0x8E },
-      113 /* Bin Number */
-  },
-  {
-    /* CFCA_EV_ROOT */
-    { 0x5C, 0xC3, 0xD7, 0x8E, 0x4E, 0x1D, 0x5E, 0x45, 0x54, 0x7A, 0x04, 0xE6, 0x87, 0x3E, 0x64, 0xF9,
-      0x0C, 0xF9, 0x53, 0x6D, 0x1C, 0xCC, 0x2E, 0xF8, 0x00, 0xF3, 0x55, 0xC4, 0xC5, 0xFD, 0x70, 0xFD },
-      165 /* Bin Number */
-  },
-  {
-    /* IdenTrust_Commercial_Root_CA_1 */
-    { 0x5D, 0x56, 0x49, 0x9B, 0xE4, 0xD2, 0xE0, 0x8B, 0xCF, 0xCA, 0xD0, 0x8A, 0x3E, 0x38, 0x72, 0x3D,
-      0x50, 0x50, 0x3B, 0xDE, 0x70, 0x69, 0x48, 0xE4, 0x2F, 0x55, 0x60, 0x30, 0x19, 0xE5, 0x28, 0xAE },
-      161 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Primary_Certification_Authority___G2 */
-    { 0x5E, 0xDB, 0x7A, 0xC4, 0x3B, 0x82, 0xA0, 0x6A, 0x87, 0x61, 0xE8, 0xD7, 0xBE, 0x49, 0x79, 0xEB,
-      0xF2, 0x61, 0x1F, 0x7D, 0xD7, 0x9B, 0xF9, 0x1C, 0x1C, 0x6B, 0x56, 0x6A, 0x21, 0x9E, 0xD7, 0x66 },
-      89 /* Bin Number */
-  },
-  {
-    /* Equifax_Secure_Global_eBusiness_CA_1 */
-    { 0x5F, 0x0B, 0x62, 0xEA, 0xB5, 0xE3, 0x53, 0xEA, 0x65, 0x21, 0x65, 0x16, 0x58, 0xFB, 0xB6, 0x53,
-      0x59, 0xF4, 0x43, 0x28, 0x0A, 0x4A, 0xFB, 0xD1, 0x04, 0xD7, 0x7D, 0x10, 0xF9, 0xF0, 0x4C, 0x07 },
-      12 /* Bin Number */
-  },
-  {
-    /* SwissSign_Gold_CA___G2 */
-    { 0x62, 0xDD, 0x0B, 0xE9, 0xB9, 0xF5, 0x0A, 0x16, 0x3E, 0xA0, 0xF8, 0xE7, 0x5C, 0x05, 0x3B, 0x1E,
-      0xCA, 0x57, 0xEA, 0x55, 0xC8, 0x68, 0x8F, 0x64, 0x7C, 0x68, 0x81, 0xF2, 0xC8, 0x35, 0x7B, 0x95 },
-      56 /* Bin Number */
-  },
-  {
-    /* Staat_der_Nederlanden_Root_CA___G2 */
-    { 0x66, 0x8C, 0x83, 0x94, 0x7D, 0xA6, 0x3B, 0x72, 0x4B, 0xEC, 0xE1, 0x74, 0x3C, 0x31, 0xA0, 0xE6,
-      0xAE, 0xD0, 0xDB, 0x8E, 0xC5, 0xB3, 0x1B, 0xE3, 0x77, 0xBB, 0x78, 0x4F, 0x91, 0xB6, 0x71, 0x6F },
-      93 /* Bin Number */
-  },
-  {
-    /* AddTrust_External_CA_Root */
-    { 0x68, 0x7F, 0xA4, 0x51, 0x38, 0x22, 0x78, 0xFF, 0xF0, 0xC8, 0xB1, 0x1F, 0x8D, 0x43, 0xD5, 0x76,
-      0x67, 0x1C, 0x6E, 0xB2, 0xBC, 0xEA, 0xB4, 0x13, 0xFB, 0x83, 0xD9, 0x65, 0xD0, 0x6D, 0x2F, 0xF2 },
-      15 /* Bin Number */
-  },
-  {
-    /* VeriSign_Class_3_Public_Primary_Certification_Authority___G4 */
-    { 0x69, 0xDD, 0xD7, 0xEA, 0x90, 0xBB, 0x57, 0xC9, 0x3E, 0x13, 0x5D, 0xC8, 0x5E, 0xA6, 0xFC, 0xD5,
-      0x48, 0x0B, 0x60, 0x32, 0x39, 0xBD, 0xC4, 0x54, 0xFC, 0x75, 0x8B, 0x2A, 0x26, 0xCF, 0x7F, 0x79 },
-      91 /* Bin Number */
-  },
-  {
-    /* Visa_eCommerce_Root */
-    { 0x69, 0xFA, 0xC9, 0xBD, 0x55, 0xFB, 0x0A, 0xC7, 0x8D, 0x53, 0xBB, 0xEE, 0x5C, 0xF1, 0xD5, 0x97,
-      0x98, 0x9F, 0xD0, 0xAA, 0xAB, 0x20, 0xA2, 0x51, 0x51, 0xBD, 0xF1, 0x73, 0x3E, 0xE7, 0xD1, 0x22 },
-      26 /* Bin Number */
-  },
-  {
-    /* OISTE_WISeKey_Global_Root_GB_CA */
-    { 0x6B, 0x9C, 0x08, 0xE8, 0x6E, 0xB0, 0xF7, 0x67, 0xCF, 0xAD, 0x65, 0xCD, 0x98, 0xB6, 0x21, 0x49,
-      0xE5, 0x49, 0x4A, 0x67, 0xF5, 0x84, 0x5E, 0x7B, 0xD1, 0xED, 0x01, 0x9F, 0x27, 0xB8, 0x6B, 0xD6 },
-      169 /* Bin Number */
-  },
-  {
-    /* NetLock_Arany__Class_Gold__F_tan_s_tv_ny */
-    { 0x6C, 0x61, 0xDA, 0xC3, 0xA2, 0xDE, 0xF0, 0x31, 0x50, 0x6B, 0xE0, 0x36, 0xD2, 0xA6, 0xFE, 0x40,
-      0x19, 0x94, 0xFB, 0xD1, 0x3D, 0xF9, 0xC8, 0xD4, 0x66, 0x59, 0x92, 0x74, 0xC4, 0x46, 0xEC, 0x98 },
-      92 /* Bin Number */
-  },
-  {
-    /* Certplus_Root_CA_G2 */
-    { 0x6C, 0xC0, 0x50, 0x41, 0xE6, 0x44, 0x5E, 0x74, 0x69, 0x6C, 0x4C, 0xFB, 0xC9, 0xF8, 0x0F, 0x54,
-      0x3B, 0x7E, 0xAB, 0xBB, 0x44, 0xB4, 0xCE, 0x6F, 0x78, 0x7C, 0x6A, 0x99, 0x71, 0xC4, 0x2F, 0x17 },
-      177 /* Bin Number */
-  },
-  {
-    /* Entrust_net_Certification_Authority__2048_ */
-    { 0x6D, 0xC4, 0x71, 0x72, 0xE0, 0x1C, 0xBC, 0xB0, 0xBF, 0x62, 0x58, 0x0D, 0x89, 0x5F, 0xE2, 0xB8,
-      0xAC, 0x9A, 0xD4, 0xF8, 0x73, 0x80, 0x1E, 0x0C, 0x10, 0xB9, 0xC8, 0x37, 0xD2, 0x1E, 0xB1, 0x77 },
-      10 /* Bin Number */
-  },
-  {
-    /* UTN_USERFirst_Hardware */
-    { 0x6E, 0xA5, 0x47, 0x41, 0xD0, 0x04, 0x66, 0x7E, 0xED, 0x1B, 0x48, 0x16, 0x63, 0x4A, 0xA3, 0xA7,
-      0x9E, 0x6E, 0x4B, 0x96, 0x95, 0x0F, 0x82, 0x79, 0xDA, 0xFC, 0x8D, 0x9B, 0xD8, 0x81, 0x21, 0x37 },
-      38 /* Bin Number */
-  },
-  {
-    /* AffirmTrust_Premium */
-    { 0x70, 0xA7, 0x3F, 0x7F, 0x37, 0x6B, 0x60, 0x07, 0x42, 0x48, 0x90, 0x45, 0x34, 0xB1, 0x14, 0x82,
-      0xD5, 0xBF, 0x0E, 0x69, 0x8E, 0xCC, 0x49, 0x8D, 0xF5, 0x25, 0x77, 0xEB, 0xF2, 0xE9, 0x3B, 0x9A },
-      111 /* Bin Number */
-  },
-  {
-    /* Entrust_Root_Certification_Authority */
-    { 0x73, 0xC1, 0x76, 0x43, 0x4F, 0x1B, 0xC6, 0xD5, 0xAD, 0xF4, 0x5B, 0x0E, 0x76, 0xE7, 0x27, 0x28,
-      0x7C, 0x8D, 0xE5, 0x76, 0x16, 0xC1, 0xE6, 0xE6, 0x14, 0x1A, 0x2B, 0x2C, 0xBC, 0x7D, 0x8E, 0x4C },
-      18 /* Bin Number */
-  },
-  {
-    /* DigiCert_High_Assurance_EV_Root_CA */
-    { 0x74, 0x31, 0xE5, 0xF4, 0xC3, 0xC1, 0xCE, 0x46, 0x90, 0x77, 0x4F, 0x0B, 0x61, 0xE0, 0x54, 0x40,
-      0x88, 0x3B, 0xA9, 0xA0, 0x1E, 0xD0, 0x0B, 0xA6, 0xAB, 0xD7, 0x80, 0x6E, 0xD3, 0xB1, 0x18, 0xCF },
-      50 /* Bin Number */
-  },
-  {
-    /* O_Government_Root_Certification_Authority_C_TW */
-    { 0x76, 0x00, 0x29, 0x5E, 0xEF, 0xE8, 0x5B, 0x9E, 0x1F, 0xD6, 0x24, 0xDB, 0x76, 0x06, 0x2A, 0xAA,
-      0xAE, 0x59, 0x81, 0x8A, 0x54, 0xD2, 0x77, 0x4C, 0xD4, 0xC0, 0xB2, 0xC0, 0x11, 0x31, 0xE1, 0xB3 },
-      46 /* Bin Number */
-  },
-  {
-    /* DST_ACES_CA_X6 */
-    { 0x76, 0x7C, 0x95, 0x5A, 0x76, 0x41, 0x2C, 0x89, 0xAF, 0x68, 0x8E, 0x90, 0xA1, 0xC7, 0x0F, 0x55,
-      0x6C, 0xFD, 0x6B, 0x60, 0x25, 0xDB, 0xEA, 0x10, 0x41, 0x6D, 0x7E, 0xB6, 0x83, 0x1F, 0x8C, 0x40 },
-      53 /* Bin Number */
-  },
-  {
-    /* America_Online_Root_Certification_Authority_1 */
-    { 0x77, 0x40, 0x73, 0x12, 0xC6, 0x3A, 0x15, 0x3D, 0x5B, 0xC0, 0x0B, 0x4E, 0x51, 0x75, 0x9C, 0xDF,
-      0xDA, 0xC2, 0x37, 0xDC, 0x2A, 0x33, 0xB6, 0x79, 0x46, 0xE9, 0x8E, 0x9B, 0xFA, 0x68, 0x0A, 0xE3 },
-      24 /* Bin Number */
-  },
-  {
-    /* Sonera_Class2_CA */
-    { 0x79, 0x08, 0xB4, 0x03, 0x14, 0xC1, 0x38, 0x10, 0x0B, 0x51, 0x8D, 0x07, 0x35, 0x80, 0x7F, 0xFB,
-      0xFC, 0xF8, 0x51, 0x8A, 0x00, 0x95, 0x33, 0x71, 0x05, 0xBA, 0x38, 0x6B, 0x15, 0x3D, 0xD9, 0x27 },
-      35 /* Bin Number */
-  },
-  {
-    /* A_Trust_nQual_03 */
-    { 0x79, 0x3C, 0xBF, 0x45, 0x59, 0xB9, 0xFD, 0xE3, 0x8A, 0xB2, 0x2D, 0xF1, 0x68, 0x69, 0xF6, 0x98,
-      0x81, 0xAE, 0x14, 0xC4, 0xB0, 0x13, 0x9A, 0xC7, 0x88, 0xA7, 0x8A, 0x1A, 0xFC, 0xCA, 0x02, 0xFB },
-      116 /* Bin Number */
-  },
-  {
-    /* DigiCert_Assured_ID_Root_G2 */
-    { 0x7D, 0x05, 0xEB, 0xB6, 0x82, 0x33, 0x9F, 0x8C, 0x94, 0x51, 0xEE, 0x09, 0x4E, 0xEB, 0xFE, 0xFA,
-      0x79, 0x53, 0xA1, 0x14, 0xED, 0xB2, 0xF4, 0x49, 0x49, 0x45, 0x2F, 0xAB, 0x7D, 0x2F, 0xC1, 0x85 },
-      147 /* Bin Number */
-  },
-  {
-    /* America_Online_Root_Certification_Authority_2 */
-    { 0x7D, 0x3B, 0x46, 0x5A, 0x60, 0x14, 0xE5, 0x26, 0xC0, 0xAF, 0xFC, 0xEE, 0x21, 0x27, 0xD2, 0x31,
-      0x17, 0x27, 0xAD, 0x81, 0x1C, 0x26, 0x84, 0x2D, 0x00, 0x6A, 0xF3, 0x73, 0x06, 0xCC, 0x80, 0xBD },
-      25 /* Bin Number */
-  },
-  {
-    /* DigiCert_Assured_ID_Root_G3 */
-    { 0x7E, 0x37, 0xCB, 0x8B, 0x4C, 0x47, 0x09, 0x0C, 0xAB, 0x36, 0x55, 0x1B, 0xA6, 0xF4, 0x5D, 0xB8,
-      0x40, 0x68, 0x0F, 0xBA, 0x16, 0x6A, 0x95, 0x2D, 0xB1, 0x00, 0x71, 0x7F, 0x43, 0x05, 0x3F, 0xC2 },
-      148 /* Bin Number */
-  },
-  {
-    /* NetLock_Kozjegyzoi__Class_A__Tanusitvanykiado */
-    { 0x7F, 0x12, 0xCD, 0x5F, 0x7E, 0x5E, 0x29, 0x0E, 0xC7, 0xD8, 0x51, 0x79, 0xD5, 0xB7, 0x2C, 0x20,
-      0xA5, 0xBE, 0x75, 0x08, 0xFF, 0xDB, 0x5B, 0xF8, 0x1A, 0xB9, 0x68, 0x4A, 0x7F, 0xC9, 0xF6, 0x67 },
-      41 /* Bin Number */
-  },
-  {
-    /* AddTrust_Qualified_CA_Root */
-    { 0x80, 0x95, 0x21, 0x08, 0x05, 0xDB, 0x4B, 0xBC, 0x35, 0x5E, 0x44, 0x28, 0xD8, 0xFD, 0x6E, 0xC2,
-      0xCD, 0xE3, 0xAB, 0x5F, 0xB9, 0x7A, 0x99, 0x42, 0x98, 0x8E, 0xB8, 0xF4, 0xDC, 0xD0, 0x60, 0x16 },
-      17 /* Bin Number */
-  },
-  {
-    /* OU_VeriSign_Trust_Network_OU___c__1998_VeriSign__Inc____For_authorized_use_only__OU_Class_3_Public_Primary_Certification_Authority___G2_O__VeriSign__Inc___C_US */
-    { 0x83, 0xCE, 0x3C, 0x12, 0x29, 0x68, 0x8A, 0x59, 0x3D, 0x48, 0x5F, 0x81, 0x97, 0x3C, 0x0F, 0x91,
-      0x95, 0x43, 0x1E, 0xDA, 0x37, 0xCC, 0x5E, 0x36, 0x43, 0x0E, 0x79, 0xC7, 0xA8, 0x88, 0x63, 0x8B },
-      5 /* Bin Number */
-  },
-  {
-    /* OISTE_WISeKey_Global_Root_GC_CA */
-    { 0x85, 0x60, 0xF9, 0x1C, 0x36, 0x24, 0xDA, 0xBA, 0x95, 0x70, 0xB5, 0xFE, 0xA0, 0xDB, 0xE3, 0x6F,
-      0xF1, 0x1A, 0x83, 0x23, 0xBE, 0x94, 0x86, 0x85, 0x4F, 0xB3, 0xF3, 0x4A, 0x55, 0x71, 0x19, 0x8D },
-      198 /* Bin Number */
-  },
-  {
-    /* SSL_com_Root_Certification_Authority_RSA */
-    { 0x85, 0x66, 0x6A, 0x56, 0x2E, 0xE0, 0xBE, 0x5C, 0xE9, 0x25, 0xC1, 0xD8, 0x89, 0x0A, 0x6F, 0x76,
-      0xA8, 0x7E, 0xC1, 0x6D, 0x4D, 0x7D, 0x5F, 0x29, 0xEA, 0x74, 0x19, 0xCF, 0x20, 0x12, 0x3B, 0x69 },
-      193 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_CA_2 */
-    { 0x85, 0xA0, 0xDD, 0x7D, 0xD7, 0x20, 0xAD, 0xB7, 0xFF, 0x05, 0xF8, 0x3D, 0x54, 0x2B, 0x20, 0x9D,
-      0xC7, 0xFF, 0x45, 0x28, 0xF7, 0xD6, 0x77, 0xB1, 0x83, 0x89, 0xFE, 0xA5, 0xE5, 0xC4, 0x9E, 0x86 },
-      32 /* Bin Number */
-  },
-  {
-    /* UTN___DATACorp_SGC */
-    { 0x85, 0xFB, 0x2F, 0x91, 0xDD, 0x12, 0x27, 0x5A, 0x01, 0x45, 0xB6, 0x36, 0x53, 0x4F, 0x84, 0x02,
-      0x4A, 0xD6, 0x8B, 0x69, 0xB8, 0xEE, 0x88, 0x68, 0x4F, 0xF7, 0x11, 0x37, 0x58, 0x05, 0xB3, 0x48 },
-      37 /* Bin Number */
-  },
-  {
-    /* EC_ACC */
-    { 0x88, 0x49, 0x7F, 0x01, 0x60, 0x2F, 0x31, 0x54, 0x24, 0x6A, 0xE2, 0x8C, 0x4D, 0x5A, 0xEF, 0x10,
-      0xF1, 0xD8, 0x7E, 0xBB, 0x76, 0x62, 0x6F, 0x4A, 0xE0, 0xB7, 0xF9, 0x5B, 0xA7, 0x96, 0x87, 0x99 },
-      119 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_CA_3_G3 */
-    { 0x88, 0xEF, 0x81, 0xDE, 0x20, 0x2E, 0xB0, 0x18, 0x45, 0x2E, 0x43, 0xF8, 0x64, 0x72, 0x5C, 0xEA,
-      0x5F, 0xBD, 0x1F, 0xC2, 0xD9, 0xD2, 0x05, 0x73, 0x07, 0x09, 0xC5, 0xD8, 0xB8, 0x69, 0x0F, 0x46 },
-      146 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_CA_1_G3 */
-    { 0x8A, 0x86, 0x6F, 0xD1, 0xB2, 0x76, 0xB5, 0x7E, 0x57, 0x8E, 0x92, 0x1C, 0x65, 0x82, 0x8A, 0x2B,
-      0xED, 0x58, 0xE9, 0xF2, 0xF2, 0x88, 0x05, 0x41, 0x34, 0xB7, 0xF1, 0xF4, 0xBF, 0xC9, 0xCC, 0x74 },
-      144 /* Bin Number */
-  },
-  {
-    /* CA_WoSign_ECC_Root */
-    { 0x8B, 0x45, 0xDA, 0x1C, 0x06, 0xF7, 0x91, 0xEB, 0x0C, 0xAB, 0xF2, 0x6B, 0xE5, 0x88, 0xF5, 0xFB,
-      0x23, 0x16, 0x5C, 0x2E, 0x61, 0x4B, 0xF8, 0x85, 0x56, 0x2D, 0x0D, 0xCE, 0x50, 0xB2, 0x9B, 0x02 },
-      171 /* Bin Number */
-  },
-  {
-    /* Root_CA_Generalitat_Valenciana */
-    { 0x8C, 0x4E, 0xDF, 0xD0, 0x43, 0x48, 0xF3, 0x22, 0x96, 0x9E, 0x7E, 0x29, 0xA4, 0xCD, 0x4D, 0xCA,
-      0x00, 0x46, 0x55, 0x06, 0x1C, 0x16, 0xE1, 0xB0, 0x76, 0x42, 0x2E, 0xF3, 0x42, 0xAD, 0x63, 0x0E },
-      115 /* Bin Number */
-  },
-  {
-    /* AddTrust_Class_1_CA_Root */
-    { 0x8C, 0x72, 0x09, 0x27, 0x9A, 0xC0, 0x4E, 0x27, 0x5E, 0x16, 0xD0, 0x7F, 0xD3, 0xB7, 0x75, 0xE8,
-      0x01, 0x54, 0xB5, 0x96, 0x80, 0x46, 0xE3, 0x1F, 0x52, 0xDD, 0x25, 0x76, 0x63, 0x24, 0xE9, 0xA7 },
-      14 /* Bin Number */
-  },
-  {
-    /* thawte_Primary_Root_CA */
-    { 0x8D, 0x72, 0x2F, 0x81, 0xA9, 0xC1, 0x13, 0xC0, 0x79, 0x1D, 0xF1, 0x36, 0xA2, 0x96, 0x6D, 0xB2,
-      0x6C, 0x95, 0x0A, 0x97, 0x1D, 0xB4, 0x6B, 0x41, 0x99, 0xF4, 0xEA, 0x54, 0xB7, 0x8B, 0xFB, 0x9F },
-      59 /* Bin Number */
-  },
-  {
-    /* TC_TrustCenter_Class_3_CA_II */
-    { 0x8D, 0xA0, 0x84, 0xFC, 0xF9, 0x9C, 0xE0, 0x77, 0x22, 0xF8, 0x9B, 0x32, 0x05, 0x93, 0x98, 0x06,
-      0xFA, 0x5C, 0xB8, 0x11, 0xE1, 0xC8, 0x13, 0xF6, 0xA1, 0x08, 0xC7, 0xD3, 0x36, 0xB3, 0x40, 0x8E },
-      73 /* Bin Number */
-  },
-  {
-    /* T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s__H6 */
-    { 0x8D, 0xE7, 0x86, 0x55, 0xE1, 0xBE, 0x7F, 0x78, 0x47, 0x80, 0x0B, 0x93, 0xF6, 0x94, 0xD2, 0x1D,
-      0x36, 0x8C, 0xC0, 0x6E, 0x03, 0x3E, 0x7F, 0xAB, 0x04, 0xBB, 0x5E, 0xB9, 0x9D, 0xA6, 0xB7, 0x00 },
-      167 /* Bin Number */
-  },
-  {
-    /* Amazon_Root_CA_1 */
-    { 0x8E, 0xCD, 0xE6, 0x88, 0x4F, 0x3D, 0x87, 0xB1, 0x12, 0x5B, 0xA3, 0x1A, 0xC3, 0xFC, 0xB1, 0x3D,
-      0x70, 0x16, 0xDE, 0x7F, 0x57, 0xCC, 0x90, 0x4F, 0xE1, 0xCB, 0x97, 0xC6, 0xAE, 0x98, 0x19, 0x6E },
-      183 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_CA_2_G3 */
-    { 0x8F, 0xE4, 0xFB, 0x0A, 0xF9, 0x3A, 0x4D, 0x0D, 0x67, 0xDB, 0x0B, 0xEB, 0xB2, 0x3E, 0x37, 0xC7,
-      0x1B, 0xF3, 0x25, 0xDC, 0xBC, 0xDD, 0x24, 0x0E, 0xA0, 0x4D, 0xAF, 0x58, 0xB4, 0x7E, 0x18, 0x40 },
-      145 /* Bin Number */
-  },
-  {
-    /* T_TeleSec_GlobalRoot_Class_2 */
-    { 0x91, 0xE2, 0xF5, 0x78, 0x8D, 0x58, 0x10, 0xEB, 0xA7, 0xBA, 0x58, 0x73, 0x7D, 0xE1, 0x54, 0x8A,
-      0x8E, 0xCA, 0xCD, 0x01, 0x45, 0x98, 0xBC, 0x0B, 0x14, 0x3E, 0x04, 0x1B, 0x17, 0x05, 0x25, 0x52 },
-      142 /* Bin Number */
-  },
-  {
-    /* CA_Disig */
-    { 0x92, 0xBF, 0x51, 0x19, 0xAB, 0xEC, 0xCA, 0xD0, 0xB1, 0x33, 0x2D, 0xC4, 0xE1, 0xD0, 0x5F, 0xBA,
-      0x75, 0xB5, 0x67, 0x90, 0x44, 0xEE, 0x0C, 0xA2, 0x6E, 0x93, 0x1F, 0x74, 0x4F, 0x2F, 0x33, 0xCF },
-      94 /* Bin Number */
-  },
-  {
-    /* Cybertrust_Global_Root */
-    { 0x96, 0x0A, 0xDF, 0x00, 0x63, 0xE9, 0x63, 0x56, 0x75, 0x0C, 0x29, 0x65, 0xDD, 0x0A, 0x08, 0x67,
-      0xDA, 0x0B, 0x9C, 0xBD, 0x6E, 0x77, 0x71, 0x4A, 0xEA, 0xFB, 0x23, 0x49, 0xAB, 0x39, 0x3D, 0xA3 },
-      77 /* Bin Number */
-  },
-  {
-    /* ISRG_Root_X1 */
-    { 0x96, 0xBC, 0xEC, 0x06, 0x26, 0x49, 0x76, 0xF3, 0x74, 0x60, 0x77, 0x9A, 0xCF, 0x28, 0xC5, 0xA7,
-      0xCF, 0xE8, 0xA3, 0xC0, 0xAA, 0xE1, 0x1A, 0x8F, 0xFC, 0xEE, 0x05, 0xC0, 0xBD, 0xDF, 0x08, 0xC6 },
-      181 /* Bin Number */
-  },
-  {
-    /* T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_ */
-    { 0x97, 0x8C, 0xD9, 0x66, 0xF2, 0xFA, 0xA0, 0x7B, 0xA7, 0xAA, 0x95, 0x00, 0xD9, 0xC0, 0x2E, 0x9D,
-      0x77, 0xF2, 0xCD, 0xAD, 0xA6, 0xAD, 0x6B, 0xA7, 0x4A, 0xF4, 0xB9, 0x1C, 0x66, 0x59, 0x3C, 0x50 },
-      129 /* Bin Number */
-  },
-  {
-    /* Buypass_Class_2_Root_CA */
-    { 0x9A, 0x11, 0x40, 0x25, 0x19, 0x7C, 0x5B, 0xB9, 0x5D, 0x94, 0xE6, 0x3D, 0x55, 0xCD, 0x43, 0x79,
-      0x08, 0x47, 0xB6, 0x46, 0xB2, 0x3C, 0xDF, 0x11, 0xAD, 0xA4, 0xA0, 0x0E, 0xFF, 0x15, 0xFB, 0x48 },
-      125 /* Bin Number */
-  },
-  {
-    /* ACCVRAIZ1 */
-    { 0x9A, 0x6E, 0xC0, 0x12, 0xE1, 0xA7, 0xDA, 0x9D, 0xBE, 0x34, 0x19, 0x4D, 0x47, 0x8A, 0xD7, 0xC0,
-      0xDB, 0x18, 0x22, 0xFB, 0x07, 0x1D, 0xF1, 0x29, 0x81, 0x49, 0x6E, 0xD1, 0x04, 0x38, 0x41, 0x13 },
-      138 /* Bin Number */
-  },
-  {
-    /* VeriSign_Class_3_Public_Primary_Certification_Authority___G5 */
-    { 0x9A, 0xCF, 0xAB, 0x7E, 0x43, 0xC8, 0xD8, 0x80, 0xD0, 0x6B, 0x26, 0x2A, 0x94, 0xDE, 0xEE, 0xE4,
-      0xB4, 0x65, 0x99, 0x89, 0xC3, 0xD0, 0xCA, 0xF1, 0x9B, 0xAF, 0x64, 0x05, 0xE4, 0x1A, 0xB7, 0xDF },
-      60 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Universal_CA_2 */
-    { 0xA0, 0x23, 0x4F, 0x3B, 0xC8, 0x52, 0x7C, 0xA5, 0x62, 0x8E, 0xEC, 0x81, 0xAD, 0x5D, 0x69, 0x89,
-      0x5D, 0xA5, 0x68, 0x0D, 0xC9, 0x1D, 0x1C, 0xB8, 0x47, 0x7F, 0x33, 0xF8, 0x78, 0xB9, 0x5B, 0x0B },
-      23 /* Bin Number */
-  },
-  {
-    /* Hellenic_Academic_and_Research_Institutions_RootCA_2015 */
-    { 0xA0, 0x40, 0x92, 0x9A, 0x02, 0xCE, 0x53, 0xB4, 0xAC, 0xF4, 0xF2, 0xFF, 0xC6, 0x98, 0x1C, 0xE4,
-      0x49, 0x6F, 0x75, 0x5E, 0x6D, 0x45, 0xFE, 0x0B, 0x2A, 0x69, 0x2B, 0xCD, 0x52, 0x52, 0x3F, 0x36 },
-      174 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Universal_CA */
-    { 0xA0, 0x45, 0x9B, 0x9F, 0x63, 0xB2, 0x25, 0x59, 0xF5, 0xFA, 0x5D, 0x4C, 0x6D, 0xB3, 0xF9, 0xF7,
-      0x2F, 0xF1, 0x93, 0x42, 0x03, 0x35, 0x78, 0xF0, 0x73, 0xBF, 0x1D, 0x1B, 0x46, 0xCB, 0xB9, 0x12 },
-      22 /* Bin Number */
-  },
-  {
-    /* SZAFIR_ROOT_CA2 */
-    { 0xA1, 0x33, 0x9D, 0x33, 0x28, 0x1A, 0x0B, 0x56, 0xE5, 0x57, 0xD3, 0xD3, 0x2B, 0x1C, 0xE7, 0xF9,
-      0x36, 0x7E, 0xB0, 0x94, 0xBD, 0x5F, 0xA7, 0x2A, 0x7E, 0x50, 0x04, 0xC8, 0xDE, 0xD7, 0xCA, 0xFE },
-      172 /* Bin Number */
-  },
-  {
-    /* OU_Security_Communication_EV_RootCA1_O__SECOM_Trust_Systems_CO__LTD___C_JP */
-    { 0xA2, 0x2D, 0xBA, 0x68, 0x1E, 0x97, 0x37, 0x6E, 0x2D, 0x39, 0x7D, 0x72, 0x8A, 0xAE, 0x3A, 0x9B,
-      0x62, 0x96, 0xB9, 0xFD, 0xBA, 0x60, 0xBC, 0x2E, 0x11, 0xF6, 0x47, 0xF2, 0xC6, 0x75, 0xFB, 0x37 },
-      68 /* Bin Number */
-  },
-  {
-    /* thawte_Primary_Root_CA___G2 */
-    { 0xA4, 0x31, 0x0D, 0x50, 0xAF, 0x18, 0xA6, 0x44, 0x71, 0x90, 0x37, 0x2A, 0x86, 0xAF, 0xAF, 0x8B,
-      0x95, 0x1F, 0xFB, 0x43, 0x1D, 0x83, 0x7F, 0x1E, 0x56, 0x88, 0xB4, 0x59, 0x71, 0xED, 0x15, 0x57 },
-      87 /* Bin Number */
-  },
-  {
-    /* QuoVadis_Root_Certification_Authority */
-    { 0xA4, 0x5E, 0xDE, 0x3B, 0xBB, 0xF0, 0x9C, 0x8A, 0xE1, 0x5C, 0x72, 0xEF, 0xC0, 0x72, 0x68, 0xD6,
-      0x93, 0xA2, 0x1C, 0x99, 0x6F, 0xD5, 0x1E, 0x67, 0xCA, 0x07, 0x94, 0x60, 0xFD, 0x6D, 0x88, 0x73 },
-      31 /* Bin Number */
-  },
-  {
-    /* GTE_CyberTrust_Global_Root */
-    { 0xA5, 0x31, 0x25, 0x18, 0x8D, 0x21, 0x10, 0xAA, 0x96, 0x4B, 0x02, 0xC7, 0xB7, 0xC6, 0xDA, 0x32,
-      0x03, 0x17, 0x08, 0x94, 0xE5, 0xFB, 0x71, 0xFF, 0xFB, 0x66, 0x67, 0xD5, 0xE6, 0x81, 0x0A, 0x36 },
-      1 /* Bin Number */
-  },
-  {
-    /* WellsSecure_Public_Root_Certificate_Authority */
-    { 0xA7, 0x12, 0x72, 0xAE, 0xAA, 0xA3, 0xCF, 0xE8, 0x72, 0x7F, 0x7F, 0xB3, 0x9F, 0x0F, 0xB3, 0xD1,
-      0xE5, 0x42, 0x6E, 0x90, 0x60, 0xB0, 0x6E, 0xE6, 0xF1, 0x3E, 0x9A, 0x3C, 0x58, 0x33, 0xCD, 0x43 },
-      65 /* Bin Number */
-  },
-  {
-    /* Thawte_Premium_Server_CA */
-    { 0xAB, 0x70, 0x36, 0x36, 0x5C, 0x71, 0x54, 0xAA, 0x29, 0xC2, 0xC2, 0x9F, 0x5D, 0x41, 0x91, 0x16,
-      0x3B, 0x16, 0x2A, 0x22, 0x25, 0x01, 0x13, 0x57, 0xD5, 0x6D, 0x07, 0xFF, 0xA7, 0xBC, 0x1F, 0x72 },
-      3 /* Bin Number */
-  },
-  {
-    /* OU_RSA_Security_2048_V3_O_RSA_Security_Inc */
-    { 0xAF, 0x8B, 0x67, 0x62, 0xA1, 0xE5, 0x28, 0x22, 0x81, 0x61, 0xA9, 0x5D, 0x5C, 0x55, 0x9E, 0xE2,
-      0x66, 0x27, 0x8F, 0x75, 0xD7, 0x9E, 0x83, 0x01, 0x89, 0xA5, 0x03, 0x50, 0x6A, 0xBD, 0x6B, 0x4C },
-      19 /* Bin Number */
-  },
-  {
-    /* E_Tugra_Certification_Authority */
-    { 0xB0, 0xBF, 0xD5, 0x2B, 0xB0, 0xD7, 0xD9, 0xBD, 0x92, 0xBF, 0x5D, 0x4D, 0xC1, 0x3D, 0xA2, 0x55,
-      0xC0, 0x2C, 0x54, 0x2F, 0x37, 0x83, 0x65, 0xEA, 0x89, 0x39, 0x11, 0xF5, 0x5E, 0x55, 0xF2, 0x3C },
-      141 /* Bin Number */
-  },
-  {
-    /* Thawte_Server_CA */
-    { 0xB4, 0x41, 0x0B, 0x73, 0xE2, 0xE6, 0xEA, 0xCA, 0x47, 0xFB, 0xC4, 0x2F, 0x8F, 0xA4, 0x01, 0x8A,
-      0xF4, 0x38, 0x1D, 0xC5, 0x4C, 0xFA, 0xA8, 0x44, 0x50, 0x46, 0x1E, 0xED, 0x09, 0x45, 0x4D, 0xE9 },
-      2 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Primary_Certification_Authority___G3 */
-    { 0xB4, 0x78, 0xB8, 0x12, 0x25, 0x0D, 0xF8, 0x78, 0x63, 0x5C, 0x2A, 0xA7, 0xEC, 0x7D, 0x15, 0x5E,
-      0xAA, 0x62, 0x5E, 0xE8, 0x29, 0x16, 0xE2, 0xCD, 0x29, 0x43, 0x61, 0x88, 0x6C, 0xD1, 0xFB, 0xD4 },
-      86 /* Bin Number */
-  },
-  {
-    /* Deutsche_Telekom_Root_CA_2 */
-    { 0xB6, 0x19, 0x1A, 0x50, 0xD0, 0xC3, 0x97, 0x7F, 0x7D, 0xA9, 0x9B, 0xCD, 0xAA, 0xC8, 0x6A, 0x22,
-      0x7D, 0xAE, 0xB9, 0x67, 0x9E, 0xC7, 0x0B, 0xA3, 0xB0, 0xC9, 0xD9, 0x22, 0x71, 0xC1, 0x70, 0xD3 },
-      75 /* Bin Number */
-  },
-  {
-    /* Certum_Trusted_Network_CA_2 */
-    { 0xB6, 0x76, 0xF2, 0xED, 0xDA, 0xE8, 0x77, 0x5C, 0xD3, 0x6C, 0xB0, 0xF6, 0x3C, 0xD1, 0xD4, 0x60,
-      0x39, 0x61, 0xF4, 0x9E, 0x62, 0x65, 0xBA, 0x01, 0x3A, 0x2F, 0x03, 0x07, 0xB6, 0xD0, 0xB8, 0x04 },
-      173 /* Bin Number */
-  },
-  {
-    /* Buypass_Class_3_CA_1 */
-    { 0xB7, 0xB1, 0x2B, 0x17, 0x1F, 0x82, 0x1D, 0xAA, 0x99, 0x0C, 0xD0, 0xFE, 0x50, 0x87, 0xB1, 0x28,
-      0x44, 0x8B, 0xA8, 0xE5, 0x18, 0x4F, 0x84, 0xC5, 0x1E, 0x02, 0xB5, 0xC8, 0xFB, 0x96, 0x2B, 0x24 },
-      81 /* Bin Number */
-  },
-  {
-    /* OpenTrust_Root_CA_G3 */
-    { 0xB7, 0xC3, 0x62, 0x31, 0x70, 0x6E, 0x81, 0x07, 0x8C, 0x36, 0x7C, 0xB8, 0x96, 0x19, 0x8F, 0x1E,
-      0x32, 0x08, 0xDD, 0x92, 0x69, 0x49, 0xDD, 0x8F, 0x57, 0x09, 0xA4, 0x10, 0xF7, 0x5B, 0x62, 0x92 },
-      180 /* Bin Number */
-  },
-  {
-    /* IGC_A */
-    { 0xB9, 0xBE, 0xA7, 0x86, 0x0A, 0x96, 0x2E, 0xA3, 0x61, 0x1D, 0xAB, 0x97, 0xAB, 0x6D, 0xA3, 0xE2,
-      0x1C, 0x10, 0x68, 0xB9, 0x7D, 0x55, 0x57, 0x5E, 0xD0, 0xE1, 0x12, 0x79, 0xC1, 0x1C, 0x89, 0x32 },
-      67 /* Bin Number */
-  },
-  {
-    /* Hellenic_Academic_and_Research_Institutions_RootCA_2011 */
-    { 0xBC, 0x10, 0x4F, 0x15, 0xA4, 0x8B, 0xE7, 0x09, 0xDC, 0xA5, 0x42, 0xA7, 0xE1, 0xD4, 0xB9, 0xDF,
-      0x6F, 0x05, 0x45, 0x27, 0xE8, 0x02, 0xEA, 0xA9, 0x2D, 0x59, 0x54, 0x44, 0x25, 0x8A, 0xFE, 0x71 },
-      120 /* Bin Number */
-  },
-  {
-    /* AffirmTrust_Premium_ECC */
-    { 0xBD, 0x71, 0xFD, 0xF6, 0xDA, 0x97, 0xE4, 0xCF, 0x62, 0xD1, 0x64, 0x7A, 0xDD, 0x25, 0x81, 0xB0,
-      0x7D, 0x79, 0xAD, 0xF8, 0x39, 0x7E, 0xB4, 0xEC, 0xBA, 0x9C, 0x5E, 0x84, 0x88, 0x82, 0x14, 0x23 },
-      112 /* Bin Number */
-  },
-  {
-    /* Secure_Certificate_Services */
-    { 0xBD, 0x81, 0xCE, 0x3B, 0x4F, 0x65, 0x91, 0xD1, 0x1A, 0x67, 0xB5, 0xFC, 0x7A, 0x47, 0xFD, 0xEF,
-      0x25, 0x52, 0x1B, 0xF9, 0xAA, 0x4E, 0x18, 0xB9, 0xE3, 0xDF, 0x2E, 0x34, 0xA7, 0x80, 0x3B, 0xE8 },
-      29 /* Bin Number */
-  },
-  {
-    /* SwissSign_Silver_CA___G2 */
-    { 0xBE, 0x6C, 0x4D, 0xA2, 0xBB, 0xB9, 0xBA, 0x59, 0xB6, 0xF3, 0x93, 0x97, 0x68, 0x37, 0x42, 0x46,
-      0xC3, 0xC0, 0x05, 0x99, 0x3F, 0xA9, 0x8F, 0x02, 0x0D, 0x1D, 0xED, 0xBE, 0xD4, 0x8A, 0x81, 0xD5 },
-      57 /* Bin Number */
-  },
-  {
-    /* GlobalSign */
-    { 0xBE, 0xC9, 0x49, 0x11, 0xC2, 0x95, 0x56, 0x76, 0xDB, 0x6C, 0x0A, 0x55, 0x09, 0x86, 0xD7, 0x6E,
-      0x3B, 0xA0, 0x05, 0x66, 0x7C, 0x44, 0x2C, 0x97, 0x62, 0xB4, 0xFB, 0xB7, 0x73, 0xDE, 0x22, 0x8C },
-      157 /* Bin Number */
-  },
-  {
-    /* SecureSign_RootCA11 */
-    { 0xBF, 0x0F, 0xEE, 0xFB, 0x9E, 0x3A, 0x58, 0x1A, 0xD5, 0xF9, 0xE9, 0xDB, 0x75, 0x89, 0x98, 0x57,
-      0x43, 0xD2, 0x61, 0x08, 0x5C, 0x4D, 0x31, 0x4F, 0x6F, 0x5D, 0x72, 0x59, 0xAA, 0x42, 0x16, 0x12 },
-      97 /* Bin Number */
-  },
-  {
-    /* TWCA_Root_Certification_Authority */
-    { 0xBF, 0xD8, 0x8F, 0xE1, 0x10, 0x1C, 0x41, 0xAE, 0x3E, 0x80, 0x1B, 0xF8, 0xBE, 0x56, 0x35, 0x0E,
-      0xE9, 0xBA, 0xD1, 0xA6, 0xB9, 0xBD, 0x51, 0x5E, 0xDC, 0x5C, 0x6D, 0x5B, 0x87, 0x11, 0xAC, 0x44 },
-      117 /* Bin Number */
-  },
-  {
-    /* GDCA_TrustAUTH_R5_ROOT */
-    { 0xBF, 0xFF, 0x8F, 0xD0, 0x44, 0x33, 0x48, 0x7D, 0x6A, 0x8A, 0xA6, 0x0C, 0x1A, 0x29, 0x76, 0x7A,
-      0x9F, 0xC2, 0xBB, 0xB0, 0x5E, 0x42, 0x0F, 0x71, 0x3A, 0x13, 0xB9, 0x92, 0x89, 0x1D, 0x38, 0x93 },
-      189 /* Bin Number */
-  },
-  {
-    /* OU_ePKI_Root_Certification_Authority_O__Chunghwa_Telecom_Co___Ltd___C_TW */
-    { 0xC0, 0xA6, 0xF4, 0xDC, 0x63, 0xA2, 0x4B, 0xFD, 0xCF, 0x54, 0xEF, 0x2A, 0x6A, 0x08, 0x2A, 0x0A,
-      0x72, 0xDE, 0x35, 0x80, 0x3E, 0x2F, 0xF5, 0xFF, 0x52, 0x7A, 0xE5, 0xD8, 0x72, 0x06, 0xDF, 0xD5 },
-      78 /* Bin Number */
-  },
-  {
-    /* OU_Trustis_FPS_Root_CA_O_Trustis_Limited_C_GB */
-    { 0xC1, 0xB4, 0x82, 0x99, 0xAB, 0xA5, 0x20, 0x8F, 0xE9, 0x63, 0x0A, 0xCE, 0x55, 0xCA, 0x68, 0xA0,
-      0x3E, 0xDA, 0x5A, 0x51, 0x9C, 0x88, 0x02, 0xA0, 0xD3, 0xA6, 0x73, 0xBE, 0x8F, 0x8E, 0x55, 0x7D },
-      122 /* Bin Number */
-  },
-  {
-    /* OU_Go_Daddy_Class_2_Certification_Authority_O__The_Go_Daddy_Group__Inc___C_US */
-    { 0xC3, 0x84, 0x6B, 0xF2, 0x4B, 0x9E, 0x93, 0xCA, 0x64, 0x27, 0x4C, 0x0E, 0xC6, 0x7C, 0x1E, 0xCC,
-      0x5E, 0x02, 0x4F, 0xFC, 0xAC, 0xD2, 0xD7, 0x40, 0x19, 0x35, 0x0E, 0x81, 0xFE, 0x54, 0x6A, 0xE4 },
-      43 /* Bin Number */
-  },
-  {
-    /* T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_ */
-    { 0xC4, 0x70, 0xCF, 0x54, 0x7E, 0x23, 0x02, 0xB9, 0x77, 0xFB, 0x29, 0xDD, 0x71, 0xA8, 0x9A, 0x7B,
-      0x6C, 0x1F, 0x60, 0x77, 0x7B, 0x03, 0x29, 0xF5, 0x60, 0x17, 0xF3, 0x28, 0xBF, 0x4F, 0x6B, 0xE6 },
-      55 /* Bin Number */
-  },
-  {
-    /* StartCom_Certification_Authority */
-    { 0xC7, 0x66, 0xA9, 0xBE, 0xF2, 0xD4, 0x07, 0x1C, 0x86, 0x3A, 0x31, 0xAA, 0x49, 0x20, 0xE8, 0x13,
-      0xB2, 0xD1, 0x98, 0x60, 0x8C, 0xB7, 0xB7, 0xCF, 0xE2, 0x11, 0x43, 0xB8, 0x36, 0xDF, 0x09, 0xEA },
-      45 /* Bin Number */
-  },
-  {
-    /* StartCom_Certification_Authority_G2 */
-    { 0xC7, 0xBA, 0x65, 0x67, 0xDE, 0x93, 0xA7, 0x98, 0xAE, 0x1F, 0xAA, 0x79, 0x1E, 0x71, 0x2D, 0x37,
-      0x8F, 0xAE, 0x1F, 0x93, 0xC4, 0x39, 0x7F, 0xEA, 0x44, 0x1B, 0xB7, 0xCB, 0xE6, 0xFD, 0x59, 0x95 },
-      124 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Global_CA_2 */
-    { 0xCA, 0x2D, 0x82, 0xA0, 0x86, 0x77, 0x07, 0x2F, 0x8A, 0xB6, 0x76, 0x4F, 0xF0, 0x35, 0x67, 0x6C,
-      0xFE, 0x3E, 0x5E, 0x32, 0x5E, 0x01, 0x21, 0x72, 0xDF, 0x3F, 0x92, 0x09, 0x6D, 0xB7, 0x9B, 0x85 },
-      21 /* Bin Number */
-  },
-  {
-    /* GlobalSign */
-    { 0xCA, 0x42, 0xDD, 0x41, 0x74, 0x5F, 0xD0, 0xB8, 0x1E, 0xB9, 0x02, 0x36, 0x2C, 0xF9, 0xD8, 0xBF,
-      0x71, 0x9D, 0xA1, 0xBD, 0x1B, 0x1E, 0xFC, 0x94, 0x6F, 0x5B, 0x4C, 0x99, 0xF4, 0x2C, 0x1B, 0x9E },
-      7 /* Bin Number */
-  },
-  {
-    /* DigiCert_Global_Root_G2 */
-    { 0xCB, 0x3C, 0xCB, 0xB7, 0x60, 0x31, 0xE5, 0xE0, 0x13, 0x8F, 0x8D, 0xD3, 0x9A, 0x23, 0xF9, 0xDE,
-      0x47, 0xFF, 0xC3, 0x5E, 0x43, 0xC1, 0x14, 0x4C, 0xEA, 0x27, 0xD4, 0x6A, 0x5A, 0xB1, 0xCB, 0x5F },
-      149 /* Bin Number */
-  },
-  {
-    /* GlobalSign */
-    { 0xCB, 0xB5, 0x22, 0xD7, 0xB7, 0xF1, 0x27, 0xAD, 0x6A, 0x01, 0x13, 0x86, 0x5B, 0xDF, 0x1C, 0xD4,
-      0x10, 0x2E, 0x7D, 0x07, 0x59, 0xAF, 0x63, 0x5A, 0x7C, 0xF4, 0x72, 0x0D, 0xC9, 0x63, 0xC5, 0x3B },
-      101 /* Bin Number */
-  },
-  {
-    /* XRamp_Global_Certification_Authority */
-    { 0xCE, 0xCD, 0xDC, 0x90, 0x50, 0x99, 0xD8, 0xDA, 0xDF, 0xC5, 0xB1, 0xD2, 0x09, 0xB7, 0x37, 0xCB,
-      0xE2, 0xC1, 0x8C, 0xFB, 0x2C, 0x10, 0xC0, 0xFF, 0x0B, 0xCF, 0x0D, 0x32, 0x86, 0xFC, 0x1A, 0xA2 },
-      42 /* Bin Number */
-  },
-  {
-    /* Equifax_Secure_eBusiness_CA_1 */
-    { 0xCF, 0x56, 0xFF, 0x46, 0xA4, 0xA1, 0x86, 0x10, 0x9D, 0xD9, 0x65, 0x84, 0xB5, 0xEE, 0xB5, 0x8A,
-      0x51, 0x0C, 0x42, 0x75, 0xB0, 0xE5, 0xF9, 0x4F, 0x40, 0xBB, 0xAE, 0x86, 0x5E, 0x19, 0xF6, 0x73 },
-      13 /* Bin Number */
-  },
-  {
-    /* TrustCor_RootCert_CA_1 */
-    { 0xD4, 0x0E, 0x9C, 0x86, 0xCD, 0x8F, 0xE4, 0x68, 0xC1, 0x77, 0x69, 0x59, 0xF4, 0x9E, 0xA7, 0x74,
-      0xFA, 0x54, 0x86, 0x84, 0xB6, 0xC4, 0x06, 0xF3, 0x90, 0x92, 0x61, 0xF4, 0xDC, 0xE2, 0x57, 0x5C },
-      190 /* Bin Number */
-  },
-  {
-    /* Staat_der_Nederlanden_Root_CA */
-    { 0xD4, 0x1D, 0x82, 0x9E, 0x8C, 0x16, 0x59, 0x82, 0x2A, 0xF9, 0x3F, 0xCE, 0x62, 0xBF, 0xFC, 0xDE,
-      0x26, 0x4F, 0xC8, 0x4E, 0x8B, 0x95, 0x0C, 0x5F, 0xF2, 0x75, 0xD0, 0x52, 0x35, 0x46, 0x95, 0xA3 },
-      36 /* Bin Number */
-  },
-  {
-    /* Certification_Authority_of_WoSign_G2 */
-    { 0xD4, 0x87, 0xA5, 0x6F, 0x83, 0xB0, 0x74, 0x82, 0xE8, 0x5E, 0x96, 0x33, 0x94, 0xC1, 0xEC, 0xC2,
-      0xC9, 0xE5, 0x1D, 0x09, 0x03, 0xEE, 0x94, 0x6B, 0x02, 0xC3, 0x01, 0x58, 0x1E, 0xD9, 0x9E, 0x16 },
-      170 /* Bin Number */
-  },
-  {
-    /* CA______ */
-    { 0xD6, 0xF0, 0x34, 0xBD, 0x94, 0xAA, 0x23, 0x3F, 0x02, 0x97, 0xEC, 0xA4, 0x24, 0x5B, 0x28, 0x39,
-      0x73, 0xE4, 0x47, 0xAA, 0x59, 0x0F, 0x31, 0x0C, 0x77, 0xF4, 0x8F, 0xDF, 0x83, 0x11, 0x22, 0x54 },
-      153 /* Bin Number */
-  },
-  {
-    /* AAA_Certificate_Services */
-    { 0xD7, 0xA7, 0xA0, 0xFB, 0x5D, 0x7E, 0x27, 0x31, 0xD7, 0x71, 0xE9, 0x48, 0x4E, 0xBC, 0xDE, 0xF7,
-      0x1D, 0x5F, 0x0C, 0x3E, 0x0A, 0x29, 0x48, 0x78, 0x2B, 0xC8, 0x3E, 0xE0, 0xEA, 0x69, 0x9E, 0xF4 },
-      28 /* Bin Number */
-  },
-  {
-    /* Certum_CA */
-    { 0xD8, 0xE0, 0xFE, 0xBC, 0x1D, 0xB2, 0xE3, 0x8D, 0x00, 0x94, 0x0F, 0x37, 0xD2, 0x7D, 0x41, 0x34,
-      0x4D, 0x99, 0x3E, 0x73, 0x4B, 0x99, 0xD5, 0x65, 0x6D, 0x97, 0x78, 0xD4, 0xD8, 0x14, 0x36, 0x24 },
-      27 /* Bin Number */
-  },
-  {
-    /* Swisscom_Root_EV_CA_2 */
-    { 0xD9, 0x5F, 0xEA, 0x3C, 0xA4, 0xEE, 0xDC, 0xE7, 0x4C, 0xD7, 0x6E, 0x75, 0xFC, 0x6D, 0x1F, 0xF6,
-      0x2C, 0x44, 0x1F, 0x0F, 0xA8, 0xBC, 0x77, 0xF0, 0x34, 0xB1, 0x9E, 0x5D, 0xB2, 0x58, 0x01, 0x5D },
-      135 /* Bin Number */
-  },
-  {
-    /* TeliaSonera_Root_CA_v1 */
-    { 0xDD, 0x69, 0x36, 0xFE, 0x21, 0xF8, 0xF0, 0x77, 0xC1, 0x23, 0xA1, 0xA5, 0x21, 0xC1, 0x22, 0x24,
-      0xF7, 0x22, 0x55, 0xB7, 0x3E, 0x03, 0xA7, 0x26, 0x06, 0x93, 0xE8, 0xA2, 0x4B, 0x0F, 0xA3, 0x89 },
-      140 /* Bin Number */
-  },
-  {
-    /* StartCom_Certification_Authority */
-    { 0xE1, 0x78, 0x90, 0xEE, 0x09, 0xA3, 0xFB, 0xF4, 0xF4, 0x8B, 0x9C, 0x41, 0x4A, 0x17, 0xD6, 0x37,
-      0xB7, 0xA5, 0x06, 0x47, 0xE9, 0xBC, 0x75, 0x23, 0x22, 0x72, 0x7F, 0xCC, 0x17, 0x42, 0xA9, 0x11 },
-      123 /* Bin Number */
-  },
-  {
-    /* CA_Disig_Root_R2 */
-    { 0xE2, 0x3D, 0x4A, 0x03, 0x6D, 0x7B, 0x70, 0xE9, 0xF5, 0x95, 0xB1, 0x42, 0x20, 0x79, 0xD2, 0xB9,
-      0x1E, 0xDF, 0xBB, 0x1F, 0xB6, 0x51, 0xA0, 0x63, 0x3E, 0xAA, 0x8A, 0x9D, 0xC5, 0xF8, 0x07, 0x03 },
-      137 /* Bin Number */
-  },
-  {
-    /* CNNIC_ROOT */
-    { 0xE2, 0x83, 0x93, 0x77, 0x3D, 0xA8, 0x45, 0xA6, 0x79, 0xF2, 0x08, 0x0C, 0xC7, 0xFB, 0x44, 0xA3,
-      0xB7, 0xA1, 0xC3, 0x79, 0x2C, 0xB7, 0xEB, 0x77, 0x29, 0xFD, 0xCB, 0x6A, 0x8D, 0x99, 0xAE, 0xA7 },
-      84 /* Bin Number */
-  },
-  {
-    /* Amazon_Root_CA_4 */
-    { 0xE3, 0x5D, 0x28, 0x41, 0x9E, 0xD0, 0x20, 0x25, 0xCF, 0xA6, 0x90, 0x38, 0xCD, 0x62, 0x39, 0x62,
-      0x45, 0x8D, 0xA5, 0xC6, 0x95, 0xFB, 0xDE, 0xA3, 0xC2, 0x2B, 0x0B, 0xFB, 0x25, 0x89, 0x70, 0x92 },
-      186 /* Bin Number */
-  },
-  {
-    /* VeriSign_Class_4_Public_Primary_Certification_Authority___G3 */
-    { 0xE3, 0x89, 0x36, 0x0D, 0x0F, 0xDB, 0xAE, 0xB3, 0xD2, 0x50, 0x58, 0x4B, 0x47, 0x30, 0x31, 0x4E,
-      0x22, 0x2F, 0x39, 0xC1, 0x56, 0xA0, 0x20, 0x14, 0x4E, 0x8D, 0x96, 0x05, 0x61, 0x79, 0x15, 0x06 },
-      9 /* Bin Number */
-  },
-  {
-    /* Certigna */
-    { 0xE3, 0xB6, 0xA2, 0xDB, 0x2E, 0xD7, 0xCE, 0x48, 0x84, 0x2F, 0x7A, 0xC5, 0x32, 0x41, 0xC7, 0xB7,
-      0x1D, 0x54, 0x14, 0x4B, 0xFB, 0x40, 0xC1, 0x1F, 0x3F, 0x1D, 0x0B, 0x42, 0xF5, 0xEE, 0xA1, 0x2D },
-      71 /* Bin Number */
-  },
-  {
-    /* T_B_TAK_UEKAE_K_k_Sertifika_Hizmet_Sa_lay_c_s____S_r_m_3 */
-    { 0xE4, 0xC7, 0x34, 0x30, 0xD7, 0xA5, 0xB5, 0x09, 0x25, 0xDF, 0x43, 0x37, 0x0A, 0x0D, 0x21, 0x6E,
-      0x9A, 0x79, 0xB9, 0xD6, 0xDB, 0x83, 0x73, 0xA0, 0xC6, 0x9E, 0xB1, 0xCC, 0x31, 0xC7, 0xC5, 0x2A },
-      79 /* Bin Number */
-  },
-  {
-    /* e_Guven_Kok_Elektronik_Sertifika_Hizmet_Saglayicisi */
-    { 0xE6, 0x09, 0x07, 0x84, 0x65, 0xA4, 0x19, 0x78, 0x0C, 0xB6, 0xAC, 0x4C, 0x1C, 0x0B, 0xFB, 0x46,
-      0x53, 0xD9, 0xD9, 0xCC, 0x6E, 0xB3, 0x94, 0x6E, 0xB7, 0xF3, 0xD6, 0x99, 0x97, 0xBA, 0xD5, 0x98 },
-      100 /* Bin Number */
-  },
-  {
-    /* TC_TrustCenter_Class_2_CA_II */
-    { 0xE6, 0xB8, 0xF8, 0x76, 0x64, 0x85, 0xF8, 0x07, 0xAE, 0x7F, 0x8D, 0xAC, 0x16, 0x70, 0x46, 0x1F,
-      0x07, 0xC0, 0xA1, 0x3E, 0xEF, 0x3A, 0x1F, 0xF7, 0x17, 0x53, 0x8D, 0x7A, 0xBA, 0xD3, 0x91, 0xB4 },
-      72 /* Bin Number */
-  },
-  {
-    /* OU_Security_Communication_RootCA1_O_SECOM_Trust_net_C_JP */
-    { 0xE7, 0x5E, 0x72, 0xED, 0x9F, 0x56, 0x0E, 0xEC, 0x6E, 0xB4, 0x80, 0x00, 0x73, 0xA4, 0x3F, 0xC3,
-      0xAD, 0x19, 0x19, 0x5A, 0x39, 0x22, 0x82, 0x01, 0x78, 0x95, 0x97, 0x4A, 0x99, 0x02, 0x6B, 0x6C },
-      34 /* Bin Number */
-  },
-  {
-    /* USERTrust_RSA_Certification_Authority */
-    { 0xE7, 0x93, 0xC9, 0xB0, 0x2F, 0xD8, 0xAA, 0x13, 0xE2, 0x1C, 0x31, 0x22, 0x8A, 0xCC, 0xB0, 0x81,
-      0x19, 0x64, 0x3B, 0x74, 0x9C, 0x89, 0x89, 0x64, 0xB1, 0x74, 0x6D, 0x46, 0xC3, 0xD4, 0xCB, 0xD2 },
-      155 /* Bin Number */
-  },
-  {
-    /* OU_certSIGN_ROOT_CA_O_certSIGN_C_RO */
-    { 0xEA, 0xA9, 0x62, 0xC4, 0xFA, 0x4A, 0x6B, 0xAF, 0xEB, 0xE4, 0x15, 0x19, 0x6D, 0x35, 0x1C, 0xCD,
-      0x88, 0x8D, 0x4F, 0x53, 0xF3, 0xFA, 0x8A, 0xE6, 0xD7, 0xC4, 0x66, 0xA9, 0x4E, 0x60, 0x42, 0xBB },
-      83 /* Bin Number */
-  },
-  {
-    /* VeriSign_Class_3_Public_Primary_Certification_Authority___G3 */
-    { 0xEB, 0x04, 0xCF, 0x5E, 0xB1, 0xF3, 0x9A, 0xFA, 0x76, 0x2F, 0x2B, 0xB1, 0x20, 0xF2, 0x96, 0xCB,
-      0xA5, 0x20, 0xC1, 0xB9, 0x7D, 0xB1, 0x58, 0x95, 0x65, 0xB8, 0x1C, 0xB9, 0xA1, 0x7B, 0x72, 0x44 },
-      8 /* Bin Number */
-  },
-  {
-    /* OU_AC_RAIZ_FNMT_RCM_O_FNMT_RCM_C_ES */
-    { 0xEB, 0xC5, 0x57, 0x0C, 0x29, 0x01, 0x8C, 0x4D, 0x67, 0xB1, 0xAA, 0x12, 0x7B, 0xAF, 0x12, 0xF7,
-      0x03, 0xB4, 0x61, 0x1E, 0xBC, 0x17, 0xB7, 0xDA, 0xB5, 0x57, 0x38, 0x94, 0x17, 0x9B, 0x93, 0xFA },
-      182 /* Bin Number */
-  },
-  {
-    /* GlobalSign_Root_CA */
-    { 0xEB, 0xD4, 0x10, 0x40, 0xE4, 0xBB, 0x3E, 0xC7, 0x42, 0xC9, 0xE3, 0x81, 0xD3, 0x1E, 0xF2, 0xA4,
-      0x1A, 0x48, 0xB6, 0x68, 0x5C, 0x96, 0xE7, 0xCE, 0xF3, 0xC1, 0xDF, 0x6C, 0xD4, 0x33, 0x1C, 0x99 },
-      6 /* Bin Number */
-  },
-  {
-    /* TC_TrustCenter_Universal_CA_I */
-    { 0xEB, 0xF3, 0xC0, 0x2A, 0x87, 0x89, 0xB1, 0xFB, 0x7D, 0x51, 0x19, 0x95, 0xD6, 0x63, 0xB7, 0x29,
-      0x06, 0xD9, 0x13, 0xCE, 0x0D, 0x5E, 0x10, 0x56, 0x8A, 0x8A, 0x77, 0xE2, 0x58, 0x61, 0x67, 0xE7 },
-      74 /* Bin Number */
-  },
-  {
-    /* Juur_SK */
-    { 0xEC, 0xC3, 0xE9, 0xC3, 0x40, 0x75, 0x03, 0xBE, 0xE0, 0x91, 0xAA, 0x95, 0x2F, 0x41, 0x34, 0x8F,
-      0xF8, 0x8B, 0xAA, 0x86, 0x3B, 0x22, 0x64, 0xBE, 0xFA, 0xC8, 0x07, 0x90, 0x15, 0x74, 0xE9, 0x39 },
-      95 /* Bin Number */
-  },
-  {
-    /* Buypass_Class_3_Root_CA */
-    { 0xED, 0xF7, 0xEB, 0xBC, 0xA2, 0x7A, 0x2A, 0x38, 0x4D, 0x38, 0x7B, 0x7D, 0x40, 0x10, 0xC6, 0x66,
-      0xE2, 0xED, 0xB4, 0x84, 0x3E, 0x4C, 0x29, 0xB4, 0xAE, 0x1D, 0x5B, 0x93, 0x32, 0xE6, 0xB2, 0x4D },
-      126 /* Bin Number */
-  },
-  {
-    /* D_TRUST_Root_Class_3_CA_2_EV_2009 */
-    { 0xEE, 0xC5, 0x49, 0x6B, 0x98, 0x8C, 0xE9, 0x86, 0x25, 0xB9, 0x34, 0x09, 0x2E, 0xEC, 0x29, 0x08,
-      0xBE, 0xD0, 0xB0, 0xF3, 0x16, 0xC2, 0xD4, 0x73, 0x0C, 0x84, 0xEA, 0xF1, 0xF3, 0xD3, 0x48, 0x81 },
-      131 /* Bin Number */
-  },
-  {
-    /* Global_Chambersign_Root */
-    { 0xEF, 0x3C, 0xB4, 0x17, 0xFC, 0x8E, 0xBF, 0x6F, 0x97, 0x87, 0x6C, 0x9E, 0x4E, 0xCE, 0x39, 0xDE,
-      0x1E, 0xA5, 0xFE, 0x64, 0x91, 0x41, 0xD1, 0x02, 0x8B, 0x7D, 0x11, 0xC0, 0xB2, 0x29, 0x8C, 0xED },
-      40 /* Bin Number */
-  },
-  {
-    /* Swisscom_Root_CA_2 */
-    { 0xF0, 0x9B, 0x12, 0x2C, 0x71, 0x14, 0xF4, 0xA0, 0x9B, 0xD4, 0xEA, 0x4F, 0x4A, 0x99, 0xD5, 0x58,
-      0xB4, 0x6E, 0x4C, 0x25, 0xCD, 0x81, 0x14, 0x0D, 0x29, 0xC0, 0x56, 0x13, 0x91, 0x4C, 0x38, 0x41 },
-      134 /* Bin Number */
-  },
-  {
-    /* SecureTrust_CA */
-    { 0xF1, 0xC1, 0xB5, 0x0A, 0xE5, 0xA2, 0x0D, 0xD8, 0x03, 0x0E, 0xC9, 0xF6, 0xBC, 0x24, 0x82, 0x3D,
-      0xD3, 0x67, 0xB5, 0x25, 0x57, 0x59, 0xB4, 0xE7, 0x1B, 0x61, 0xFC, 0xE9, 0xF7, 0x37, 0x5D, 0x73 },
-      61 /* Bin Number */
-  },
-  {
-    /* Atos_TrustedRoot_2011 */
-    { 0xF3, 0x56, 0xBE, 0xA2, 0x44, 0xB7, 0xA9, 0x1E, 0xB3, 0x5D, 0x53, 0xCA, 0x9A, 0xD7, 0x86, 0x4A,
-      0xCE, 0x01, 0x8E, 0x2D, 0x35, 0xD5, 0xF8, 0xF9, 0x6D, 0xDF, 0x68, 0xA6, 0xF4, 0x1A, 0xA4, 0x74 },
-      143 /* Bin Number */
-  },
-  {
-    /* CA_Disig_Root_R1 */
-    { 0xF9, 0x6F, 0x23, 0xF4, 0xC3, 0xE7, 0x9C, 0x07, 0x7A, 0x46, 0x98, 0x8D, 0x5A, 0xF5, 0x90, 0x06,
-      0x76, 0xA0, 0xF0, 0x39, 0xCB, 0x64, 0x5D, 0xD1, 0x75, 0x49, 0xB2, 0x16, 0xC8, 0x24, 0x40, 0xCE },
-      136 /* Bin Number */
-  },
-  {
-    /* Hongkong_Post_Root_CA_1 */
-    { 0xF9, 0xE6, 0x7D, 0x33, 0x6C, 0x51, 0x00, 0x2A, 0xC0, 0x54, 0xC6, 0x32, 0x02, 0x2D, 0x66, 0xDD,
-      0xA2, 0xE7, 0xE3, 0xFF, 0xF1, 0x0A, 0xD0, 0x61, 0xED, 0x31, 0xD8, 0xBB, 0xB4, 0x10, 0xCF, 0xB2 },
-      96 /* Bin Number */
-  },
-  {
-    /* Certinomis___Autorit__Racine */
-    { 0xFC, 0xBF, 0xE2, 0x88, 0x62, 0x06, 0xF7, 0x2B, 0x27, 0x59, 0x3C, 0x8B, 0x07, 0x02, 0x97, 0xE1,
-      0x2D, 0x76, 0x9E, 0xD1, 0x0E, 0xD7, 0x93, 0x07, 0x05, 0xA8, 0x09, 0x8E, 0xFF, 0xC1, 0x4D, 0x17 },
-      114 /* Bin Number */
-  },
-  {
-    /* T_TeleSec_GlobalRoot_Class_3 */
-    { 0xFD, 0x73, 0xDA, 0xD3, 0x1C, 0x64, 0x4F, 0xF1, 0xB4, 0x3B, 0xEF, 0x0C, 0xCD, 0xDA, 0x96, 0x71,
-      0x0B, 0x9C, 0xD9, 0x87, 0x5E, 0xCA, 0x7E, 0x31, 0x70, 0x7A, 0xF3, 0xE9, 0x6D, 0x52, 0x2B, 0xBD },
-      127 /* Bin Number */
-  },
-  {
-    /* GeoTrust_Global_CA */
-    { 0xFF, 0x85, 0x6A, 0x2D, 0x25, 0x1D, 0xCD, 0x88, 0xD3, 0x66, 0x56, 0xF4, 0x50, 0x12, 0x67, 0x98,
-      0xCF, 0xAB, 0xAA, 0xDE, 0x40, 0x79, 0x9C, 0x72, 0x2D, 0xE4, 0xD2, 0xB5, 0xDB, 0x36, 0xA7, 0x3A },
-      20 /* Bin Number */
-  },
-};
-
deleted file mode 100644
--- a/security/manager/tools/KnownRootHashes.json.orig
+++ /dev/null
@@ -1,1004 +0,0 @@
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-//
-//***************************************************************************
-// This is an automatically generated file. It's used to maintain state for
-// runs of genRootCAHashes.js; you should never need to manually edit it
-//***************************************************************************
-
-{
-  "roots": [
-    {
-      "label": "GTE_CyberTrust_Global_Root",
-      "binNumber": 1,
-      "sha256Fingerprint": "pTElGI0hEKqWSwLHt8baMgMXCJTl+3H/+2Zn1eaBCjY="
-    },
-    {
-      "label": "Thawte_Server_CA",
-      "binNumber": 2,
-      "sha256Fingerprint": "tEELc+Lm6spH+8Qvj6QBivQ4HcVM+qhEUEYe7QlFTek="
-    },
-    {
-      "label": "Thawte_Premium_Server_CA",
-      "binNumber": 3,
-      "sha256Fingerprint": "q3A2NlxxVKopwsKfXUGRFjsWKiIlARNX1W0H/6e8H3I="
-    },
-    {
-      "label": "OU_Equifax_Secure_Certificate_Authority_O_Equifax_C_US",
-      "binNumber": 4,
-      "sha256Fingerprint": "CCl6QEfbojaAxzHbbjF2U8p4SOG+vToLAXmnB/ks8Xg="
-    },
-    {
-      "label": "OU_VeriSign_Trust_Network_OU___c__1998_VeriSign__Inc____For_authorized_use_only__OU_Class_3_Public_Primary_Certification_Authority___G2_O__VeriSign__Inc___C_US",
-      "binNumber": 5,
-      "sha256Fingerprint": "g848Eiloilk9SF+BlzwPkZVDHto3zF42Qw55x6iIY4s="
-    },
-    {
-      "label": "GlobalSign_Root_CA",
-      "binNumber": 6,
-      "sha256Fingerprint": "69QQQOS7PsdCyeOB0x7ypBpItmhclufO88HfbNQzHJk="
-    },
-    {
-      "label": "GlobalSign",
-      "binNumber": 7,
-      "sha256Fingerprint": "ykLdQXRf0LgeuQI2LPnYv3Gdob0bHvyUb1tMmfQsG54="
-    },
-    {
-      "label": "VeriSign_Class_3_Public_Primary_Certification_Authority___G3",
-      "binNumber": 8,
-      "sha256Fingerprint": "6wTPXrHzmvp2LyuxIPKWy6Ugwbl9sViVZbgcuaF7ckQ="
-    },
-    {
-      "label": "VeriSign_Class_4_Public_Primary_Certification_Authority___G3",
-      "binNumber": 9,
-      "sha256Fingerprint": "44k2DQ/brrPSUFhLRzAxTiIvOcFWoCAUTo2WBWF5FQY="
-    },
-    {
-      "label": "Entrust_net_Certification_Authority__2048_",
-      "binNumber": 10,
-      "sha256Fingerprint": "bcRxcuAcvLC/YlgNiV/iuKya1PhzgB4MELnIN9IesXc="
-    },
-    {
-      "label": "Baltimore_CyberTrust_Root",
-      "binNumber": 11,
-      "sha256Fingerprint": "Fq9XqfZ2sKsSYJWqXrre8iqzERnWRKyVzUuT2/Pyaus="
-    },
-    {
-      "label": "Equifax_Secure_Global_eBusiness_CA_1",
-      "binNumber": 12,
-      "sha256Fingerprint": "Xwti6rXjU+plIWUWWPu2U1n0QygKSvvRBNd9EPnwTAc="
-    },
-    {
-      "label": "Equifax_Secure_eBusiness_CA_1",
-      "binNumber": 13,
-      "sha256Fingerprint": "z1b/RqShhhCd2WWEte61ilEMQnWw5flPQLuuhl4Z9nM="
-    },
-    {
-      "label": "AddTrust_Class_1_CA_Root",
-      "binNumber": 14,
-      "sha256Fingerprint": "jHIJJ5rATideFtB/07d16AFUtZaARuMfUt0ldmMk6ac="
-    },
-    {
-      "label": "AddTrust_External_CA_Root",
-      "binNumber": 15,
-      "sha256Fingerprint": "aH+kUTgieP/wyLEfjUPVdmccbrK86rQT+4PZZdBtL/I="
-    },
-    {
-      "label": "AddTrust_Public_CA_Root",
-      "binNumber": 16,
-      "sha256Fingerprint": "B5HKB0myB4Kq08fXvQzfyUhYNYQ+steZYAnOQ6tsaSc="
-    },
-    {
-      "label": "AddTrust_Qualified_CA_Root",
-      "binNumber": 17,
-      "sha256Fingerprint": "gJUhCAXbS7w1XkQo2P1uws3jq1+5eplCmI649NzQYBY="
-    },
-    {
-      "label": "Entrust_Root_Certification_Authority",
-      "binNumber": 18,
-      "sha256Fingerprint": "c8F2Q08bxtWt9FsOducnKHyN5XYWwebmFBorLLx9jkw="
-    },
-    {
-      "label": "OU_RSA_Security_2048_V3_O_RSA_Security_Inc",
-      "binNumber": 19,
-      "sha256Fingerprint": "r4tnYqHlKCKBYaldXFWe4mYnj3XXnoMBiaUDUGq9a0w="
-    },
-    {
-      "label": "GeoTrust_Global_CA",
-      "binNumber": 20,
-      "sha256Fingerprint": "/4VqLSUdzYjTZlb0UBJnmM+rqt5AeZxyLeTStds2pzo="
-    },
-    {
-      "label": "GeoTrust_Global_CA_2",
-      "binNumber": 21,
-      "sha256Fingerprint": "yi2CoIZ3By+KtnZP8DVnbP4+XjJeASFy3z+SCW23m4U="
-    },
-    {
-      "label": "GeoTrust_Universal_CA",
-      "binNumber": 22,
-      "sha256Fingerprint": "oEWbn2OyJVn1+l1MbbP59y/xk0IDNXjwc78dG0bLuRI="
-    },
-    {
-      "label": "GeoTrust_Universal_CA_2",
-      "binNumber": 23,
-      "sha256Fingerprint": "oCNPO8hSfKVijuyBrV1piV2laA3JHRy4R38z+Hi5Wws="
-    },
-    {
-      "label": "America_Online_Root_Certification_Authority_1",
-      "binNumber": 24,
-      "sha256Fingerprint": "d0BzEsY6FT1bwAtOUXWc39rCN9wqM7Z5RumOm/poCuM="
-    },
-    {
-      "label": "America_Online_Root_Certification_Authority_2",
-      "binNumber": 25,
-      "sha256Fingerprint": "fTtGWmAU5SbAr/zuISfSMRcnrYEcJoQtAGrzcwbMgL0="
-    },
-    {
-      "label": "Visa_eCommerce_Root",
-      "binNumber": 26,
-      "sha256Fingerprint": "afrJvVX7CseNU7vuXPHVl5if0KqrIKJRUb3xcz7n0SI="
-    },
-    {
-      "label": "Certum_CA",
-      "binNumber": 27,
-      "sha256Fingerprint": "2OD+vB2y440AlA830n1BNE2ZPnNLmdVlbZd41NgUNiQ="
-    },
-    {
-      "label": "AAA_Certificate_Services",
-      "binNumber": 28,
-      "sha256Fingerprint": "16eg+11+JzHXcelITrze9x1fDD4KKUh4K8g+4OppnvQ="
-    },
-    {
-      "label": "Secure_Certificate_Services",
-      "binNumber": 29,
-      "sha256Fingerprint": "vYHOO09lkdEaZ7X8ekf97yVSG/mqThi5498uNKeAO+g="
-    },
-    {
-      "label": "Trusted_Certificate_Services",
-      "binNumber": 30,
-      "sha256Fingerprint": "PwblVoHUlvW+Fp61OJ+fK4/2HhcI32iBckhJzV0ny2k="
-    },
-    {
-      "label": "QuoVadis_Root_Certification_Authority",
-      "binNumber": 31,
-      "sha256Fingerprint": "pF7eO7vwnIrhXHLvwHJo1pOiHJlv1R5nygeUYP1tiHM="
-    },
-    {
-      "label": "QuoVadis_Root_CA_2",
-      "binNumber": 32,
-      "sha256Fingerprint": "haDdfdcgrbf/Bfg9VCsgncf/RSj31nexg4n+peXEnoY="
-    },
-    {
-      "label": "QuoVadis_Root_CA_3",
-      "binNumber": 33,
-      "sha256Fingerprint": "GPH8fyBd+K3d63/gB91X4683WpxNjXNUa/Tx/tHhjTU="
-    },
-    {
-      "label": "OU_Security_Communication_RootCA1_O_SECOM_Trust_net_C_JP",
-      "binNumber": 34,
-      "sha256Fingerprint": "515y7Z9WDuxutIAAc6Q/w60ZGVo5IoIBeJWXSpkCa2w="
-    },
-    {
-      "label": "Sonera_Class2_CA",
-      "binNumber": 35,
-      "sha256Fingerprint": "eQi0AxTBOBALUY0HNYB/+/z4UYoAlTNxBbo4axU92Sc="
-    },
-    {
-      "label": "Staat_der_Nederlanden_Root_CA",
-      "binNumber": 36,
-      "sha256Fingerprint": "1B2CnowWWYIq+T/OYr/83iZPyE6LlQxf8nXQUjVGlaM="
-    },
-    {
-      "label": "UTN___DATACorp_SGC",
-      "binNumber": 37,
-      "sha256Fingerprint": "hfsvkd0SJ1oBRbY2U0+EAkrWi2m47ohoT/cRN1gFs0g="
-    },
-    {
-      "label": "UTN_USERFirst_Hardware",
-      "binNumber": 38,
-      "sha256Fingerprint": "bqVHQdAEZn7tG0gWY0qjp55uS5aVD4J52vyNm9iBITc="
-    },
-    {
-      "label": "Chambers_of_Commerce_Root",
-      "binNumber": 39,
-      "sha256Fingerprint": "DCWKEqVnSu8l8oun3Prs7qNI5UHm9cxO5jtxs2FgasM="
-    },
-    {
-      "label": "Global_Chambersign_Root",
-      "binNumber": 40,
-      "sha256Fingerprint": "7zy0F/yOv2+Xh2yeTs453h6l/mSRQdECi30RwLIpjO0="
-    },
-    {
-      "label": "NetLock_Kozjegyzoi__Class_A__Tanusitvanykiado",
-      "binNumber": 41,
-      "sha256Fingerprint": "fxLNX35eKQ7H2FF51bcsIKW+dQj/21v4GrloSn/J9mc="
-    },
-    {
-      "label": "XRamp_Global_Certification_Authority",
-      "binNumber": 42,
-      "sha256Fingerprint": "zs3ckFCZ2NrfxbHSCbc3y+LBjPssEMD/C88NMob8GqI="
-    },
-    {
-      "label": "OU_Go_Daddy_Class_2_Certification_Authority_O__The_Go_Daddy_Group__Inc___C_US",
-      "binNumber": 43,
-      "sha256Fingerprint": "w4Rr8kuek8pkJ0wOxnwezF4CT/ys0tdAGTUOgf5UauQ="
-    },
-    {
-      "label": "OU_Starfield_Class_2_Certification_Authority_O__Starfield_Technologies__Inc___C_US",
-      "binNumber": 44,
-      "sha256Fingerprint": "FGX6IFOXuHb6pvCplY5VkOQPzH+qT7fCyGd1Iftftlg="
-    },
-    {
-      "label": "StartCom_Certification_Authority",
-      "binNumber": 45,
-      "sha256Fingerprint": "x2apvvLUBxyGOjGqSSDoE7LRmGCMt7fP4hFDuDbfCeo="
-    },
-    {
-      "label": "O_Government_Root_Certification_Authority_C_TW",
-      "binNumber": 46,
-      "sha256Fingerprint": "dgApXu/oW54f1iTbdgYqqq5ZgYpU0ndM1MCywBEx4bM="
-    },
-    {
-      "label": "Swisscom_Root_CA_1",
-      "binNumber": 47,
-      "sha256Fingerprint": "IdsgEjZguy7UGCBdoR7nqFpl4rxuVbWvfniZyKJm2S4="
-    },
-    {
-      "label": "DigiCert_Assured_ID_Root_CA",
-      "binNumber": 48,
-      "sha256Fingerprint": "PpCZtQFej0hsALzqnREe5yH6ujVaibzx32lWHj3GMlw="
-    },
-    {
-      "label": "DigiCert_Global_Root_CA",
-      "binNumber": 49,
-      "sha256Fingerprint": "Q0ig6URMeMsmXgWNXolEtNhPlmK9Jtslf4k0pEPHAWE="
-    },
-    {
-      "label": "DigiCert_High_Assurance_EV_Root_CA",
-      "binNumber": 50,
-      "sha256Fingerprint": "dDHl9MPBzkaQd08LYeBUQIg7qaAe0Aumq9eAbtOxGM8="
-    },
-    {
-      "label": "Class_2_Primary_CA",
-      "binNumber": 51,
-      "sha256Fingerprint": "D5k8iu+Xuq9WhxQO1ZrRghu0r6zwqppYtdV6M4o6+8s="
-    },
-    {
-      "label": "DST_Root_CA_X3",
-      "binNumber": 52,
-      "sha256Fingerprint": "BocmAzGnJAPZCfEF5pvPDTLhvSST/8bZIG0RvNZ3Bzk="
-    },
-    {
-      "label": "DST_ACES_CA_X6",
-      "binNumber": 53,
-      "sha256Fingerprint": "dnyVWnZBLImvaI6QoccPVWz9a2Al2+oQQW1+toMfjEA="
-    },
-    {
-      "label": "T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_",
-      "binNumber": 54,
-      "sha256Fingerprint": "RATjO14UDc+ZgFH9/IAox8gWFcXuc3sRG1iCM6m1NaA="
-    },
-    {
-      "label": "T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_",
-      "binNumber": 55,
-      "sha256Fingerprint": "xHDPVH4jArl3+yndcaiae2wfYHd7Ayn1YBfzKL9Pa+Y="
-    },
-    {
-      "label": "SwissSign_Gold_CA___G2",
-      "binNumber": 56,
-      "sha256Fingerprint": "Yt0L6bn1ChY+oPjnXAU7HspX6lXIaI9kfGiB8sg1e5U="
-    },
-    {
-      "label": "SwissSign_Silver_CA___G2",
-      "binNumber": 57,
-      "sha256Fingerprint": "vmxNoru5ulm285OXaDdCRsPABZk/qY8CDR3tvtSKgdU="
-    },
-    {
-      "label": "GeoTrust_Primary_Certification_Authority",
-      "binNumber": 58,
-      "sha256Fingerprint": "N9UQBsUS6qtiZCHx7IySAT/F+CrpjuUz60YZuN600Gw="
-    },
-    {
-      "label": "thawte_Primary_Root_CA",
-      "binNumber": 59,
-      "sha256Fingerprint": "jXIvganBE8B5HfE2opZtsmyVCpcdtGtBmfTqVLeL+58="
-    },
-    {
-      "label": "VeriSign_Class_3_Public_Primary_Certification_Authority___G5",
-      "binNumber": 60,
-      "sha256Fingerprint": "ms+rfkPI2IDQayYqlN7u5LRlmYnD0Mrxm69kBeQat98="
-    },
-    {
-      "label": "SecureTrust_CA",
-      "binNumber": 61,
-      "sha256Fingerprint": "8cG1CuWiDdgDDsn2vCSCPdNntSVXWbTnG2H86fc3XXM="
-    },
-    {
-      "label": "Secure_Global_CA",
-      "binNumber": 62,
-      "sha256Fingerprint": "QgD1BDrIWQ67Un0gntFQMCn7y9QcobUG7CfxWt59rGk="
-    },
-    {
-      "label": "COMODO_Certification_Authority",
-      "binNumber": 63,
-      "sha256Fingerprint": "DCzWPfeAb6OZ7egJEWtXW/h5ifBlGPmAjIYFAxeLr2Y="
-    },
-    {
-      "label": "Network_Solutions_Certificate_Authority",
-      "binNumber": 64,
-      "sha256Fingerprint": "FfC6AKOsevOsiEwHKxARoHe9d8CX9AFksvhZir2Dhgw="
-    },
-    {
-      "label": "WellsSecure_Public_Root_Certificate_Authority",
-      "binNumber": 65,
-      "sha256Fingerprint": "pxJyrqqjz+hyf3+znw+z0eVCbpBgsG7m8T6aPFgzzUM="
-    },
-    {
-      "label": "COMODO_ECC_Certification_Authority",
-      "binNumber": 66,
-      "sha256Fingerprint": "F5OSegYUVJeJrc4vjzT38LZtDzrjo7hNIewV27pPrcc="
-    },
-    {
-      "label": "IGC_A",
-      "binNumber": 67,
-      "sha256Fingerprint": "ub6nhgqWLqNhHauXq22j4hwQaLl9VVde0OESecEciTI="
-    },
-    {
-      "label": "OU_Security_Communication_EV_RootCA1_O__SECOM_Trust_Systems_CO__LTD___C_JP",
-      "binNumber": 68,
-      "sha256Fingerprint": "oi26aB6XN24tOX1yiq46m2KWuf26YLwuEfZH8sZ1+zc="
-    },
-    {
-      "label": "OISTE_WISeKey_Global_Root_GA_CA",
-      "binNumber": 69,
-      "sha256Fingerprint": "Qckjhmq0yta3rVeAgVguAgeXpsvfT/94zoOWs4k31/U="
-    },
-    {
-      "label": "Microsec_e_Szigno_Root_CA",
-      "binNumber": 70,
-      "sha256Fingerprint": "Mno9dhq63qA065mEBidcsaR3bv2uL99tAWjqHE9VZ9A="
-    },
-    {
-      "label": "Certigna",
-      "binNumber": 71,
-      "sha256Fingerprint": "47ai2y7XzkiEL3rFMkHHtx1UFEv7QMEfPx0LQvXuoS0="
-    },
-    {
-      "label": "TC_TrustCenter_Class_2_CA_II",
-      "binNumber": 72,
-      "sha256Fingerprint": "5rj4dmSF+Aeuf42sFnBGHwfAoT7vOh/3F1ONerrTkbQ="
-    },
-    {
-      "label": "TC_TrustCenter_Class_3_CA_II",
-      "binNumber": 73,
-      "sha256Fingerprint": "jaCE/Pmc4Hci+JsyBZOYBvpcuBHhyBP2oQjH0zazQI4="
-    },
-    {
-      "label": "TC_TrustCenter_Universal_CA_I",
-      "binNumber": 74,
-      "sha256Fingerprint": "6/PAKoeJsft9URmV1mO3KQbZE84NXhBWiop34lhhZ+c="
-    },
-    {
-      "label": "Deutsche_Telekom_Root_CA_2",
-      "binNumber": 75,
-      "sha256Fingerprint": "thkaUNDDl399qZvNqshqIn2uuWeexwujsMnZInHBcNM="
-    },
-    {
-      "label": "ComSign_Secured_CA",
-      "binNumber": 76,
-      "sha256Fingerprint": "UHlBx0RgoLRwhiINTpkyVyq10bW7y4mAqxyxdlGoRNI="
-    },
-    {
-      "label": "Cybertrust_Global_Root",
-      "binNumber": 77,
-      "sha256Fingerprint": "lgrfAGPpY1Z1DCll3QoIZ9oLnL1ud3FK6vsjSas5PaM="
-    },
-    {
-      "label": "OU_ePKI_Root_Certification_Authority_O__Chunghwa_Telecom_Co___Ltd___C_TW",
-      "binNumber": 78,
-      "sha256Fingerprint": "wKb03GOiS/3PVO8qaggqCnLeNYA+L/X/Unrl2HIG39U="
-    },
-    {
-      "label": "T_B_TAK_UEKAE_K_k_Sertifika_Hizmet_Sa_lay_c_s____S_r_m_3",
-      "binNumber": 79,
-      "sha256Fingerprint": "5Mc0MNeltQkl30M3Cg0hbpp5udbbg3Ogxp6xzDHHxSo="
-    },
-    {
-      "label": "Buypass_Class_2_CA_1",
-      "binNumber": 80,
-      "sha256Fingerprint": "D06c3SZLAlVQ0XCAY0AhT+lENMmwL2l+xxD8X+r7Xjg="
-    },
-    {
-      "label": "Buypass_Class_3_CA_1",
-      "binNumber": 81,
-      "sha256Fingerprint": "t7ErFx+CHaqZDND+UIexKESLqOUYT4TFHgK1yPuWKyQ="
-    },
-    {
-      "label": "EBG_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_",
-      "binNumber": 82,
-      "sha256Fingerprint": "Na5b3dj3rmNc/7pWgqjwC5X0hGLHEI7poOUpKwdKr7I="
-    },
-    {
-      "label": "OU_certSIGN_ROOT_CA_O_certSIGN_C_RO",
-      "binNumber": 83,
-      "sha256Fingerprint": "6qlixPpKa6/r5BUZbTUczYiNT1Pz+orm18RmqU5gQrs="
-    },
-    {
-      "label": "CNNIC_ROOT",
-      "binNumber": 84,
-      "sha256Fingerprint": "4oOTdz2oRaZ58ggMx/tEo7ehw3kst+t3Kf3Lao2Zrqc="
-    },
-    {
-      "label": "OU_ApplicationCA_O_Japanese_Government_C_JP",
-      "binNumber": 85,
-      "sha256Fingerprint": "LUdDfeF5USFaEvPFjlHHKaWAJu8fzApfs9ncAS9gDRk="
-    },
-    {
-      "label": "GeoTrust_Primary_Certification_Authority___G3",
-      "binNumber": 86,
-      "sha256Fingerprint": "tHi4EiUN+HhjXCqn7H0VXqpiXugpFuLNKUNhiGzR+9Q="
-    },
-    {
-      "label": "thawte_Primary_Root_CA___G2",
-      "binNumber": 87,
-      "sha256Fingerprint": "pDENUK8YpkRxkDcqhq+vi5Uf+0Mdg38eVoi0WXHtFVc="
-    },
-    {
-      "label": "thawte_Primary_Root_CA___G3",
-      "binNumber": 88,
-      "sha256Fingerprint": "SwP0WAetcPIb/Cyuccn95GBMBkz1/7aGuuXbqtf900w="
-    },
-    {
-      "label": "GeoTrust_Primary_Certification_Authority___G2",
-      "binNumber": 89,
-      "sha256Fingerprint": "Xtt6xDuCoGqHYejXvkl56/JhH33Xm/kcHGtWaiGe12Y="
-    },
-    {
-      "label": "VeriSign_Universal_Root_Certification_Authority",
-      "binNumber": 90,
-      "sha256Fingerprint": "I5lWESelcSXejO/qYQ3fL6B4tcgGf06CgpC/uGDoSzw="
-    },
-    {
-      "label": "VeriSign_Class_3_Public_Primary_Certification_Authority___G4",
-      "binNumber": 91,
-      "sha256Fingerprint": "ad3X6pC7V8k+E13IXqb81UgLYDI5vcRU/HWLKibPf3k="
-    },
-    {
-      "label": "NetLock_Arany__Class_Gold__F_tan_s_tv_ny",
-      "binNumber": 92,
-      "sha256Fingerprint": "bGHaw6Le8DFQa+A20qb+QBmU+9E9+cjUZlmSdMRG7Jg="
-    },
-    {
-      "label": "Staat_der_Nederlanden_Root_CA___G2",
-      "binNumber": 93,
-      "sha256Fingerprint": "ZoyDlH2mO3JL7OF0PDGg5q7Q247Fsxvjd7t4T5G2cW8="
-    },
-    {
-      "label": "CA_Disig",
-      "binNumber": 94,
-      "sha256Fingerprint": "kr9RGavsytCxMy3E4dBfunW1Z5BE7gyibpMfdE8vM88="
-    },
-    {
-      "label": "Juur_SK",
-      "binNumber": 95,
-      "sha256Fingerprint": "7MPpw0B1A77gkaqVL0E0j/iLqoY7ImS++sgHkBV06Tk="
-    },
-    {
-      "label": "Hongkong_Post_Root_CA_1",
-      "binNumber": 96,
-      "sha256Fingerprint": "+eZ9M2xRACrAVMYyAi1m3aLn4//xCtBh7THYu7QQz7I="
-    },
-    {
-      "label": "SecureSign_RootCA11",
-      "binNumber": 97,
-      "sha256Fingerprint": "vw/u+546WBrV+enbdYmYV0PSYQhcTTFPb11yWapCFhI="
-    },
-    {
-      "label": "ACEDICOM_Root",
-      "binNumber": 98,
-      "sha256Fingerprint": "A5UPtJpTHz4ZkZQjmN+p4Ooy17oc3ZvIXbV+2UALQ0o="
-    },
-    {
-      "label": "Microsec_e_Szigno_Root_CA_2009",
-      "binNumber": 99,
-      "sha256Fingerprint": "PF+B/qX6uCxkv6Lq7K/N6OB3/IYgp8rlNxY9827b83g="
-    },
-    {
-      "label": "e_Guven_Kok_Elektronik_Sertifika_Hizmet_Saglayicisi",
-      "binNumber": 100,
-      "sha256Fingerprint": "5gkHhGWkGXgMtqxMHAv7RlPZ2cxus5Rut/PWmZe61Zg="
-    },
-    {
-      "label": "GlobalSign",
-      "binNumber": 101,
-      "sha256Fingerprint": "y7Ui17fxJ61qAROGW98c1BAufQdZr2NafPRyDcljxTs="
-    },
-    {
-      "label": "Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068",
-      "binNumber": 102,
-      "sha256Fingerprint": "BASAKL8fKGTUj5rU2DKUNmqCiFZVPzsUMD+QFH9dQO8="
-    },
-    {
-      "label": "Izenpe_com",
-      "binNumber": 103,
-      "sha256Fingerprint": "JTDMjpgyFQK62W+bH7obCZ4tKZ4PRUi7kU82O8DUUx8="
-    },
-    {
-      "label": "Chambers_of_Commerce_Root___2008",
-      "binNumber": 104,
-      "sha256Fingerprint": "Bj5K+sSR39My8wibhULpRhfYk9f+lE4Qp5N+4p2Wk8A="
-    },
-    {
-      "label": "Global_Chambersign_Root___2008",
-      "binNumber": 105,
-      "sha256Fingerprint": "E2M1Q5M0p2mAFqDTJN5yKE4HnXtSILuPvXR4Fu6+uso="
-    },
-    {
-      "label": "Go_Daddy_Root_Certificate_Authority___G2",
-      "binNumber": 106,
-      "sha256Fingerprint": "RRQLMkfrnMjFtPDXtTCR9zKSCJ5uWmPidJ3TrKkZjto="
-    },
-    {
-      "label": "Starfield_Root_Certificate_Authority___G2",
-      "binNumber": 107,
-      "sha256Fingerprint": "LOHLC/nS+eECmT++IVFSw7LdDKveHGjlMZuDkVTbt/U="
-    },
-    {
-      "label": "Starfield_Services_Root_Certificate_Authority___G2",
-      "binNumber": 108,
-      "sha256Fingerprint": "Vo1pBaLIhwikswJRkO3P7bGXSmBqE8blKQ/LKuY+2rU="
-    },
-    {
-      "label": "AffirmTrust_Commercial",
-      "binNumber": 109,
-      "sha256Fingerprint": "A3arHVTF+YA85LLiAaDufu97V7Y26Kk8m41IYMlvX6c="
-    },
-    {
-      "label": "AffirmTrust_Networking",
-      "binNumber": 110,
-      "sha256Fingerprint": "CoHsWpKXd/FFkErzjV1Qn2a14sWPzbUxBYsOF/PwtBs="
-    },
-    {
-      "label": "AffirmTrust_Premium",
-      "binNumber": 111,
-      "sha256Fingerprint": "cKc/fzdrYAdCSJBFNLEUgtW/DmmOzEmN9SV36/LpO5o="
-    },
-    {
-      "label": "AffirmTrust_Premium_ECC",
-      "binNumber": 112,
-      "sha256Fingerprint": "vXH99tqX5M9i0WR63SWBsH15rfg5frTsupxehIiCFCM="
-    },
-    {
-      "label": "Certum_Trusted_Network_CA",
-      "binNumber": 113,
-      "sha256Fingerprint": "XFhGjVX1jkl+dDmC0rUAELbRZTdKz4On1KMtt2jEQI4="
-    },
-    {
-      "label": "Certinomis___Autorit__Racine",
-      "binNumber": 114,
-      "sha256Fingerprint": "/L/iiGIG9ysnWTyLBwKX4S12ntEO15MHBagJjv/BTRc="
-    },
-    {
-      "label": "Root_CA_Generalitat_Valenciana",
-      "binNumber": 115,
-      "sha256Fingerprint": "jE7f0ENI8yKWnn4ppM1NygBGVQYcFuGwdkIu80KtYw4="
-    },
-    {
-      "label": "A_Trust_nQual_03",
-      "binNumber": 116,
-      "sha256Fingerprint": "eTy/RVm5/eOKsi3xaGn2mIGuFMSwE5rHiKeKGvzKAvs="
-    },
-    {
-      "label": "TWCA_Root_Certification_Authority",
-      "binNumber": 117,
-      "sha256Fingerprint": "v9iP4RAcQa4+gBv4vlY1Dum60aa5vVFe3FxtW4cRrEQ="
-    },
-    {
-      "label": "OU_Security_Communication_RootCA2_O__SECOM_Trust_Systems_CO__LTD___C_JP",
-      "binNumber": 118,
-      "sha256Fingerprint": "UTss7LgQ1M3l3YU5Gt/Gwt1g2Hu3NtK1IUhKpHoOvvY="
-    },
-    {
-      "label": "EC_ACC",
-      "binNumber": 119,
-      "sha256Fingerprint": "iEl/AWAvMVQkauKMTVrvEPHYfrt2Ym9K4Lf5W6eWh5k="
-    },
-    {
-      "label": "Hellenic_Academic_and_Research_Institutions_RootCA_2011",
-      "binNumber": 120,
-      "sha256Fingerprint": "vBBPFaSL5wncpUKn4dS5328FRSfoAuqpLVlURCWK/nE="
-    },
-    {
-      "label": "Actalis_Authentication_Root_CA",
-      "binNumber": 121,
-      "sha256Fingerprint": "VZJghOyWOmS5biq+Ac4LqGpk+/68x6q1r8FVs3/XYGY="
-    },
-    {
-      "label": "OU_Trustis_FPS_Root_CA_O_Trustis_Limited_C_GB",
-      "binNumber": 122,
-      "sha256Fingerprint": "wbSCmaulII/pYwrOVcpooD7aWlGciAKg06Zzvo+OVX0="
-    },
-    {
-      "label": "StartCom_Certification_Authority",
-      "binNumber": 123,
-      "sha256Fingerprint": "4XiQ7gmj+/T0i5xBShfWN7elBkfpvHUjInJ/zBdCqRE="
-    },
-    {
-      "label": "StartCom_Certification_Authority_G2",
-      "binNumber": 124,
-      "sha256Fingerprint": "x7plZ96Tp5iuH6p5HnEtN4+uH5PEOX/qRBu3y+b9WZU="
-    },
-    {
-      "label": "Buypass_Class_2_Root_CA",
-      "binNumber": 125,
-      "sha256Fingerprint": "mhFAJRl8W7ldlOY9Vc1DeQhHtkayPN8RraSgDv8V+0g="
-    },
-    {
-      "label": "Buypass_Class_3_Root_CA",
-      "binNumber": 126,
-      "sha256Fingerprint": "7ffrvKJ6KjhNOHt9QBDGZuLttIQ+TCm0rh1bkzLmsk0="
-    },
-    {
-      "label": "T_TeleSec_GlobalRoot_Class_3",
-      "binNumber": 127,
-      "sha256Fingerprint": "/XPa0xxkT/G0O+8MzdqWcQuc2Ydeyn4xcHrz6W1SK70="
-    },
-    {
-      "label": "EE_Certification_Centre_Root_CA",
-      "binNumber": 128,
-      "sha256Fingerprint": "PoS6Q0KQhRbndXPAmS8JecoITkaFaB/xlcy6iiKbinY="
-    },
-    {
-      "label": "T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s_",
-      "binNumber": 129,
-      "sha256Fingerprint": "l4zZZvL6oHunqpUA2cAunXfyza2mrWunSvS5HGZZPFA="
-    },
-    {
-      "label": "D_TRUST_Root_Class_3_CA_2_2009",
-      "binNumber": 130,
-      "sha256Fingerprint": "SeekQqzw6mKHBQBUtSVktlDk9J5C40jWqjjgOelXscE="
-    },
-    {
-      "label": "D_TRUST_Root_Class_3_CA_2_EV_2009",
-      "binNumber": 131,
-      "sha256Fingerprint": "7sVJa5iM6YYluTQJLuwpCL7QsPMWwtRzDITq8fPTSIE="
-    },
-    {
-      "label": "PSCProcert",
-      "binNumber": 132,
-      "sha256Fingerprint": "PPw8FNH2hP8X44xDykQMALln7JM+i/4GTKHXLJDyrbA="
-    },
-    {
-      "label": "China_Internet_Network_Information_Center_EV_Certificates_Root",
-      "binNumber": 133,
-      "sha256Fingerprint": "HAHG9Nuy/vwiVYsryjJWP0mESs/DK3vksP9Zn56Mevc="
-    },
-    {
-      "label": "Swisscom_Root_CA_2",
-      "binNumber": 134,
-      "sha256Fingerprint": "8JsSLHEU9KCb1OpPSpnVWLRuTCXNgRQNKcBWE5FMOEE="
-    },
-    {
-      "label": "Swisscom_Root_EV_CA_2",
-      "binNumber": 135,
-      "sha256Fingerprint": "2V/qPKTu3OdM1251/G0f9ixEHw+ovHfwNLGeXbJYAV0="
-    },
-    {
-      "label": "CA_Disig_Root_R1",
-      "binNumber": 136,
-      "sha256Fingerprint": "+W8j9MPnnAd6RpiNWvWQBnag8DnLZF3RdUmyFsgkQM4="
-    },
-    {
-      "label": "CA_Disig_Root_R2",
-      "binNumber": 137,
-      "sha256Fingerprint": "4j1KA217cOn1lbFCIHnSuR7fux+2UaBjPqqKncX4BwM="
-    },
-    {
-      "label": "ACCVRAIZ1",
-      "binNumber": 138,
-      "sha256Fingerprint": "mm7AEuGn2p2+NBlNR4rXwNsYIvsHHfEpgUlu0QQ4QRM="
-    },
-    {
-      "label": "TWCA_Global_Root_CA",
-      "binNumber": 139,
-      "sha256Fingerprint": "WXaQB/doXQ/NUIcvn5XVdVpbK0V9gfNpK2EKmGcvDhs="
-    },
-    {
-      "label": "TeliaSonera_Root_CA_v1",
-      "binNumber": 140,
-      "sha256Fingerprint": "3Wk2/iH48HfBI6GlIcEiJPciVbc+A6cmBpPooksPo4k="
-    },
-    {
-      "label": "E_Tugra_Certification_Authority",
-      "binNumber": 141,
-      "sha256Fingerprint": "sL/VK7DX2b2Sv11NwT2iVcAsVC83g2XqiTkR9V5V8jw="
-    },
-    {
-      "label": "T_TeleSec_GlobalRoot_Class_2",
-      "binNumber": 142,
-      "sha256Fingerprint": "keL1eI1YEOunulhzfeFUio7KzQFFmLwLFD4EGxcFJVI="
-    },
-    {
-      "label": "Atos_TrustedRoot_2011",
-      "binNumber": 143,
-      "sha256Fingerprint": "81a+okS3qR6zXVPKmteGSs4Bji011fj5bd9opvQapHQ="
-    },
-    {
-      "label": "QuoVadis_Root_CA_1_G3",
-      "binNumber": 144,
-      "sha256Fingerprint": "ioZv0bJ2tX5XjpIcZYKKK+1Y6fLyiAVBNLfx9L/JzHQ="
-    },
-    {
-      "label": "QuoVadis_Root_CA_2_G3",
-      "binNumber": 145,
-      "sha256Fingerprint": "j+T7Cvk6TQ1n2wvrsj43xxvzJdy83SQOoE2vWLR+GEA="
-    },
-    {
-      "label": "QuoVadis_Root_CA_3_G3",
-      "binNumber": 146,
-      "sha256Fingerprint": "iO+B3iAusBhFLkP4ZHJc6l+9H8LZ0gVzBwnF2LhpD0Y="
-    },
-    {
-      "label": "DigiCert_Assured_ID_Root_G2",
-      "binNumber": 147,
-      "sha256Fingerprint": "fQXrtoIzn4yUUe4JTuv++nlToRTtsvRJSUUvq30vwYU="
-    },
-    {
-      "label": "DigiCert_Assured_ID_Root_G3",
-      "binNumber": 148,
-      "sha256Fingerprint": "fjfLi0xHCQyrNlUbpvRduEBoD7oWapUtsQBxf0MFP8I="
-    },
-    {
-      "label": "DigiCert_Global_Root_G2",
-      "binNumber": 149,
-      "sha256Fingerprint": "yzzLt2Ax5eATj43TmiP53kf/w15DwRRM6ifUalqxy18="
-    },
-    {
-      "label": "DigiCert_Global_Root_G3",
-      "binNumber": 150,
-      "sha256Fingerprint": "Ma1mSPgQQTjHOPOepDIBMzk+OhjMAilu+Xwqye9nMdA="
-    },
-    {
-      "label": "DigiCert_Trusted_Root_G4",
-      "binNumber": 151,
-      "sha256Fingerprint": "VS973PGnr55s5nIBf08Sq/dyQMeOdhrCA9HZ0grImYg="
-    },
-    {
-      "label": "Certification_Authority_of_WoSign",
-      "binNumber": 152,
-      "sha256Fingerprint": "SyLVpq7JnzzbeapewGg4R5zV7LpxZPfyLcHWX2PYVwg="
-    },
-    {
-      "label": "CA______",
-      "binNumber": 153,
-      "sha256Fingerprint": "1vA0vZSqIz8Cl+ykJFsoOXPkR6pZDzEMd/SP34MRIlQ="
-    },
-    {
-      "label": "COMODO_RSA_Certification_Authority",
-      "binNumber": 154,
-      "sha256Fingerprint": "UvDhxOWOxikpG2AxfwdGcbhdfqgNWwcnNGNTSzK0AjQ="
-    },
-    {
-      "label": "USERTrust_RSA_Certification_Authority",
-      "binNumber": 155,
-      "sha256Fingerprint": "55PJsC/YqhPiHDEiisywgRlkO3SciYlksXRtRsPUy9I="
-    },
-    {
-      "label": "USERTrust_ECC_Certification_Authority",
-      "binNumber": 156,
-      "sha256Fingerprint": "T/Rg1Uuchtq/vPxXEuBADSvtP7xNT72qhuBq3NKprXo="
-    },
-    {
-      "label": "GlobalSign",
-      "binNumber": 157,
-      "sha256Fingerprint": "vslJEcKVVnbbbApVCYbXbjugBWZ8RCyXYrT7t3PeIow="
-    },
-    {
-      "label": "GlobalSign",
-      "binNumber": 158,
-      "sha256Fingerprint": "F5+8FIo90A/STqE0WMxDv6f1nIGC14OlE/br7BAMiSQ="
-    },
-    {
-      "label": "Staat_der_Nederlanden_Root_CA___G3",
-      "binNumber": 159,
-      "sha256Fingerprint": "PE+wuVq4swAy9DK4b1Nf4XLBhdD9OYZYN882GH+m9Cg="
-    },
-    {
-      "label": "Staat_der_Nederlanden_EV_Root_CA",
-      "binNumber": 160,
-      "sha256Fingerprint": "TSSRQUz+lWdG7Ezvps9vcuKKEylDL52KkHrEy12twVo="
-    },
-    {
-      "label": "IdenTrust_Commercial_Root_CA_1",
-      "binNumber": 161,
-      "sha256Fingerprint": "XVZJm+TS4IvPytCKPjhyPVBQO95waUjkL1VgMBnlKK4="
-    },
-    {
-      "label": "IdenTrust_Public_Sector_Root_CA_1",
-      "binNumber": 162,
-      "sha256Fingerprint": "MNCJWppEiiYgkWNVItH1IBC1hnrK4Sx475WP1PQ4ny8="
-    },
-    {
-      "label": "Entrust_Root_Certification_Authority___G2",
-      "binNumber": 163,
-      "sha256Fingerprint": "Q99XdLA+f+9f5A2TGnvt8bsua0JzjE5tOEEQPTqn8zk="
-    },
-    {
-      "label": "Entrust_Root_Certification_Authority___EC1",
-      "binNumber": 164,
-      "sha256Fingerprint": "Au0OsowU2kUWXFZnkXANZFHX+1bwsqsdO46wcOVu3/U="
-    },
-    {
-      "label": "CFCA_EV_ROOT",
-      "binNumber": 165,
-      "sha256Fingerprint": "XMPXjk4dXkVUegTmhz5k+Qz5U20czC74APNVxMX9cP0="
-    },
-    {
-      "label": "T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s__H5",
-      "binNumber": 166,
-      "sha256Fingerprint": "STUbkDREwYXM3FxpPSTYVVyyCNaoFBMHaZ9K8GMZnXg="
-    },
-    {
-      "label": "T_RKTRUST_Elektronik_Sertifika_Hizmet_Sa_lay_c_s__H6",
-      "binNumber": 167,
-      "sha256Fingerprint": "jeeGVeG+f3hHgAuT9pTSHTaMwG4DPn+rBLteuZ2mtwA="
-    },
-    {
-      "label": "Certinomis___Root_CA",
-      "binNumber": 168,
-      "sha256Fingerprint": "Kpn1vBF0tzy7HWIIhOAcNOUcyzl42hJfDjMmiIO/QVg="
-    },
-    {
-      "label": "OISTE_WISeKey_Global_Root_GB_CA",
-      "binNumber": 169,
-      "sha256Fingerprint": "a5wI6G6w92fPrWXNmLYhSeVJSmf1hF570e0Bnye4a9Y="
-    },
-    {
-      "label": "Certification_Authority_of_WoSign_G2",
-      "binNumber": 170,
-      "sha256Fingerprint": "1Ielb4OwdILoXpYzlMHswsnlHQkD7pRrAsMBWB7ZnhY="
-    },
-    {
-      "label": "CA_WoSign_ECC_Root",
-      "binNumber": 171,
-      "sha256Fingerprint": "i0XaHAb3kesMq/Jr5Yj1+yMWXC5hS/iFVi0NzlCymwI="
-    },
-    {
-      "label": "SZAFIR_ROOT_CA2",
-      "binNumber": 172,
-      "sha256Fingerprint": "oTOdMygaC1blV9PTKxzn+TZ+sJS9X6cqflAEyN7Xyv4="
-    },
-    {
-      "label": "Certum_Trusted_Network_CA_2",
-      "binNumber": 173,
-      "sha256Fingerprint": "tnby7drod1zTbLD2PNHUYDlh9J5iZboBOi8DB7bQuAQ="
-    },
-    {
-      "label": "Hellenic_Academic_and_Research_Institutions_RootCA_2015",
-      "binNumber": 174,
-      "sha256Fingerprint": "oECSmgLOU7Ss9PL/xpgc5ElvdV5tRf4LKmkrzVJSPzY="
-    },
-    {
-      "label": "Hellenic_Academic_and_Research_Institutions_ECC_RootCA_2015",
-      "binNumber": 175,
-      "sha256Fingerprint": "RLVFqool5lpzyhXcJ/w20kwcuZU6BmU5sRWC3Eh7SDM="
-    },
-    {
-      "label": "Certplus_Root_CA_G1",
-      "binNumber": 176,
-      "sha256Fingerprint": "FSpAK/zfLNVIBU0idbOcf8o+wJeAeLDw6nblYabHQz4="
-    },
-    {
-      "label": "Certplus_Root_CA_G2",
-      "binNumber": 177,
-      "sha256Fingerprint": "bMBQQeZEXnRpbEz7yfgPVDt+q7tEtM5veHxqmXHELxc="
-    },
-    {
-      "label": "OpenTrust_Root_CA_G1",
-      "binNumber": 178,
-      "sha256Fingerprint": "VsdxKNmMGNkbTP3/vCXukQPUdY6iq62CapDzRX1GDrQ="
-    },
-    {
-      "label": "OpenTrust_Root_CA_G2",
-      "binNumber": 179,
-      "sha256Fingerprint": "J5lYKf5qdRXBv+hI+cR2HbFsIlkpJXv0DQiU8p6ouvI="
-    },
-    {
-      "label": "OpenTrust_Root_CA_G3",
-      "binNumber": 180,
-      "sha256Fingerprint": "t8NiMXBugQeMNny4lhmPHjII3ZJpSd2PVwmkEPdbYpI="
-    },
-    {
-      "label": "ISRG_Root_X1",
-      "binNumber": 181,
-      "sha256Fingerprint": "lrzsBiZJdvN0YHeazyjFp8/oo8Cq4RqP/O4FwL3fCMY="
-    },
-    {
-      "label": "OU_AC_RAIZ_FNMT_RCM_O_FNMT_RCM_C_ES",
-      "binNumber": 182,
-      "sha256Fingerprint": "68VXDCkBjE1nsaoSe68S9wO0YR68F7fatVc4lBebk/o="
-    },
-    {
-      "label": "Amazon_Root_CA_1",
-      "binNumber": 183,
-      "sha256Fingerprint": "js3miE89h7ESW6Maw/yxPXAW3n9XzJBP4cuXxq6YGW4="
-    },
-    {
-      "label": "Amazon_Root_CA_2",
-      "binNumber": 184,
-      "sha256Fingerprint": "G6WyqoxlQBqClgEY+AvsT2IwTYPOxHE6GcOcAR6kbbQ="
-    },
-    {
-      "label": "Amazon_Root_CA_3",
-      "binNumber": 185,
-      "sha256Fingerprint": "GM5s/nvxTmCy40e43+hoyzHQLrs62icVafUDQ7Rts6Q="
-    },
-    {
-      "label": "Amazon_Root_CA_4",
-      "binNumber": 186,
-      "sha256Fingerprint": "410oQZ7QICXPppA4zWI5YkWNpcaV+96jwisL+yWJcJI="
-    },
-    {
-      "label": "LuxTrust_Global_Root_2",
-      "binNumber": 187,
-      "sha256Fingerprint": "VEVfcSnCCxRHxBj5lxaPJMWPxQI79dpb4utuHdiQLtU="
-    },
-    {
-      "label": "TUBITAK_Kamu_SM_SSL_Kok_Sertifikasi___Surum_1",
-      "binNumber": 188,
-      "sha256Fingerprint": "Ru3DaJBG1TpFP7MQSrgNyuxliyZg6hYp3X6GeZBkhxY="
-    },
-    {
-      "label": "GDCA_TrustAUTH_R5_ROOT",
-      "binNumber": 189,
-      "sha256Fingerprint": "v/+P0EQzSH1qiqYMGil2ep/Cu7BeQg9xOhO5kokdOJM="
-    },
-    {
-      "label": "TrustCor_RootCert_CA_1",
-      "binNumber": 190,
-      "sha256Fingerprint": "1A6chs2P5GjBd2lZ9J6ndPpUhoS2xAbzkJJh9NziV1w="
-    },
-    {
-      "label": "TrustCor_RootCert_CA_2",
-      "binNumber": 191,
-      "sha256Fingerprint": "B1PpQDeMG9Xjg245Xa6ly4OeUEbxvQ6uGVHPEP7HyWU="
-    },
-    {
-      "label": "TrustCor_ECA_1",
-      "binNumber": 192,
-      "sha256Fingerprint": "WohdsZwB2RLFdZOIk4yvu98DGrLUjpHuFVibQpcdA5w="
-    },
-    {
-      "label": "SSL_com_Root_Certification_Authority_RSA",
-      "binNumber": 193,
-      "sha256Fingerprint": "hWZqVi7gvlzpJcHYiQpvdqh+wW1NfV8p6nQZzyASO2k="
-    },
-    {
-      "label": "SSL_com_Root_Certification_Authority_ECC",
-      "binNumber": 194,
-      "sha256Fingerprint": "NBe7BsxgB9oblhySC4q0zj+tgg5Kowuay8SnTr3OvGU="
-    },
-    {
-      "label": "SSL_com_EV_Root_Certification_Authority_RSA_R2",
-      "binNumber": 195,
-      "sha256Fingerprint": "LnvxbMIkhae74qqGlnUHYbCuOb47L+nQzG1O9zSRQlw="
-    },
-    {
-      "label": "SSL_com_EV_Root_Certification_Authority_ECC",
-      "binNumber": 196,
-      "sha256Fingerprint": "IqLB973tcEzB5wG19AjDEIgP6Va13ipKRPmchzolp8g="
-    },
-    {
-      "label": "GlobalSign",
-      "binNumber": 197,
-      "sha256Fingerprint": "LKvq/jfQbKIqunORwAM9JZgpUsRTZHNJdjo6ta1sz2k="
-    },
-    {
-      "label": "OISTE_WISeKey_Global_Root_GC_CA",
-      "binNumber": 198,
-      "sha256Fingerprint": "hWD5HDYk2rqVcLX+oNvjb/EagyO+lIaFT7PzSlVxGY0="
-    }
-  ],
-  "maxBin": 198
-}
\ No newline at end of file
--- a/taskcluster/ci/packages/kind.yml
+++ b/taskcluster/ci/packages/kind.yml
@@ -95,34 +95,34 @@ jobs:
 
   deb7-mercurial:
     description: "Modern Mercurial for Debian wheezy"
     treeherder:
       symbol: Deb7(hg)
     run:
       using: debian-package
       tarball:
-        url: https://www.mercurial-scm.org/release/mercurial-4.7.tar.gz
-        sha256: 098cb1437f77fb7f75dc2f008742933c729ec0b63cfa3e4e2f0a8fbc3d0d349f
+        url: https://www.mercurial-scm.org/release/mercurial-4.7.1.tar.gz
+        sha256: 8503383c1c31842576516b803d07564216470887ca6388719e4c4089663b410c
       pre-build-command: >-
         cp -r contrib/packaging/debian debian &&
         sed -i -e "s/__VERSION__/$(awk -F\" '$2 {print $2}' mercurial/__version__.py)-1.deb7moz1/" \
                -e "s/__DATE__/$(date --rfc-2822)/" \
                -e "s/__CODENAME__/wheezy/" debian/changelog
 
   deb9-mercurial:
     description: "Modern Mercurial for Debian stretch"
     treeherder:
       symbol: Deb9(hg)
     run:
       using: debian-package
       dist: stretch
       tarball:
-        url: https://www.mercurial-scm.org/release/mercurial-4.7.tar.gz
-        sha256: 098cb1437f77fb7f75dc2f008742933c729ec0b63cfa3e4e2f0a8fbc3d0d349f
+        url: https://www.mercurial-scm.org/release/mercurial-4.7.1.tar.gz
+        sha256: 8503383c1c31842576516b803d07564216470887ca6388719e4c4089663b410c
       pre-build-command: >-
         cp -r contrib/packaging/debian debian &&
         sed -i -e "s/__VERSION__/$(awk -F\" '$2 {print $2}' mercurial/__version__.py)-1.deb9moz1/" \
                -e "s/__DATE__/$(date --rfc-2822)/" \
                -e "s/__CODENAME__/stretch/" debian/changelog
 
   deb7-git:
     description: "Modern git for Debian wheezy"
--- a/taskcluster/ci/test/mochitest.yml
+++ b/taskcluster/ci/test/mochitest.yml
@@ -57,17 +57,17 @@ mochitest:
             android-em.*: xlarge
             default: default
     virtualization:
         by-test-platform:
             windows10-64-qr/.*: virtual-with-gpu
             default: virtual
     chunks:
         by-test-platform:
-            android-em-4.3-arm7-api-16/debug: 48
+            android-em-4.3-arm7-api-16/debug: 60
             android-em-7.0-x86/opt: 4
             android-em.*: 24
             linux.*/debug: 16
             linux64-asan/opt: 10
             linux64-.*cov/opt: 10
             windows10-64-ccov/debug: 10
             macosx64-ccov/debug: 10
             default: 5
--- a/taskcluster/docker/recipes/install-mercurial.sh
+++ b/taskcluster/docker/recipes/install-mercurial.sh
@@ -11,23 +11,23 @@ set -e
 if [ -f /etc/lsb-release ]; then
     # Disabled so linting works on Mac
     # shellcheck disable=SC1091
     . /etc/lsb-release
 
     if [ "${DISTRIB_ID}" = "Ubuntu" ] && [[ "${DISTRIB_RELEASE}" = "16.04" || "${DISTRIB_RELEASE}" = "17.10" || "${DISTRIB_RELEASE}" = "18.04" ]]
     then
         HG_DEB=1
-        HG_DIGEST=21a5ca8170bdb05527b04cbc93f00ecef39680a2c7b80aa625f9add8b7dba0a7bff0ad58e0ba40b1956ae310f681d04302d033e398eca0e001dce10d74d0dbdc
-        HG_SIZE=250748
-        HG_FILENAME=mercurial_4.7_amd64.deb
+        HG_DIGEST=cbc3eafbc7598c7eafee81f4fb95f8d58dea5fede0fca6a04334eaa29667b9b464e3070fa24be91276d7294ba4629d7b7a648cbf969256289e9a28f5da684d09
+        HG_SIZE=250774
+        HG_FILENAME=mercurial_4.7.1_amd64.deb
 
-        HG_COMMON_DIGEST=521e0c150b142d0bbb69fa100b96bac5bee7a108605eea1c484e8544540dcf764efffab2e3a9ad640f56674ad85c1b47647e3d504c96f7567d7d7c21299c2c25
-        HG_COMMON_SIZE=2315590
-        HG_COMMON_FILENAME=mercurial-common_4.7_all.deb
+        HG_COMMON_DIGEST=15f9c72dba116d33c2d60831bc17cd714d66b830089aebe547c846b910dbc929200f7863e167a8dade67c77c4347b8e967e6da505c2fdffa4faaa7143eccdfd8
+        HG_COMMON_SIZE=2315652
+        HG_COMMON_FILENAME=mercurial-common_4.7.1_all.deb
     elif [ "${DISTRIB_ID}" = "Ubuntu" ] && [ "${DISTRIB_RELEASE}" = "12.04" ]
     then
         echo "Ubuntu 12.04 not supported"
         exit 1
     fi
 
     CERT_PATH=/etc/ssl/certs/ca-certificates.crt
 
@@ -101,25 +101,25 @@ tooltool_fetch <<EOF
 ]
 EOF
 
     rpm -i ${HG_FILENAME}
 elif [ -n "${PIP_PATH}" ]; then
 tooltool_fetch <<EOF
 [
   {
-    "size": 6476268,
-    "digest": "a08dfc4e296b5d162097769ab38ab85b7c5de16710bce0b6dce2a39f56cb517455c0ed634f689d07e9bd082fb7641501b7da51963844aee7ab28233cf721dec8",
+    "size": 6480135,
+    "digest": "04d3f97dd4a0f36c6f6d639d8eccc7e4f29b2dc211fa69e7fc17dae0eb954f2ddaaf04f70facc6b968a166db7c07ed80792575d7a27e80bc0c1a43fc38b5e536",
     "algorithm": "sha512",
-    "filename": "mercurial-4.7.tar.gz"
+    "filename": "mercurial-4.7.1.tar.gz"
   }
 ]
 EOF
 
-   ${PIP_PATH} install mercurial-4.7.tar.gz
+   ${PIP_PATH} install mercurial-4.7.1.tar.gz
 else
     echo "Do not know how to install Mercurial on this OS"
     exit 1
 fi
 
 chmod 644 /usr/local/mercurial/robustcheckout.py
 
 cat >/etc/mercurial/hgrc.d/cacerts.rc <<EOF
copy from toolkit/components/reader/Readability.js
copy to toolkit/components/reader/Readability-readerable.js
--- a/toolkit/components/reader/Readability.js
+++ b/toolkit/components/reader/Readability-readerable.js
@@ -1,16 +1,10 @@
-/*eslint-env es6:false*/
-/*
- * DO NOT MODIFY THIS FILE DIRECTLY!
- *
- * This is a shared library that is maintained in an external repo:
- * https://github.com/mozilla/readability
- */
-
+/* eslint-env es6:false */
+/* globals exports */
 /*
  * Copyright (c) 2010 Arc90 Inc
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
@@ -22,1814 +16,81 @@
  * limitations under the License.
  */
 
 /*
  * This code is heavily based on Arc90's readability.js (1.7.1) script
  * available at: http://code.google.com/p/arc90labs-readability
  */
 
-/**
- * Public constructor.
- * @param {HTMLDocument} doc     The document to parse.
- * @param {Object}       options The options object.
- */
-function Readability(doc, options) {
-  // In some older versions, people passed a URI as the first argument. Cope:
-  if (options && options.documentElement) {
-    doc = options;
-    options = arguments[2];
-  } else if (!doc || !doc.documentElement) {
-    throw new Error("First argument to Readability constructor should be a document object.");
-  }
-  options = options || {};
-
-  this._doc = doc;
-  this._articleTitle = null;
-  this._articleByline = null;
-  this._articleDir = null;
-  this._attempts = [];
-
-  // Configurable options
-  this._debug = !!options.debug;
-  this._maxElemsToParse = options.maxElemsToParse || this.DEFAULT_MAX_ELEMS_TO_PARSE;
-  this._nbTopCandidates = options.nbTopCandidates || this.DEFAULT_N_TOP_CANDIDATES;
-  this._charThreshold = options.charThreshold || this.DEFAULT_CHAR_THRESHOLD;
-  this._classesToPreserve = this.CLASSES_TO_PRESERVE.concat(options.classesToPreserve || []);
+var REGEXPS = {
+  // NOTE: These two regular expressions are duplicated in
+  // Readability.js. Please keep both copies in sync.
+  unlikelyCandidates: /-ad-|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
+  okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
+};
 
-  // Start with all flags set
-  this._flags = this.FLAG_STRIP_UNLIKELYS |
-                this.FLAG_WEIGHT_CLASSES |
-                this.FLAG_CLEAN_CONDITIONALLY;
-
-  var logEl;
-
-  // Control whether log messages are sent to the console
-  if (this._debug) {
-    logEl = function(e) {
-      var rv = e.nodeName + " ";
-      if (e.nodeType == e.TEXT_NODE) {
-        return rv + '("' + e.textContent + '")';
-      }
-      var classDesc = e.className && ("." + e.className.replace(/ /g, "."));
-      var elDesc = "";
-      if (e.id)
-        elDesc = "(#" + e.id + classDesc + ")";
-      else if (classDesc)
-        elDesc = "(" + classDesc + ")";
-      return rv + elDesc;
-    };
-    this.log = function () {
-      if (typeof dump !== "undefined") {
-        var msg = Array.prototype.map.call(arguments, function(x) {
-          return (x && x.nodeName) ? logEl(x) : x;
-        }).join(" ");
-        dump("Reader: (Readability) " + msg + "\n");
-      } else if (typeof console !== "undefined") {
-        var args = ["Reader: (Readability) "].concat(arguments);
-        console.log.apply(console, args);
-      }
-    };
-  } else {
-    this.log = function () {};
-  }
+function isNodeVisible(node) {
+  return node.style.display != "none" && !node.hasAttribute("hidden");
 }
 
-Readability.prototype = {
-  FLAG_STRIP_UNLIKELYS: 0x1,
-  FLAG_WEIGHT_CLASSES: 0x2,
-  FLAG_CLEAN_CONDITIONALLY: 0x4,
-
-  // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
-  ELEMENT_NODE: 1,
-  TEXT_NODE: 3,
-
-  // Max number of nodes supported by this parser. Default: 0 (no limit)
-  DEFAULT_MAX_ELEMS_TO_PARSE: 0,
-
-  // The number of top candidates to consider when analysing how
-  // tight the competition is among candidates.
-  DEFAULT_N_TOP_CANDIDATES: 5,
-
-  // Element tags to score by default.
-  DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),
-
-  // The default number of chars an article must have in order to return a result
-  DEFAULT_CHAR_THRESHOLD: 500,
-
-  // All of the regular expressions in use within readability.
-  // Defined up here so we don't instantiate them repeatedly in loops.
-  REGEXPS: {
-    unlikelyCandidates: /-ad-|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
-    okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
-    positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,
-    negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
-    extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
-    byline: /byline|author|dateline|writtenby|p-author/i,
-    replaceFonts: /<(\/?)font[^>]*>/gi,
-    normalize: /\s{2,}/g,
-    videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,
-    nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
-    prevLink: /(prev|earl|old|new|<|«)/i,
-    whitespace: /^\s*$/,
-    hasContent: /\S$/,
-  },
-
-  DIV_TO_P_ELEMS: [ "A", "BLOCKQUOTE", "DL", "DIV", "IMG", "OL", "P", "PRE", "TABLE", "UL", "SELECT" ],
-
-  ALTER_TO_DIV_EXCEPTIONS: ["DIV", "ARTICLE", "SECTION", "P"],
-
-  PRESENTATIONAL_ATTRIBUTES: [ "align", "background", "bgcolor", "border", "cellpadding", "cellspacing", "frame", "hspace", "rules", "style", "valign", "vspace" ],
-
-  DEPRECATED_SIZE_ATTRIBUTE_ELEMS: [ "TABLE", "TH", "TD", "HR", "PRE" ],
-
-  // The commented out elements qualify as phrasing content but tend to be
-  // removed by readability when put into paragraphs, so we ignore them here.
-  PHRASING_ELEMS: [
-    // "CANVAS", "IFRAME", "SVG", "VIDEO",
-    "ABBR", "AUDIO", "B", "BDO", "BR", "BUTTON", "CITE", "CODE", "DATA",
-    "DATALIST", "DFN", "EM", "EMBED", "I", "IMG", "INPUT", "KBD", "LABEL",
-    "MARK", "MATH", "METER", "NOSCRIPT", "OBJECT", "OUTPUT", "PROGRESS", "Q",
-    "RUBY", "SAMP", "SCRIPT", "SELECT", "SMALL", "SPAN", "STRONG", "SUB",
-    "SUP", "TEXTAREA", "TIME", "VAR", "WBR"
-  ],
-
-  // These are the classes that readability sets itself.
-  CLASSES_TO_PRESERVE: [ "page" ],
-
-  /**
-   * Run any post-process modifications to article content as necessary.
-   *
-   * @param Element
-   * @return void
-  **/
-  _postProcessContent: function(articleContent) {
-    // Readability cannot open relative uris so we convert them to absolute uris.
-    this._fixRelativeUris(articleContent);
-
-    // Remove classes.
-    this._cleanClasses(articleContent);
-  },
-
-  /**
-   * Iterates over a NodeList, calls `filterFn` for each node and removes node
-   * if function returned `true`.
-   *
-   * If function is not passed, removes all the nodes in node list.
-   *
-   * @param NodeList nodeList The nodes to operate on
-   * @param Function filterFn the function to use as a filter
-   * @return void
-   */
-  _removeNodes: function(nodeList, filterFn) {
-    for (var i = nodeList.length - 1; i >= 0; i--) {
-      var node = nodeList[i];
-      var parentNode = node.parentNode;
-      if (parentNode) {
-        if (!filterFn || filterFn.call(this, node, i, nodeList)) {
-          parentNode.removeChild(node);
-        }
-      }
-    }
-  },
-
-  /**
-   * Iterates over a NodeList, and calls _setNodeTag for each node.
-   *
-   * @param NodeList nodeList The nodes to operate on
-   * @param String newTagName the new tag name to use
-   * @return void
-   */
-  _replaceNodeTags: function(nodeList, newTagName) {
-    for (var i = nodeList.length - 1; i >= 0; i--) {
-      var node = nodeList[i];
-      this._setNodeTag(node, newTagName);
-    }
-  },
-
-  /**
-   * Iterate over a NodeList, which doesn't natively fully implement the Array
-   * interface.
-   *
-   * For convenience, the current object context is applied to the provided
-   * iterate function.
-   *
-   * @param  NodeList nodeList The NodeList.
-   * @param  Function fn       The iterate function.
-   * @return void
-   */
-  _forEachNode: function(nodeList, fn) {
-    Array.prototype.forEach.call(nodeList, fn, this);
-  },
-
-  /**
-   * Iterate over a NodeList, return true if any of the provided iterate
-   * function calls returns true, false otherwise.
-   *
-   * For convenience, the current object context is applied to the
-   * provided iterate function.
-   *
-   * @param  NodeList nodeList The NodeList.
-   * @param  Function fn       The iterate function.
-   * @return Boolean
-   */
-  _someNode: function(nodeList, fn) {
-    return Array.prototype.some.call(nodeList, fn, this);
-  },
+/**
+ * Decides whether or not the document is reader-able without parsing the whole thing.
+ *
+ * @return boolean Whether or not we suspect Readability.parse() will suceeed at returning an article object.
+ */
+function isProbablyReaderable(doc, isVisible) {
+  if (!isVisible) {
+    isVisible = isNodeVisible;
+  }
 
-  /**
-   * Iterate over a NodeList, return true if all of the provided iterate
-   * function calls return true, false otherwise.
-   *
-   * For convenience, the current object context is applied to the
-   * provided iterate function.
-   *
-   * @param  NodeList nodeList The NodeList.
-   * @param  Function fn       The iterate function.
-   * @return Boolean
-   */
-  _everyNode: function(nodeList, fn) {
-    return Array.prototype.every.call(nodeList, fn, this);
-  },
-
-  /**
-   * Concat all nodelists passed as arguments.
-   *
-   * @return ...NodeList
-   * @return Array
-   */
-  _concatNodeLists: function() {
-    var slice = Array.prototype.slice;
-    var args = slice.call(arguments);
-    var nodeLists = args.map(function(list) {
-      return slice.call(list);
-    });
-    return Array.prototype.concat.apply([], nodeLists);
-  },
-
-  _getAllNodesWithTag: function(node, tagNames) {
-    if (node.querySelectorAll) {
-      return node.querySelectorAll(tagNames.join(","));
-    }
-    return [].concat.apply([], tagNames.map(function(tag) {
-      var collection = node.getElementsByTagName(tag);
-      return Array.isArray(collection) ? collection : Array.from(collection);
-    }));
-  },
-
-  /**
-   * Removes the class="" attribute from every element in the given
-   * subtree, except those that match CLASSES_TO_PRESERVE and
-   * the classesToPreserve array from the options object.
-   *
-   * @param Element
-   * @return void
-   */
-  _cleanClasses: function(node) {
-    var classesToPreserve = this._classesToPreserve;
-    var className = (node.getAttribute("class") || "")
-      .split(/\s+/)
-      .filter(function(cls) {
-        return classesToPreserve.indexOf(cls) != -1;
-      })
-      .join(" ");
-
-    if (className) {
-      node.setAttribute("class", className);
-    } else {
-      node.removeAttribute("class");
-    }
-
-    for (node = node.firstElementChild; node; node = node.nextElementSibling) {
-      this._cleanClasses(node);
-    }
-  },
-
-  /**
-   * Converts each <a> and <img> uri in the given element to an absolute URI,
-   * ignoring #ref URIs.
-   *
-   * @param Element
-   * @return void
-   */
-  _fixRelativeUris: function(articleContent) {
-    var baseURI = this._doc.baseURI;
-    var documentURI = this._doc.documentURI;
-    function toAbsoluteURI(uri) {
-      // Leave hash links alone if the base URI matches the document URI:
-      if (baseURI == documentURI && uri.charAt(0) == "#") {
-        return uri;
-      }
-      // Otherwise, resolve against base URI:
-      try {
-        return new URL(uri, baseURI).href;
-      } catch (ex) {
-        // Something went wrong, just return the original:
-      }
-      return uri;
-    }
-
-    var links = articleContent.getElementsByTagName("a");
-    this._forEachNode(links, function(link) {
-      var href = link.getAttribute("href");
-      if (href) {
-        // Replace links with javascript: URIs with text content, since
-        // they won't work after scripts have been removed from the page.
-        if (href.indexOf("javascript:") === 0) {
-          var text = this._doc.createTextNode(link.textContent);
-          link.parentNode.replaceChild(text, link);
-        } else {
-          link.setAttribute("href", toAbsoluteURI(href));
-        }
-      }
-    });
-
-    var imgs = articleContent.getElementsByTagName("img");
-    this._forEachNode(imgs, function(img) {
-      var src = img.getAttribute("src");
-      if (src) {
-        img.setAttribute("src", toAbsoluteURI(src));
-      }
-    });
-  },
-
-  /**
-   * Get the article title as an H1.
-   *
-   * @return void
-   **/
-  _getArticleTitle: function() {
-    var doc = this._doc;
-    var curTitle = "";
-    var origTitle = "";
-
-    try {
-      curTitle = origTitle = doc.title.trim();
-
-      // If they had an element with id "title" in their HTML
-      if (typeof curTitle !== "string")
-        curTitle = origTitle = this._getInnerText(doc.getElementsByTagName("title")[0]);
-    } catch (e) {/* ignore exceptions setting the title. */}
-
-    var titleHadHierarchicalSeparators = false;
-    function wordCount(str) {
-      return str.split(/\s+/).length;
-    }
-
-    // If there's a separator in the title, first remove the final part
-    if ((/ [\|\-\\\/>»] /).test(curTitle)) {
-      titleHadHierarchicalSeparators = / [\\\/>»] /.test(curTitle);
-      curTitle = origTitle.replace(/(.*)[\|\-\\\/>»] .*/gi, "$1");
-
-      // If the resulting title is too short (3 words or fewer), remove
-      // the first part instead:
-      if (wordCount(curTitle) < 3)
-        curTitle = origTitle.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi, "$1");
-    } else if (curTitle.indexOf(": ") !== -1) {
-      // Check if we have an heading containing this exact string, so we
-      // could assume it's the full title.
-      var headings = this._concatNodeLists(
-        doc.getElementsByTagName("h1"),
-        doc.getElementsByTagName("h2")
-      );
-      var trimmedTitle = curTitle.trim();
-      var match = this._someNode(headings, function(heading) {
-        return heading.textContent.trim() === trimmedTitle;
-      });
-
-      // If we don't, let's extract the title out of the original title string.
-      if (!match) {
-        curTitle = origTitle.substring(origTitle.lastIndexOf(":") + 1);
+  var nodes = doc.querySelectorAll("p, pre");
 
-        // If the title is now too short, try the first colon instead:
-        if (wordCount(curTitle) < 3) {
-          curTitle = origTitle.substring(origTitle.indexOf(":") + 1);
-          // But if we have too many words before the colon there's something weird
-          // with the titles and the H tags so let's just use the original title instead
-        } else if (wordCount(origTitle.substr(0, origTitle.indexOf(":"))) > 5) {
-          curTitle = origTitle;
-        }
-      }
-    } else if (curTitle.length > 150 || curTitle.length < 15) {
-      var hOnes = doc.getElementsByTagName("h1");
-
-      if (hOnes.length === 1)
-        curTitle = this._getInnerText(hOnes[0]);
-    }
-
-    curTitle = curTitle.trim();
-    // If we now have 4 words or fewer as our title, and either no
-    // 'hierarchical' separators (\, /, > or ») were found in the original
-    // title or we decreased the number of words by more than 1 word, use
-    // the original title.
-    var curTitleWordCount = wordCount(curTitle);
-    if (curTitleWordCount <= 4 &&
-        (!titleHadHierarchicalSeparators ||
-         curTitleWordCount != wordCount(origTitle.replace(/[\|\-\\\/>»]+/g, "")) - 1)) {
-      curTitle = origTitle;
-    }
-
-    return curTitle;
-  },
-
-  /**
-   * Prepare the HTML document for readability to scrape it.
-   * This includes things like stripping javascript, CSS, and handling terrible markup.
-   *
-   * @return void
-   **/
-  _prepDocument: function() {
-    var doc = this._doc;
-
-    // Remove all style tags in head
-    this._removeNodes(doc.getElementsByTagName("style"));
-
-    if (doc.body) {
-      this._replaceBrs(doc.body);
-    }
-
-    this._replaceNodeTags(doc.getElementsByTagName("font"), "SPAN");
-  },
-
-  /**
-   * Finds the next element, starting from the given node, and ignoring
-   * whitespace in between. If the given node is an element, the same node is
-   * returned.
-   */
-  _nextElement: function (node) {
-    var next = node;
-    while (next
-        && (next.nodeType != this.ELEMENT_NODE)
-        && this.REGEXPS.whitespace.test(next.textContent)) {
-      next = next.nextSibling;
-    }
-    return next;
-  },
-
-  /**
-   * Replaces 2 or more successive <br> elements with a single <p>.
-   * Whitespace between <br> elements are ignored. For example:
-   *   <div>foo<br>bar<br> <br><br>abc</div>
-   * will become:
-   *   <div>foo<br>bar<p>abc</p></div>
-   */
-  _replaceBrs: function (elem) {
-    this._forEachNode(this._getAllNodesWithTag(elem, ["br"]), function(br) {
-      var next = br.nextSibling;
-
-      // Whether 2 or more <br> elements have been found and replaced with a
-      // <p> block.
-      var replaced = false;
-
-      // If we find a <br> chain, remove the <br>s until we hit another element
-      // or non-whitespace. This leaves behind the first <br> in the chain
-      // (which will be replaced with a <p> later).
-      while ((next = this._nextElement(next)) && (next.tagName == "BR")) {
-        replaced = true;
-        var brSibling = next.nextSibling;
-        next.parentNode.removeChild(next);
-        next = brSibling;
-      }
-
-      // If we removed a <br> chain, replace the remaining <br> with a <p>. Add
-      // all sibling nodes as children of the <p> until we hit another <br>
-      // chain.
-      if (replaced) {
-        var p = this._doc.createElement("p");
-        br.parentNode.replaceChild(p, br);
-
-        next = p.nextSibling;
-        while (next) {
-          // If we've hit another <br><br>, we're done adding children to this <p>.
-          if (next.tagName == "BR") {
-            var nextElem = this._nextElement(next.nextSibling);
-            if (nextElem && nextElem.tagName == "BR")
-              break;
-          }
-
-          if (!this._isPhrasingContent(next))
-            break;
-
-          // Otherwise, make this node a child of the new <p>.
-          var sibling = next.nextSibling;
-          p.appendChild(next);
-          next = sibling;
-        }
-
-        while (p.lastChild && this._isWhitespace(p.lastChild)) {
-          p.removeChild(p.lastChild);
-        }
-
-        if (p.parentNode.tagName === "P")
-          this._setNodeTag(p.parentNode, "DIV");
-      }
+  // Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
+  // Some articles' DOM structures might look like
+  // <div>
+  //   Sentences<br>
+  //   <br>
+  //   Sentences<br>
+  // </div>
+  var brNodes = doc.querySelectorAll("div > br");
+  if (brNodes.length) {
+    var set = new Set(nodes);
+    [].forEach.call(brNodes, function(node) {
+      set.add(node.parentNode);
     });
-  },
-
-  _setNodeTag: function (node, tag) {
-    this.log("_setNodeTag", node, tag);
-    if (node.__JSDOMParser__) {
-      node.localName = tag.toLowerCase();
-      node.tagName = tag.toUpperCase();
-      return node;
-    }
-
-    var replacement = node.ownerDocument.createElement(tag);
-    while (node.firstChild) {
-      replacement.appendChild(node.firstChild);
-    }
-    node.parentNode.replaceChild(replacement, node);
-    if (node.readability)
-      replacement.readability = node.readability;
-
-    for (var i = 0; i < node.attributes.length; i++) {
-      replacement.setAttribute(node.attributes[i].name, node.attributes[i].value);
-    }
-    return replacement;
-  },
-
-  /**
-   * Prepare the article node for display. Clean out any inline styles,
-   * iframes, forms, strip extraneous <p> tags, etc.
-   *
-   * @param Element
-   * @return void
-   **/
-  _prepArticle: function(articleContent) {
-    this._cleanStyles(articleContent);
+    nodes = Array.from(set);
+  }
 
-    // Check for data tables before we continue, to avoid removing items in
-    // those tables, which will often be isolated even though they're
-    // visually linked to other content-ful elements (text, images, etc.).
-    this._markDataTables(articleContent);
-
-    // Clean out junk from the article content
-    this._cleanConditionally(articleContent, "form");
-    this._cleanConditionally(articleContent, "fieldset");
-    this._clean(articleContent, "object");
-    this._clean(articleContent, "embed");
-    this._clean(articleContent, "h1");
-    this._clean(articleContent, "footer");
-    this._clean(articleContent, "link");
-    this._clean(articleContent, "aside");
-
-    // Clean out elements have "share" in their id/class combinations from final top candidates,
-    // which means we don't remove the top candidates even they have "share".
-    this._forEachNode(articleContent.children, function(topCandidate) {
-      this._cleanMatchedNodes(topCandidate, /share/);
-    });
-
-    // If there is only one h2 and its text content substantially equals article title,
-    // they are probably using it as a header and not a subheader,
-    // so remove it since we already extract the title separately.
-    var h2 = articleContent.getElementsByTagName("h2");
-    if (h2.length === 1) {
-      var lengthSimilarRate = (h2[0].textContent.length - this._articleTitle.length) / this._articleTitle.length;
-      if (Math.abs(lengthSimilarRate) < 0.5) {
-        var titlesMatch = false;
-        if (lengthSimilarRate > 0) {
-          titlesMatch = h2[0].textContent.includes(this._articleTitle);
-        } else {
-          titlesMatch = this._articleTitle.includes(h2[0].textContent);
-        }
-        if (titlesMatch) {
-          this._clean(articleContent, "h2");
-        }
-      }
-    }
-
-    this._clean(articleContent, "iframe");
-    this._clean(articleContent, "input");
-    this._clean(articleContent, "textarea");
-    this._clean(articleContent, "select");
-    this._clean(articleContent, "button");
-    this._cleanHeaders(articleContent);
-
-    // Do these last as the previous stuff may have removed junk
-    // that will affect these
-    this._cleanConditionally(articleContent, "table");
-    this._cleanConditionally(articleContent, "ul");
-    this._cleanConditionally(articleContent, "div");
-
-    // Remove extra paragraphs
-    this._removeNodes(articleContent.getElementsByTagName("p"), function (paragraph) {
-      var imgCount = paragraph.getElementsByTagName("img").length;
-      var embedCount = paragraph.getElementsByTagName("embed").length;
-      var objectCount = paragraph.getElementsByTagName("object").length;
-      // At this point, nasty iframes have been removed, only remain embedded video ones.
-      var iframeCount = paragraph.getElementsByTagName("iframe").length;
-      var totalCount = imgCount + embedCount + objectCount + iframeCount;
-
-      return totalCount === 0 && !this._getInnerText(paragraph, false);
-    });
-
-    this._forEachNode(this._getAllNodesWithTag(articleContent, ["br"]), function(br) {
-      var next = this._nextElement(br.nextSibling);
-      if (next && next.tagName == "P")
-        br.parentNode.removeChild(br);
-    });
+  var score = 0;
+  // This is a little cheeky, we use the accumulator 'score' to decide what to return from
+  // this callback:
+  return [].some.call(nodes, function(node) {
+    if (!isVisible(node))
+      return false;
 
-    // Remove single-cell tables
-    this._forEachNode(this._getAllNodesWithTag(articleContent, ["table"]), function(table) {
-      var tbody = this._hasSingleTagInsideElement(table, "TBODY") ? table.firstElementChild : table;
-      if (this._hasSingleTagInsideElement(tbody, "TR")) {
-        var row = tbody.firstElementChild;
-        if (this._hasSingleTagInsideElement(row, "TD")) {
-          var cell = row.firstElementChild;
-          cell = this._setNodeTag(cell, this._everyNode(cell.childNodes, this._isPhrasingContent) ? "P" : "DIV");
-          table.parentNode.replaceChild(cell, table);
-        }
-      }
-    });
-  },
-
-  /**
-   * Initialize a node with the readability object. Also checks the
-   * className/id for special names to add to its score.
-   *
-   * @param Element
-   * @return void
-  **/
-  _initializeNode: function(node) {
-    node.readability = {"contentScore": 0};
-
-    switch (node.tagName) {
-      case "DIV":
-        node.readability.contentScore += 5;
-        break;
-
-      case "PRE":
-      case "TD":
-      case "BLOCKQUOTE":
-        node.readability.contentScore += 3;
-        break;
-
-      case "ADDRESS":
-      case "OL":
-      case "UL":
-      case "DL":
-      case "DD":
-      case "DT":
-      case "LI":
-      case "FORM":
-        node.readability.contentScore -= 3;
-        break;
-
-      case "H1":
-      case "H2":
-      case "H3":
-      case "H4":
-      case "H5":
-      case "H6":
-      case "TH":
-        node.readability.contentScore -= 5;
-        break;
-    }
-
-    node.readability.contentScore += this._getClassWeight(node);
-  },
-
-  _removeAndGetNext: function(node) {
-    var nextNode = this._getNextNode(node, true);
-    node.parentNode.removeChild(node);
-    return nextNode;
-  },
-
-  /**
-   * Traverse the DOM from node to node, starting at the node passed in.
-   * Pass true for the second parameter to indicate this node itself
-   * (and its kids) are going away, and we want the next node over.
-   *
-   * Calling this in a loop will traverse the DOM depth-first.
-   */
-  _getNextNode: function(node, ignoreSelfAndKids) {
-    // First check for kids if those aren't being ignored
-    if (!ignoreSelfAndKids && node.firstElementChild) {
-      return node.firstElementChild;
-    }
-    // Then for siblings...
-    if (node.nextElementSibling) {
-      return node.nextElementSibling;
-    }
-    // And finally, move up the parent chain *and* find a sibling
-    // (because this is depth-first traversal, we will have already
-    // seen the parent nodes themselves).
-    do {
-      node = node.parentNode;
-    } while (node && !node.nextElementSibling);
-    return node && node.nextElementSibling;
-  },
-
-  _checkByline: function(node, matchString) {
-    if (this._articleByline) {
+    var matchString = node.className + " " + node.id;
+    if (REGEXPS.unlikelyCandidates.test(matchString) &&
+        !REGEXPS.okMaybeItsACandidate.test(matchString)) {
       return false;
     }
 
-    if (node.getAttribute !== undefined) {
-      var rel = node.getAttribute("rel");
-    }
-
-    if ((rel === "author" || this.REGEXPS.byline.test(matchString)) && this._isValidByline(node.textContent)) {
-      this._articleByline = node.textContent.trim();
-      return true;
-    }
-
-    return false;
-  },
-
-  _getNodeAncestors: function(node, maxDepth) {
-    maxDepth = maxDepth || 0;
-    var i = 0, ancestors = [];
-    while (node.parentNode) {
-      ancestors.push(node.parentNode);
-      if (maxDepth && ++i === maxDepth)
-        break;
-      node = node.parentNode;
-    }
-    return ancestors;
-  },
-
-  /***
-   * grabArticle - Using a variety of metrics (content score, classname, element types), find the content that is
-   *         most likely to be the stuff a user wants to read. Then return it wrapped up in a div.
-   *
-   * @param page a document to run upon. Needs to be a full document, complete with body.
-   * @return Element
-  **/
-  _grabArticle: function (page) {
-    this.log("**** grabArticle ****");
-    var doc = this._doc;
-    var isPaging = (page !== null ? true: false);
-    page = page ? page : this._doc.body;
-
-    // We can't grab an article if we don't have a page!
-    if (!page) {
-      this.log("No body found in document. Abort.");
-      return null;
+    if (node.matches("li p")) {
+      return false;
     }
 
-    var pageCacheHtml = page.innerHTML;
-
-    while (true) {
-      var stripUnlikelyCandidates = this._flagIsActive(this.FLAG_STRIP_UNLIKELYS);
-
-      // First, node prepping. Trash nodes that look cruddy (like ones with the
-      // class name "comment", etc), and turn divs into P tags where they have been
-      // used inappropriately (as in, where they contain no other block level elements.)
-      var elementsToScore = [];
-      var node = this._doc.documentElement;
-
-      while (node) {
-        var matchString = node.className + " " + node.id;
-
-        if (!this._isProbablyVisible(node)) {
-          this.log("Removing hidden node - " + matchString);
-          node = this._removeAndGetNext(node);
-          continue;
-        }
-
-        // Check to see if this node is a byline, and remove it if it is.
-        if (this._checkByline(node, matchString)) {
-          node = this._removeAndGetNext(node);
-          continue;
-        }
-
-        // Remove unlikely candidates
-        if (stripUnlikelyCandidates) {
-          if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
-              !this.REGEXPS.okMaybeItsACandidate.test(matchString) &&
-              node.tagName !== "BODY" &&
-              node.tagName !== "A") {
-            this.log("Removing unlikely candidate - " + matchString);
-            node = this._removeAndGetNext(node);
-            continue;
-          }
-        }
-
-        // Remove DIV, SECTION, and HEADER nodes without any content(e.g. text, image, video, or iframe).
-        if ((node.tagName === "DIV" || node.tagName === "SECTION" || node.tagName === "HEADER" ||
-             node.tagName === "H1" || node.tagName === "H2" || node.tagName === "H3" ||
-             node.tagName === "H4" || node.tagName === "H5" || node.tagName === "H6") &&
-            this._isElementWithoutContent(node)) {
-          node = this._removeAndGetNext(node);
-          continue;
-        }
-
-        if (this.DEFAULT_TAGS_TO_SCORE.indexOf(node.tagName) !== -1) {
-          elementsToScore.push(node);
-        }
-
-        // Turn all divs that don't have children block level elements into p's
-        if (node.tagName === "DIV") {
-          // Put phrasing content into paragraphs.
-          var p = null;
-          var childNode = node.firstChild;
-          while (childNode) {
-            var nextSibling = childNode.nextSibling;
-            if (this._isPhrasingContent(childNode)) {
-              if (p !== null) {
-                p.appendChild(childNode);
-              } else if (!this._isWhitespace(childNode)) {
-                p = doc.createElement("p");
-                node.replaceChild(p, childNode);
-                p.appendChild(childNode);
-              }
-            } else if (p !== null) {
-              while (p.lastChild && this._isWhitespace(p.lastChild)) {
-                p.removeChild(p.lastChild);
-              }
-              p = null;
-            }
-            childNode = nextSibling;
-          }
-
-          // Sites like http://mobile.slate.com encloses each paragraph with a DIV
-          // element. DIVs with only a P element inside and no text content can be
-          // safely converted into plain P elements to avoid confusing the scoring
-          // algorithm with DIVs with are, in practice, paragraphs.
-          if (this._hasSingleTagInsideElement(node, "P") && this._getLinkDensity(node) < 0.25) {
-            var newNode = node.children[0];
-            node.parentNode.replaceChild(newNode, node);
-            node = newNode;
-            elementsToScore.push(node);
-          } else if (!this._hasChildBlockElement(node)) {
-            node = this._setNodeTag(node, "P");
-            elementsToScore.push(node);
-          }
-        }
-        node = this._getNextNode(node);
-      }
-
-      /**
-       * Loop through all paragraphs, and assign a score to them based on how content-y they look.
-       * Then add their score to their parent node.
-       *
-       * A score is determined by things like number of commas, class names, etc. Maybe eventually link density.
-      **/
-      var candidates = [];
-      this._forEachNode(elementsToScore, function(elementToScore) {
-        if (!elementToScore.parentNode || typeof(elementToScore.parentNode.tagName) === "undefined")
-          return;
-
-        // If this paragraph is less than 25 characters, don't even count it.
-        var innerText = this._getInnerText(elementToScore);
-        if (innerText.length < 25)
-          return;
-
-        // Exclude nodes with no ancestor.
-        var ancestors = this._getNodeAncestors(elementToScore, 3);
-        if (ancestors.length === 0)
-          return;
-
-        var contentScore = 0;
-
-        // Add a point for the paragraph itself as a base.
-        contentScore += 1;
-
-        // Add points for any commas within this paragraph.
-        contentScore += innerText.split(",").length;
-
-        // For every 100 characters in this paragraph, add another point. Up to 3 points.
-        contentScore += Math.min(Math.floor(innerText.length / 100), 3);
-
-        // Initialize and score ancestors.
-        this._forEachNode(ancestors, function(ancestor, level) {
-          if (!ancestor.tagName || !ancestor.parentNode || typeof(ancestor.parentNode.tagName) === "undefined")
-            return;
-
-          if (typeof(ancestor.readability) === "undefined") {
-            this._initializeNode(ancestor);
-            candidates.push(ancestor);
-          }
-
-          // Node score divider:
-          // - parent:             1 (no division)
-          // - grandparent:        2
-          // - great grandparent+: ancestor level * 3
-          if (level === 0)
-            var scoreDivider = 1;
-          else if (level === 1)
-            scoreDivider = 2;
-          else
-            scoreDivider = level * 3;
-          ancestor.readability.contentScore += contentScore / scoreDivider;
-        });
-      });
-
-      // After we've calculated scores, loop through all of the possible
-      // candidate nodes we found and find the one with the highest score.
-      var topCandidates = [];
-      for (var c = 0, cl = candidates.length; c < cl; c += 1) {
-        var candidate = candidates[c];
-
-        // Scale the final candidates score based on link density. Good content
-        // should have a relatively small link density (5% or less) and be mostly
-        // unaffected by this operation.
-        var candidateScore = candidate.readability.contentScore * (1 - this._getLinkDensity(candidate));
-        candidate.readability.contentScore = candidateScore;
-
-        this.log("Candidate:", candidate, "with score " + candidateScore);
-
-        for (var t = 0; t < this._nbTopCandidates; t++) {
-          var aTopCandidate = topCandidates[t];
-
-          if (!aTopCandidate || candidateScore > aTopCandidate.readability.contentScore) {
-            topCandidates.splice(t, 0, candidate);
-            if (topCandidates.length > this._nbTopCandidates)
-              topCandidates.pop();
-            break;
-          }
-        }
-      }
-
-      var topCandidate = topCandidates[0] || null;
-      var neededToCreateTopCandidate = false;
-      var parentOfTopCandidate;
-
-      // If we still have no top candidate, just use the body as a last resort.
-      // We also have to copy the body node so it is something we can modify.
-      if (topCandidate === null || topCandidate.tagName === "BODY") {
-        // Move all of the page's children into topCandidate
-        topCandidate = doc.createElement("DIV");
-        neededToCreateTopCandidate = true;
-        // Move everything (not just elements, also text nodes etc.) into the container
-        // so we even include text directly in the body:
-        var kids = page.childNodes;
-        while (kids.length) {
-          this.log("Moving child out:", kids[0]);
-          topCandidate.appendChild(kids[0]);
-        }
-
-        page.appendChild(topCandidate);
-
-        this._initializeNode(topCandidate);
-      } else if (topCandidate) {
-        // Find a better top candidate node if it contains (at least three) nodes which belong to `topCandidates` array
-        // and whose scores are quite closed with current `topCandidate` node.
-        var alternativeCandidateAncestors = [];
-        for (var i = 1; i < topCandidates.length; i++) {
-          if (topCandidates[i].readability.contentScore / topCandidate.readability.contentScore >= 0.75) {
-            alternativeCandidateAncestors.push(this._getNodeAncestors(topCandidates[i]));
-          }
-        }
-        var MINIMUM_TOPCANDIDATES = 3;
-        if (alternativeCandidateAncestors.length >= MINIMUM_TOPCANDIDATES) {
-          parentOfTopCandidate = topCandidate.parentNode;
-          while (parentOfTopCandidate.tagName !== "BODY") {
-            var listsContainingThisAncestor = 0;
-            for (var ancestorIndex = 0; ancestorIndex < alternativeCandidateAncestors.length && listsContainingThisAncestor < MINIMUM_TOPCANDIDATES; ancestorIndex++) {
-              listsContainingThisAncestor += Number(alternativeCandidateAncestors[ancestorIndex].includes(parentOfTopCandidate));
-            }
-            if (listsContainingThisAncestor >= MINIMUM_TOPCANDIDATES) {
-              topCandidate = parentOfTopCandidate;
-              break;
-            }
-            parentOfTopCandidate = parentOfTopCandidate.parentNode;
-          }
-        }
-        if (!topCandidate.readability) {
-          this._initializeNode(topCandidate);
-        }
-
-        // Because of our bonus system, parents of candidates might have scores
-        // themselves. They get half of the node. There won't be nodes with higher
-        // scores than our topCandidate, but if we see the score going *up* in the first
-        // few steps up the tree, that's a decent sign that there might be more content
-        // lurking in other places that we want to unify in. The sibling stuff
-        // below does some of that - but only if we've looked high enough up the DOM
-        // tree.
-        parentOfTopCandidate = topCandidate.parentNode;
-        var lastScore = topCandidate.readability.contentScore;
-        // The scores shouldn't get too low.
-        var scoreThreshold = lastScore / 3;
-        while (parentOfTopCandidate.tagName !== "BODY") {
-          if (!parentOfTopCandidate.readability) {
-            parentOfTopCandidate = parentOfTopCandidate.parentNode;
-            continue;
-          }
-          var parentScore = parentOfTopCandidate.readability.contentScore;
-          if (parentScore < scoreThreshold)
-            break;
-          if (parentScore > lastScore) {
-            // Alright! We found a better parent to use.
-            topCandidate = parentOfTopCandidate;
-            break;
-          }
-          lastScore = parentOfTopCandidate.readability.contentScore;
-          parentOfTopCandidate = parentOfTopCandidate.parentNode;
-        }
-
-        // If the top candidate is the only child, use parent instead. This will help sibling
-        // joining logic when adjacent content is actually located in parent's sibling node.
-        parentOfTopCandidate = topCandidate.parentNode;
-        while (parentOfTopCandidate.tagName != "BODY" && parentOfTopCandidate.children.length == 1) {
-          topCandidate = parentOfTopCandidate;
-          parentOfTopCandidate = topCandidate.parentNode;
-        }
-        if (!topCandidate.readability) {
-          this._initializeNode(topCandidate);
-        }
-      }
-
-      // Now that we have the top candidate, look through its siblings for content
-      // that might also be related. Things like preambles, content split by ads
-      // that we removed, etc.
-      var articleContent = doc.createElement("DIV");
-      if (isPaging)
-        articleContent.id = "readability-content";
-
-      var siblingScoreThreshold = Math.max(10, topCandidate.readability.contentScore * 0.2);
-      // Keep potential top candidate's parent node to try to get text direction of it later.
-      parentOfTopCandidate = topCandidate.parentNode;
-      var siblings = parentOfTopCandidate.children;
-
-      for (var s = 0, sl = siblings.length; s < sl; s++) {
-        var sibling = siblings[s];
-        var append = false;
-
-        this.log("Looking at sibling node:", sibling, sibling.readability ? ("with score " + sibling.readability.contentScore) : "");
-        this.log("Sibling has score", sibling.readability ? sibling.readability.contentScore : "Unknown");
-
-        if (sibling === topCandidate) {
-          append = true;
-        } else {
-          var contentBonus = 0;
-
-          // Give a bonus if sibling nodes and top candidates have the example same classname
-          if (sibling.className === topCandidate.className && topCandidate.className !== "")
-            contentBonus += topCandidate.readability.contentScore * 0.2;
-
-          if (sibling.readability &&
-              ((sibling.readability.contentScore + contentBonus) >= siblingScoreThreshold)) {
-            append = true;
-          } else if (sibling.nodeName === "P") {
-            var linkDensity = this._getLinkDensity(sibling);
-            var nodeContent = this._getInnerText(sibling);
-            var nodeLength = nodeContent.length;
-
-            if (nodeLength > 80 && linkDensity < 0.25) {
-              append = true;
-            } else if (nodeLength < 80 && nodeLength > 0 && linkDensity === 0 &&
-                       nodeContent.search(/\.( |$)/) !== -1) {
-              append = true;
-            }
-          }
-        }
-
-        if (append) {
-          this.log("Appending node:", sibling);
-
-          if (this.ALTER_TO_DIV_EXCEPTIONS.indexOf(sibling.nodeName) === -1) {
-            // We have a node that isn't a common block level element, like a form or td tag.
-            // Turn it into a div so it doesn't get filtered out later by accident.
-            this.log("Altering sibling:", sibling, "to div.");
-
-            sibling = this._setNodeTag(sibling, "DIV");
-          }
-
-          articleContent.appendChild(sibling);
-          // siblings is a reference to the children array, and
-          // sibling is removed from the array when we call appendChild().
-          // As a result, we must revisit this index since the nodes
-          // have been shifted.
-          s -= 1;
-          sl -= 1;
-        }
-      }
-
-      if (this._debug)
-        this.log("Article content pre-prep: " + articleContent.innerHTML);
-      // So we have all of the content that we need. Now we clean it up for presentation.
-      this._prepArticle(articleContent);
-      if (this._debug)
-        this.log("Article content post-prep: " + articleContent.innerHTML);
-
-      if (neededToCreateTopCandidate) {
-        // We already created a fake div thing, and there wouldn't have been any siblings left
-        // for the previous loop, so there's no point trying to create a new div, and then
-        // move all the children over. Just assign IDs and class names here. No need to append
-        // because that already happened anyway.
-        topCandidate.id = "readability-page-1";
-        topCandidate.className = "page";
-      } else {
-        var div = doc.createElement("DIV");
-        div.id = "readability-page-1";
-        div.className = "page";
-        var children = articleContent.childNodes;
-        while (children.length) {
-          div.appendChild(children[0]);
-        }
-        articleContent.appendChild(div);
-      }
-
-      if (this._debug)
-        this.log("Article content after paging: " + articleContent.innerHTML);
-
-      var parseSuccessful = true;
-
-      // Now that we've gone through the full algorithm, check to see if
-      // we got any meaningful content. If we didn't, we may need to re-run
-      // grabArticle with different flags set. This gives us a higher likelihood of
-      // finding the content, and the sieve approach gives us a higher likelihood of
-      // finding the -right- content.
-      var textLength = this._getInnerText(articleContent, true).length;
-      if (textLength < this._charThreshold) {
-        parseSuccessful = false;
-        page.innerHTML = pageCacheHtml;
-
-        if (this._flagIsActive(this.FLAG_STRIP_UNLIKELYS)) {
-          this._removeFlag(this.FLAG_STRIP_UNLIKELYS);
-          this._attempts.push({articleContent: articleContent, textLength: textLength});
-        } else if (this._flagIsActive(this.FLAG_WEIGHT_CLASSES)) {
-          this._removeFlag(this.FLAG_WEIGHT_CLASSES);
-          this._attempts.push({articleContent: articleContent, textLength: textLength});
-        } else if (this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)) {
-          this._removeFlag(this.FLAG_CLEAN_CONDITIONALLY);
-          this._attempts.push({articleContent: articleContent, textLength: textLength});
-        } else {
-          this._attempts.push({articleContent: articleContent, textLength: textLength});
-          // No luck after removing flags, just return the longest text we found during the different loops
-          this._attempts.sort(function (a, b) {
-            return a.textLength < b.textLength;
-          });
-
-          // But first check if we actually have something
-          if (!this._attempts[0].textLength) {
-            return null;
-          }
-
-          articleContent = this._attempts[0].articleContent;
-          parseSuccessful = true;
-        }
-      }
-
-      if (parseSuccessful) {
-        // Find out text direction from ancestors of final top candidate.
-        var ancestors = [parentOfTopCandidate, topCandidate].concat(this._getNodeAncestors(parentOfTopCandidate));
-        this._someNode(ancestors, function(ancestor) {
-          if (!ancestor.tagName)
-            return false;
-          var articleDir = ancestor.getAttribute("dir");
-          if (articleDir) {
-            this._articleDir = articleDir;
-            return true;
-          }
-          return false;
-        });
-        return articleContent;
-      }
-    }
-  },
-
-  /**
-   * Check whether the input string could be a byline.
-   * This verifies that the input is a string, and that the length
-   * is less than 100 chars.
-   *
-   * @param possibleByline {string} - a string to check whether its a byline.
-   * @return Boolean - whether the input string is a byline.
-   */
-  _isValidByline: function(byline) {
-    if (typeof byline == "string" || byline instanceof String) {
-      byline = byline.trim();
-      return (byline.length > 0) && (byline.length < 100);
-    }
-    return false;
-  },
-
-  /**
-   * Attempts to get excerpt and byline metadata for the article.
-   *
-   * @return Object with optional "excerpt" and "byline" properties
-   */
-  _getArticleMetadata: function() {
-    var metadata = {};
-    var values = {};
-    var metaElements = this._doc.getElementsByTagName("meta");
-
-    // property is a space-separated list of values
-    var propertyPattern = /\s*(dc|dcterm|og|twitter)\s*:\s*(author|creator|description|title)\s*/gi;
-
-    // name is a single value
-    var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title)\s*$/i;
-
-    // Find description tags.
-    this._forEachNode(metaElements, function(element) {
-      var elementName = element.getAttribute("name");
-      var elementProperty = element.getAttribute("property");
-      var content = element.getAttribute("content");
-      var matches = null;
-      var name = null;
-
-      if (elementProperty) {
-        matches = elementProperty.match(propertyPattern);
-        if (matches) {
-          for (var i = matches.length - 1; i >= 0; i--) {
-            // Convert to lowercase, and remove any whitespace
-            // so we can match below.
-            name = matches[i].toLowerCase().replace(/\s/g, "");
-            // multiple authors
-            values[name] = content.trim();
-          }
-        }
-      }
-      if (!matches && elementName && namePattern.test(elementName)) {
-        name = elementName;
-        if (content) {
-          // Convert to lowercase, remove any whitespace, and convert dots
-          // to colons so we can match below.
-          name = name.toLowerCase().replace(/\s/g, "").replace(/\./g, ":");
-          values[name] = content.trim();
-        }
-      }
-    });
-
-    // get title
-    metadata.title = values["dc:title"] ||
-                     values["dcterm:title"] ||
-                     values["og:title"] ||
-                     values["weibo:article:title"] ||
-                     values["weibo:webpage:title"] ||
-                     values["title"] ||
-                     values["twitter:title"];
-
-    if (!metadata.title) {
-      metadata.title = this._getArticleTitle();
-    }
-
-    // get author
-    metadata.byline = values["dc:creator"] ||
-                      values["dcterm:creator"] ||
-                      values["author"];
-
-    // get description
-    metadata.excerpt = values["dc:description"] ||
-                       values["dcterm:description"] ||
-                       values["og:description"] ||
-                       values["weibo:article:description"] ||
-                       values["weibo:webpage:description"] ||
-                       values["description"] ||
-                       values["twitter:description"];
-
-    return metadata;
-  },
-
-  /**
-   * Removes script tags from the document.
-   *
-   * @param Element
-  **/
-  _removeScripts: function(doc) {
-    this._removeNodes(doc.getElementsByTagName("script"), function(scriptNode) {
-      scriptNode.nodeValue = "";
-      scriptNode.removeAttribute("src");
-      return true;
-    });
-    this._removeNodes(doc.getElementsByTagName("noscript"));
-  },
-
-  /**
-   * Check if this node has only whitespace and a single element with given tag
-   * Returns false if the DIV node contains non-empty text nodes
-   * or if it contains no element with given tag or more than 1 element.
-   *
-   * @param Element
-   * @param string tag of child element
-  **/
-  _hasSingleTagInsideElement: function(element, tag) {
-    // There should be exactly 1 element child with given tag
-    if (element.children.length != 1 || element.children[0].tagName !== tag) {
+    var textContentLength = node.textContent.trim().length;
+    if (textContentLength < 140) {
       return false;
     }
 
-    // And there should be no text nodes with real content
-    return !this._someNode(element.childNodes, function(node) {
-      return node.nodeType === this.TEXT_NODE &&
-             this.REGEXPS.hasContent.test(node.textContent);
-    });
-  },
-
-  _isElementWithoutContent: function(node) {
-    return node.nodeType === this.ELEMENT_NODE &&
-      node.textContent.trim().length == 0 &&
-      (node.children.length == 0 ||
-       node.children.length == node.getElementsByTagName("br").length + node.getElementsByTagName("hr").length);
-  },
-
-  /**
-   * Determine whether element has any children block level elements.
-   *
-   * @param Element
-   */
-  _hasChildBlockElement: function (element) {
-    return this._someNode(element.childNodes, function(node) {
-      return this.DIV_TO_P_ELEMS.indexOf(node.tagName) !== -1 ||
-             this._hasChildBlockElement(node);
-    });
-  },
-
-  /***
-   * Determine if a node qualifies as phrasing content.
-   * https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Content_categories#Phrasing_content
-  **/
-  _isPhrasingContent: function(node) {
-    return node.nodeType === this.TEXT_NODE || this.PHRASING_ELEMS.indexOf(node.tagName) !== -1 ||
-      ((node.tagName === "A" || node.tagName === "DEL" || node.tagName === "INS") &&
-        this._everyNode(node.childNodes, this._isPhrasingContent));
-  },
-
-  _isWhitespace: function(node) {
-    return (node.nodeType === this.TEXT_NODE && node.textContent.trim().length === 0) ||
-           (node.nodeType === this.ELEMENT_NODE && node.tagName === "BR");
-  },
-
-  /**
-   * Get the inner text of a node - cross browser compatibly.
-   * This also strips out any excess whitespace to be found.
-   *
-   * @param Element
-   * @param Boolean normalizeSpaces (default: true)
-   * @return string
-  **/
-  _getInnerText: function(e, normalizeSpaces) {
-    normalizeSpaces = (typeof normalizeSpaces === "undefined") ? true : normalizeSpaces;
-    var textContent = e.textContent.trim();
-
-    if (normalizeSpaces) {
-      return textContent.replace(this.REGEXPS.normalize, " ");
-    }
-    return textContent;
-  },
-
-  /**
-   * Get the number of times a string s appears in the node e.
-   *
-   * @param Element
-   * @param string - what to split on. Default is ","
-   * @return number (integer)
-  **/
-  _getCharCount: function(e, s) {
-    s = s || ",";
-    return this._getInnerText(e).split(s).length - 1;
-  },
-
-  /**
-   * Remove the style attribute on every e and under.
-   * TODO: Test if getElementsByTagName(*) is faster.
-   *
-   * @param Element
-   * @return void
-  **/
-  _cleanStyles: function(e) {
-    if (!e || e.tagName.toLowerCase() === "svg")
-      return;
-
-    // Remove `style` and deprecated presentational attributes
-    for (var i = 0; i < this.PRESENTATIONAL_ATTRIBUTES.length; i++) {
-      e.removeAttribute(this.PRESENTATIONAL_ATTRIBUTES[i]);
-    }
-
-    if (this.DEPRECATED_SIZE_ATTRIBUTE_ELEMS.indexOf(e.tagName) !== -1) {
-      e.removeAttribute("width");
-      e.removeAttribute("height");
-    }
-
-    var cur = e.firstElementChild;
-    while (cur !== null) {
-      this._cleanStyles(cur);
-      cur = cur.nextElementSibling;
-    }
-  },
+    score += Math.sqrt(textContentLength - 140);
 
-  /**
-   * Get the density of links as a percentage of the content
-   * This is the amount of text that is inside a link divided by the total text in the node.
-   *
-   * @param Element
-   * @return number (float)
-  **/
-  _getLinkDensity: function(element) {
-    var textLength = this._getInnerText(element).length;
-    if (textLength === 0)
-      return 0;
-
-    var linkLength = 0;
-
-    // XXX implement _reduceNodeList?
-    this._forEachNode(element.getElementsByTagName("a"), function(linkNode) {
-      linkLength += this._getInnerText(linkNode).length;
-    });
-
-    return linkLength / textLength;
-  },
-
-  /**
-   * Get an elements class/id weight. Uses regular expressions to tell if this
-   * element looks good or bad.
-   *
-   * @param Element
-   * @return number (Integer)
-  **/
-  _getClassWeight: function(e) {
-    if (!this._flagIsActive(this.FLAG_WEIGHT_CLASSES))
-      return 0;
-
-    var weight = 0;
-
-    // Look for a special classname
-    if (typeof(e.className) === "string" && e.className !== "") {
-      if (this.REGEXPS.negative.test(e.className))
-        weight -= 25;
-
-      if (this.REGEXPS.positive.test(e.className))
-        weight += 25;
-    }
-
-    // Look for a special ID
-    if (typeof(e.id) === "string" && e.id !== "") {
-      if (this.REGEXPS.negative.test(e.id))
-        weight -= 25;
-
-      if (this.REGEXPS.positive.test(e.id))
-        weight += 25;
-    }
-
-    return weight;
-  },
-
-  /**
-   * Clean a node of all elements of type "tag".
-   * (Unless it's a youtube/vimeo video. People love movies.)
-   *
-   * @param Element
-   * @param string tag to clean
-   * @return void
-   **/
-  _clean: function(e, tag) {
-    var isEmbed = ["object", "embed", "iframe"].indexOf(tag) !== -1;
-
-    this._removeNodes(e.getElementsByTagName(tag), function(element) {
-      // Allow youtube and vimeo videos through as people usually want to see those.
-      if (isEmbed) {
-        var attributeValues = [].map.call(element.attributes, function(attr) {
-          return attr.value;
-        }).join("|");
-
-        // First, check the elements attributes to see if any of them contain youtube or vimeo
-        if (this.REGEXPS.videos.test(attributeValues))
-          return false;
-
-        // Then check the elements inside this element for the same.
-        if (this.REGEXPS.videos.test(element.innerHTML))
-          return false;
-      }
-
+    if (score > 20) {
       return true;
-    });
-  },
-
-  /**
-   * Check if a given node has one of its ancestor tag name matching the
-   * provided one.
-   * @param  HTMLElement node
-   * @param  String      tagName
-   * @param  Number      maxDepth
-   * @param  Function    filterFn a filter to invoke to determine whether this node 'counts'
-   * @return Boolean
-   */
-  _hasAncestorTag: function(node, tagName, maxDepth, filterFn) {
-    maxDepth = maxDepth || 3;
-    tagName = tagName.toUpperCase();
-    var depth = 0;
-    while (node.parentNode) {
-      if (maxDepth > 0 && depth > maxDepth)
-        return false;
-      if (node.parentNode.tagName === tagName && (!filterFn || filterFn(node.parentNode)))
-        return true;
-      node = node.parentNode;
-      depth++;
     }
     return false;
-  },
-
-  /**
-   * Return an object indicating how many rows and columns this table has.
-   */
-  _getRowAndColumnCount: function(table) {
-    var rows = 0;
-    var columns = 0;
-    var trs = table.getElementsByTagName("tr");
-    for (var i = 0; i < trs.length; i++) {
-      var rowspan = trs[i].getAttribute("rowspan") || 0;
-      if (rowspan) {
-        rowspan = parseInt(rowspan, 10);
-      }
-      rows += (rowspan || 1);
-
-      // Now look for column-related info
-      var columnsInThisRow = 0;
-      var cells = trs[i].getElementsByTagName("td");
-      for (var j = 0; j < cells.length; j++) {
-        var colspan = cells[j].getAttribute("colspan") || 0;
-        if (colspan) {
-          colspan = parseInt(colspan, 10);
-        }
-        columnsInThisRow += (colspan || 1);
-      }
-      columns = Math.max(columns, columnsInThisRow);
-    }
-    return {rows: rows, columns: columns};
-  },
-
-  /**
-   * Look for 'data' (as opposed to 'layout') tables, for which we use
-   * similar checks as
-   * https://dxr.mozilla.org/mozilla-central/rev/71224049c0b52ab190564d3ea0eab089a159a4cf/accessible/html/HTMLTableAccessible.cpp#920
-   */
-  _markDataTables: function(root) {
-    var tables = root.getElementsByTagName("table");
-    for (var i = 0; i < tables.length; i++) {
-      var table = tables[i];
-      var role = table.getAttribute("role");
-      if (role == "presentation") {
-        table._readabilityDataTable = false;
-        continue;
-      }
-      var datatable = table.getAttribute("datatable");
-      if (datatable == "0") {
-        table._readabilityDataTable = false;
-        continue;
-      }
-      var summary = table.getAttribute("summary");
-      if (summary) {
-        table._readabilityDataTable = true;
-        continue;
-      }
-
-      var caption = table.getElementsByTagName("caption")[0];
-      if (caption && caption.childNodes.length > 0) {
-        table._readabilityDataTable = true;
-        continue;
-      }
-
-      // If the table has a descendant with any of these tags, consider a data table:
-      var dataTableDescendants = ["col", "colgroup", "tfoot", "thead", "th"];
-      var descendantExists = function(tag) {
-        return !!table.getElementsByTagName(tag)[0];
-      };
-      if (dataTableDescendants.some(descendantExists)) {
-        this.log("Data table because found data-y descendant");
-        table._readabilityDataTable = true;
-        continue;
-      }
-
-      // Nested tables indicate a layout table:
-      if (table.getElementsByTagName("table")[0]) {
-        table._readabilityDataTable = false;
-        continue;
-      }
-
-      var sizeInfo = this._getRowAndColumnCount(table);
-      if (sizeInfo.rows >= 10 || sizeInfo.columns > 4) {
-        table._readabilityDataTable = true;
-        continue;
-      }
-      // Now just go by size entirely:
-      table._readabilityDataTable = sizeInfo.rows * sizeInfo.columns > 10;
-    }
-  },
-
-  /**
-   * Clean an element of all tags of type "tag" if they look fishy.
-   * "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc.
-   *
-   * @return void
-   **/
-  _cleanConditionally: function(e, tag) {
-    if (!this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY))
-      return;
-
-    var isList = tag === "ul" || tag === "ol";
-
-    // Gather counts for other typical elements embedded within.
-    // Traverse backwards so we can remove nodes at the same time
-    // without effecting the traversal.
-    //
-    // TODO: Consider taking into account original contentScore here.
-    this._removeNodes(e.getElementsByTagName(tag), function(node) {
-      // First check if we're in a data table, in which case don't remove us.
-      var isDataTable = function(t) {
-        return t._readabilityDataTable;
-      };
-
-      if (this._hasAncestorTag(node, "table", -1, isDataTable)) {
-        return false;
-      }
-
-      var weight = this._getClassWeight(node);
-      var contentScore = 0;
-
-      this.log("Cleaning Conditionally", node);
-
-      if (weight + contentScore < 0) {
-        return true;
-      }
-
-      if (this._getCharCount(node, ",") < 10) {
-        // If there are not very many commas, and the number of
-        // non-paragraph elements is more than paragraphs or other
-        // ominous signs, remove the element.
-        var p = node.getElementsByTagName("p").length;
-        var img = node.getElementsByTagName("img").length;
-        var li = node.getElementsByTagName("li").length - 100;
-        var input = node.getElementsByTagName("input").length;
-
-        var embedCount = 0;
-        var embeds = node.getElementsByTagName("embed");
-        for (var ei = 0, il = embeds.length; ei < il; ei += 1) {
-          if (!this.REGEXPS.videos.test(embeds[ei].src))
-            embedCount += 1;
-        }
-
-        var linkDensity = this._getLinkDensity(node);
-        var contentLength = this._getInnerText(node).length;
-
-        var haveToRemove =
-          (img > 1 && p / img < 0.5 && !this._hasAncestorTag(node, "figure")) ||
-          (!isList && li > p) ||
-          (input > Math.floor(p/3)) ||
-          (!isList && contentLength < 25 && (img === 0 || img > 2) && !this._hasAncestorTag(node, "figure")) ||
-          (!isList && weight < 25 && linkDensity > 0.2) ||
-          (weight >= 25 && linkDensity > 0.5) ||
-          ((embedCount === 1 && contentLength < 75) || embedCount > 1);
-        return haveToRemove;
-      }
-      return false;
-    });
-  },
+  });
+}
 
-  /**
-   * Clean out elements whose id/class combinations match specific string.
-   *
-   * @param Element
-   * @param RegExp match id/class combination.
-   * @return void
-   **/
-  _cleanMatchedNodes: function(e, regex) {
-    var endOfSearchMarkerNode = this._getNextNode(e, true);
-    var next = this._getNextNode(e);
-    while (next && next != endOfSearchMarkerNode) {
-      if (regex.test(next.className + " " + next.id)) {
-        next = this._removeAndGetNext(next);
-      } else {
-        next = this._getNextNode(next);
-      }
-    }
-  },
-
-  /**
-   * Clean out spurious headers from an Element. Checks things like classnames and link density.
-   *
-   * @param Element
-   * @return void
-  **/
-  _cleanHeaders: function(e) {
-    for (var headerIndex = 1; headerIndex < 3; headerIndex += 1) {
-      this._removeNodes(e.getElementsByTagName("h" + headerIndex), function (header) {
-        return this._getClassWeight(header) < 0;
-      });
-    }
-  },
-
-  _flagIsActive: function(flag) {
-    return (this._flags & flag) > 0;
-  },
-
-  _removeFlag: function(flag) {
-    this._flags = this._flags & ~flag;
-  },
-
-  _isProbablyVisible: function(node) {
-    return node.style.display != "none" && !node.hasAttribute("hidden");
-  },
-
-  /**
-   * Decides whether or not the document is reader-able without parsing the whole thing.
-   *
-   * @return boolean Whether or not we suspect parse() will suceeed at returning an article object.
-   */
-  isProbablyReaderable: function(helperIsVisible) {
-    var nodes = this._getAllNodesWithTag(this._doc, ["p", "pre"]);
-
-    // Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
-    // Some articles' DOM structures might look like
-    // <div>
-    //   Sentences<br>
-    //   <br>
-    //   Sentences<br>
-    // </div>
-    var brNodes = this._getAllNodesWithTag(this._doc, ["div > br"]);
-    if (brNodes.length) {
-      var set = new Set();
-      [].forEach.call(brNodes, function(node) {
-        set.add(node.parentNode);
-      });
-      nodes = [].concat.apply(Array.from(set), nodes);
-    }
-
-    if (!helperIsVisible) {
-      helperIsVisible = this._isProbablyVisible;
-    }
-
-    var score = 0;
-    // This is a little cheeky, we use the accumulator 'score' to decide what to return from
-    // this callback:
-    return this._someNode(nodes, function(node) {
-      if (helperIsVisible && !helperIsVisible(node))
-        return false;
-      var matchString = node.className + " " + node.id;
-
-      if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
-          !this.REGEXPS.okMaybeItsACandidate.test(matchString)) {
-        return false;
-      }
-
-      if (node.matches && node.matches("li p")) {
-        return false;
-      }
-
-      var textContentLength = node.textContent.trim().length;
-      if (textContentLength < 140) {
-        return false;
-      }
-
-      score += Math.sqrt(textContentLength - 140);
-
-      if (score > 20) {
-        return true;
-      }
-      return false;
-    });
-  },
-
-  /**
-   * Runs readability.
-   *
-   * Workflow:
-   *  1. Prep the document by removing script tags, css, etc.
-   *  2. Build readability's DOM tree.
-   *  3. Grab the article content from the current dom tree.
-   *  4. Replace the current DOM tree with the new one.
-   *  5. Read peacefully.
-   *
-   * @return void
-   **/
-  parse: function () {
-    // Avoid parsing too large documents, as per configuration option
-    if (this._maxElemsToParse > 0) {
-      var numTags = this._doc.getElementsByTagName("*").length;
-      if (numTags > this._maxElemsToParse) {
-        throw new Error("Aborting parsing document; " + numTags + " elements found");
-      }
-    }
-
-    // Remove script tags from the document.
-    this._removeScripts(this._doc);
-
-    this._prepDocument();
-
-    var metadata = this._getArticleMetadata();
-    this._articleTitle = metadata.title;
-
-    var articleContent = this._grabArticle();
-    if (!articleContent)
-      return null;
-
-    this.log("Grabbed: " + articleContent.innerHTML);
-
-    this._postProcessContent(articleContent);
-
-    // If we haven't found an excerpt in the article's metadata, use the article's
-    // first paragraph as the excerpt. This is used for displaying a preview of
-    // the article's content.
-    if (!metadata.excerpt) {
-      var paragraphs = articleContent.getElementsByTagName("p");
-      if (paragraphs.length > 0) {
-        metadata.excerpt = paragraphs[0].textContent.trim();
-      }
-    }
-
-    var textContent = articleContent.textContent;
-    return {
-      title: this._articleTitle,
-      byline: metadata.byline || this._articleByline,
-      dir: this._articleDir,
-      content: articleContent.innerHTML,
-      textContent: textContent,
-      length: textContent.length,
-      excerpt: metadata.excerpt,
-    };
-  }
-};
-
-if (typeof module === "object") {
-  module.exports = Readability;
+if (typeof exports === "object") {
+  exports.isProbablyReaderable = isProbablyReaderable;
 }
--- a/toolkit/components/reader/Readability.js
+++ b/toolkit/components/reader/Readability.js
@@ -1,17 +1,10 @@
 /*eslint-env es6:false*/
 /*
- * DO NOT MODIFY THIS FILE DIRECTLY!
- *
- * This is a shared library that is maintained in an external repo:
- * https://github.com/mozilla/readability
- */
-
-/*
  * Copyright (c) 2010 Arc90 Inc
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -113,18 +106,21 @@ Readability.prototype = {
   DEFAULT_TAGS_TO_SCORE: "section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),
 
   // The default number of chars an article must have in order to return a result
   DEFAULT_CHAR_THRESHOLD: 500,
 
   // All of the regular expressions in use within readability.
   // Defined up here so we don't instantiate them repeatedly in loops.
   REGEXPS: {
+    // NOTE: These two regular expressions are duplicated in
+    // Readability-readerable.js. Please keep both copies in sync.
     unlikelyCandidates: /-ad-|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
     okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
+
     positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,
     negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
     extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
     byline: /byline|author|dateline|writtenby|p-author/i,
     replaceFonts: /<(\/?)font[^>]*>/gi,
     normalize: /\s{2,}/g,
     videos: /\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,
     nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
@@ -1707,75 +1703,16 @@ Readability.prototype = {
     this._flags = this._flags & ~flag;
   },
 
   _isProbablyVisible: function(node) {
     return node.style.display != "none" && !node.hasAttribute("hidden");
   },
 
   /**
-   * Decides whether or not the document is reader-able without parsing the whole thing.
-   *
-   * @return boolean Whether or not we suspect parse() will suceeed at returning an article object.
-   */
-  isProbablyReaderable: function(helperIsVisible) {
-    var nodes = this._getAllNodesWithTag(this._doc, ["p", "pre"]);
-
-    // Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
-    // Some articles' DOM structures might look like
-    // <div>
-    //   Sentences<br>
-    //   <br>
-    //   Sentences<br>
-    // </div>
-    var brNodes = this._getAllNodesWithTag(this._doc, ["div > br"]);
-    if (brNodes.length) {
-      var set = new Set();
-      [].forEach.call(brNodes, function(node) {
-        set.add(node.parentNode);
-      });
-      nodes = [].concat.apply(Array.from(set), nodes);
-    }
-
-    if (!helperIsVisible) {
-      helperIsVisible = this._isProbablyVisible;
-    }
-
-    var score = 0;
-    // This is a little cheeky, we use the accumulator 'score' to decide what to return from
-    // this callback:
-    return this._someNode(nodes, function(node) {
-      if (helperIsVisible && !helperIsVisible(node))
-        return false;
-      var matchString = node.className + " " + node.id;
-
-      if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
-          !this.REGEXPS.okMaybeItsACandidate.test(matchString)) {
-        return false;
-      }
-
-      if (node.matches && node.matches("li p")) {
-        return false;
-      }
-
-      var textContentLength = node.textContent.trim().length;
-      if (textContentLength < 140) {
-        return false;
-      }
-
-      score += Math.sqrt(textContentLength - 140);
-
-      if (score > 20) {
-        return true;
-      }
-      return false;
-    });
-  },
-
-  /**
    * Runs readability.
    *
    * Workflow:
    *  1. Prep the document by removing script tags, css, etc.
    *  2. Build readability's DOM tree.
    *  3. Grab the article content from the current dom tree.
    *  4. Replace the current DOM tree with the new one.
    *  5. Read peacefully.
--- a/toolkit/components/reader/ReaderMode.jsm
+++ b/toolkit/components/reader/ReaderMode.jsm
@@ -36,68 +36,26 @@ ChromeUtils.import("resource://gre/modul
 
 XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest", "XMLSerializer"]);
 
 ChromeUtils.defineModuleGetter(this, "CommonUtils", "resource://services-common/utils.js");
 ChromeUtils.defineModuleGetter(this, "EventDispatcher", "resource://gre/modules/Messaging.jsm");
 ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 ChromeUtils.defineModuleGetter(this, "ReaderWorker", "resource://gre/modules/reader/ReaderWorker.jsm");
 ChromeUtils.defineModuleGetter(this, "LanguageDetector", "resource:///modules/translation/LanguageDetector.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Readability", function() {
-  let scope = {};
-  scope.dump = this.dump;
-  Services.scriptloader.loadSubScript("resource://gre/modules/reader/Readability.js", scope);
-  return scope.Readability;
-});
+ChromeUtils.defineModuleGetter(this, "Readerable", "resource://gre/modules/Readerable.jsm");
 
 const gIsFirefoxDesktop = Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
 
 var ReaderMode = {
   // Version of the cache schema.
   CACHE_VERSION: 1,
 
   DEBUG: 0,
 
-  // Don't try to parse the page if it has too many elements (for memory and
-  // performance reasons)
-  get maxElemsToParse() {
-    delete this.parseNodeLimit;
-
-    Services.prefs.addObserver("reader.parse-node-limit", this);
-    return this.parseNodeLimit = Services.prefs.getIntPref("reader.parse-node-limit");
-  },
-
-  get isEnabledForParseOnLoad() {
-    delete this.isEnabledForParseOnLoad;
-
-    // Listen for future pref changes.
-    Services.prefs.addObserver("reader.parse-on-load.", this);
-
-    return this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
-  },
-
-  _getStateForParseOnLoad() {
-    let isEnabled = Services.prefs.getBoolPref("reader.parse-on-load.enabled");
-    let isForceEnabled = Services.prefs.getBoolPref("reader.parse-on-load.force-enabled");
-    return isForceEnabled || isEnabled;
-  },
-
-  observe(aMessage, aTopic, aData) {
-    switch (aTopic) {
-      case "nsPref:changed":
-        if (aData.startsWith("reader.parse-on-load.")) {
-          this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
-        } else if (aData === "reader.parse-node-limit") {
-          this.parseNodeLimit = Services.prefs.getIntPref(aData);
-        }
-        break;
-    }
-  },
-
   /**
    * Enter the reader mode by going forward one step in history if applicable,
    * if not, append the about:reader page in the history instead.
    */
   enterReaderMode(docShell, win) {
     let url = win.document.location.href;
     let readerURL = "about:reader?url=" + encodeURIComponent(url);
     let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
@@ -193,58 +151,26 @@ var ReaderMode = {
       } catch (ex) {
         return null;
       }
     }
     return null;
   },
 
   /**
-   * Decides whether or not a document is reader-able without parsing the whole thing.
-   *
-   * @param doc A document to parse.
-   * @return boolean Whether or not we should show the reader mode button.
-   */
-  isProbablyReaderable(doc) {
-    // Only care about 'real' HTML documents:
-    if (doc.mozSyntheticDocument || !(doc instanceof doc.defaultView.HTMLDocument)) {
-      return false;
-    }
-
-    let uri = Services.io.newURI(doc.location.href);
-    if (!this._shouldCheckUri(uri)) {
-      return false;
-    }
-
-    let utils = this.getUtilsForWin(doc.defaultView);
-    // We pass in a helper function to determine if a node is visible, because
-    // it uses gecko APIs that the engine-agnostic readability code can't rely
-    // upon.
-    return new Readability(doc).isProbablyReaderable(this.isNodeVisible.bind(this, utils));
-  },
-
-  isNodeVisible(utils, node) {
-    let bounds = utils.getBoundsWithoutFlushing(node);
-    return bounds.height > 0 && bounds.width > 0;
-  },
-
-  getUtilsForWin(win) {
-    return win.windowUtils;
-  },
-
-  /**
    * Gets an article from a loaded browser's document. This method will not attempt
    * to parse certain URIs (e.g. about: URIs).
    *
    * @param doc A document to parse.
    * @return {Promise}
    * @resolves JS object representing the article, or null if no article is found.
    */
   parseDocument(doc) {
-    if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
+    if (!Readerable.shouldCheckUri(doc.documentURIObject) ||
+        !Readerable.shouldCheckUri(doc.baseURIObject, true)) {
       this.log("Reader mode disabled for URI");
       return null;
     }
 
     return this._readerParse(doc);
   },
 
   /**
@@ -254,27 +180,28 @@ var ReaderMode = {
    * @return {Promise}
    * @resolves JS object representing the article, or null if no article is found.
    */
   async downloadAndParseDocument(url) {
     let doc = await this._downloadDocument(url);
     if (!doc) {
       return null;
     }
-    if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
+    if (!Readerable.shouldCheckUri(doc.documentURIObject) ||
+        !Readerable.shouldCheckUri(doc.baseURIObject, true)) {
       this.log("Reader mode disabled for URI");
       return null;
     }
 
     return this._readerParse(doc);
   },
 
   _downloadDocument(url) {
     try {
-      if (!this._shouldCheckUri(Services.io.newURI(url))) {
+      if (!Readerable.shouldCheckUri(Services.io.newURI(url))) {
         return null;
       }
     } catch (ex) {
       Cu.reportError(new Error(`Couldn't create URI from ${url} to download: ${ex}`));
       return null;
     }
     let histogram = Services.telemetry.getHistogramById("READER_MODE_DOWNLOAD_RESULT");
     return new Promise((resolve, reject) => {
@@ -410,52 +337,16 @@ var ReaderMode = {
     await OS.File.remove(path);
   },
 
   log(msg) {
     if (this.DEBUG)
       dump("Reader: " + msg);
   },
 
-  _blockedHosts: [
-    "amazon.com",
-    "github.com",
-    "mail.google.com",
-    "pinterest.com",
-    "reddit.com",
-    "twitter.com",
-    "youtube.com",
-  ],
-
-  _shouldCheckUri(uri, isBaseUri = false) {
-    if (!(uri.schemeIs("http") || uri.schemeIs("https"))) {
-      this.log("Not parsing URI scheme: " + uri.scheme);
-      return false;
-    }
-
-    try {
-      uri.QueryInterface(Ci.nsIURL);
-    } catch (ex) {
-      // If this doesn't work, presumably the URL is not well-formed or something
-      return false;
-    }
-    // Sadly, some high-profile pages have false positives, so bail early for those:
-    let asciiHost = uri.asciiHost;
-    if (!isBaseUri && this._blockedHosts.some(blockedHost => asciiHost.endsWith(blockedHost))) {
-      return false;
-    }
-
-    if (!isBaseUri && (!uri.filePath || uri.filePath == "/")) {
-      this.log("Not parsing home page: " + uri.spec);
-      return false;
-    }
-
-    return true;
-  },
-
   /**
    * Attempts to parse a document into an article. Heavy lifting happens
    * in readerWorker.js.
    *
    * @param doc The document to parse.
    * @return {Promise}
    * @resolves JS object representing the article, or null if no article is found.
    */
@@ -636,8 +527,11 @@ var ReaderMode = {
       [ "sv", {cpm: 917,  variance: 156 } ],
       [ "tr", {cpm: 1054, variance: 156 } ],
       [ "zh", {cpm: 255,  variance: 29 } ],
     ]);
 
     return readingSpeed.get(lang) || readingSpeed.get("en");
   },
 };
+
+XPCOMUtils.defineLazyPreferenceGetter(
+  ReaderMode, "maxElemsToParse", "reader.parse-node-limit", 0);
copy from toolkit/components/reader/ReaderMode.jsm
copy to toolkit/components/reader/Readerable.js
--- a/toolkit/components/reader/ReaderMode.jsm
+++ b/toolkit/components/reader/Readerable.js
@@ -1,643 +1,79 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-var EXPORTED_SYMBOLS = ["ReaderMode"];
-
-// Constants for telemetry.
-const DOWNLOAD_SUCCESS = 0;
-const DOWNLOAD_ERROR_XHR = 1;
-const DOWNLOAD_ERROR_NO_DOC = 2;
-
-const PARSE_SUCCESS = 0;
-const PARSE_ERROR_TOO_MANY_ELEMENTS = 1;
-const PARSE_ERROR_WORKER = 2;
-const PARSE_ERROR_NO_ARTICLE = 3;
+// This file and Readability-readerable.js are merged together into
+// Readerable.jsm.
 
-// Class names to preserve in the readerized output. We preserve these class
-// names so that rules in aboutReader.css can match them.
-const CLASSES_TO_PRESERVE = [
-  "caption",
-  "emoji",
-  "hidden",
-  "invisble",
-  "sr-only",
-  "visually-hidden",
-  "visuallyhidden",
-  "wp-caption",
-  "wp-caption-text",
-  "wp-smiley",
-];
+/* exported Readerable */
+/* import-globals-from Readability-readerable.js */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
-XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest", "XMLSerializer"]);
-
-ChromeUtils.defineModuleGetter(this, "CommonUtils", "resource://services-common/utils.js");
-ChromeUtils.defineModuleGetter(this, "EventDispatcher", "resource://gre/modules/Messaging.jsm");
-ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
-ChromeUtils.defineModuleGetter(this, "ReaderWorker", "resource://gre/modules/reader/ReaderWorker.jsm");
-ChromeUtils.defineModuleGetter(this, "LanguageDetector", "resource:///modules/translation/LanguageDetector.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Readability", function() {
-  let scope = {};
-  scope.dump = this.dump;
-  Services.scriptloader.loadSubScript("resource://gre/modules/reader/Readability.js", scope);
-  return scope.Readability;
-});
-
-const gIsFirefoxDesktop = Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
-
-var ReaderMode = {
-  // Version of the cache schema.
-  CACHE_VERSION: 1,
-
-  DEBUG: 0,
-
-  // Don't try to parse the page if it has too many elements (for memory and
-  // performance reasons)
-  get maxElemsToParse() {
-    delete this.parseNodeLimit;
-
-    Services.prefs.addObserver("reader.parse-node-limit", this);
-    return this.parseNodeLimit = Services.prefs.getIntPref("reader.parse-node-limit");
-  },
-
-  get isEnabledForParseOnLoad() {
-    delete this.isEnabledForParseOnLoad;
-
-    // Listen for future pref changes.
-    Services.prefs.addObserver("reader.parse-on-load.", this);
-
-    return this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
-  },
-
-  _getStateForParseOnLoad() {
-    let isEnabled = Services.prefs.getBoolPref("reader.parse-on-load.enabled");
-    let isForceEnabled = Services.prefs.getBoolPref("reader.parse-on-load.force-enabled");
-    return isForceEnabled || isEnabled;
-  },
-
-  observe(aMessage, aTopic, aData) {
-    switch (aTopic) {
-      case "nsPref:changed":
-        if (aData.startsWith("reader.parse-on-load.")) {
-          this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
-        } else if (aData === "reader.parse-node-limit") {
-          this.parseNodeLimit = Services.prefs.getIntPref(aData);
-        }
-        break;
-    }
-  },
-
-  /**
-   * Enter the reader mode by going forward one step in history if applicable,
-   * if not, append the about:reader page in the history instead.
-   */
-  enterReaderMode(docShell, win) {
-    let url = win.document.location.href;
-    let readerURL = "about:reader?url=" + encodeURIComponent(url);
-    let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
-    let sh = webNav.sessionHistory;
-    if (webNav.canGoForward) {
-      let forwardEntry = sh.legacySHistory.getEntryAtIndex(sh.index + 1);
-      let forwardURL = forwardEntry.URI.spec;
-      if (forwardURL && (forwardURL == readerURL || !readerURL)) {
-        webNav.goForward();
-        return;
-      }
-    }
-
-    win.document.location = readerURL;
-  },
+function isNodeVisible(node) {
+  return node.clientHeight > 0 && node.clientWidth > 0;
+}
 
-  /**
-   * Exit the reader mode by going back one step in history if applicable,
-   * if not, append the original page in the history instead.
-   */
-  leaveReaderMode(docShell, win) {
-    let url = win.document.location.href;
-    let originalURL = this.getOriginalUrl(url);
-    let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
-    let sh = webNav.sessionHistory;
-    if (webNav.canGoBack) {
-      let prevEntry = sh.legacySHistory.getEntryAtIndex(sh.index - 1);
-      let prevURL = prevEntry.URI.spec;
-      if (prevURL && (prevURL == originalURL || !originalURL)) {
-        webNav.goBack();
-        return;
-      }
-    }
-
-    let referrerURI, principal;
-    try {
-      referrerURI = Services.io.newURI(url);
-      principal = Services.scriptSecurityManager.createCodebasePrincipal(
-        referrerURI, win.document.nodePrincipal.originAttributes);
-    } catch (e) {
-      Cu.reportError(e);
-      return;
-    }
-    let flags = webNav.LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL;
-    webNav.loadURI(originalURL, flags, referrerURI, null, null, principal);
-  },
-
-  /**
-   * Returns original URL from an about:reader URL.
-   *
-   * @param url An about:reader URL.
-   * @return The original URL for the article, or null if we did not find
-   *         a properly formatted about:reader URL.
-   */
-  getOriginalUrl(url) {
-    if (!url.startsWith("about:reader?")) {
-      return null;
-    }
-
-    let outerHash = "";
-    try {
-      let uriObj = Services.io.newURI(url);
-      url = uriObj.specIgnoringRef;
-      outerHash = uriObj.ref;
-    } catch (ex) { /* ignore, use the raw string */ }
-
-    let searchParams = new URLSearchParams(url.substring("about:reader?".length));
-    if (!searchParams.has("url")) {
-      return null;
-    }
-    let originalUrl = searchParams.get("url");
-    if (outerHash) {
-      try {
-        let uriObj = Services.io.newURI(originalUrl);
-        uriObj = Services.io.newURI("#" + outerHash, null, uriObj);
-        originalUrl = uriObj.spec;
-      } catch (ex) {}
-    }
-    return originalUrl;
-  },
-
-  getOriginalUrlObjectForDisplay(url) {
-    let originalUrl = this.getOriginalUrl(url);
-    if (originalUrl) {
-      let uriObj;
-      try {
-        uriObj = Services.uriFixup.createFixupURI(originalUrl, Services.uriFixup.FIXUP_FLAG_NONE);
-      } catch (ex) {
-        return null;
-      }
-      try {
-        return Services.uriFixup.createExposableURI(uriObj);
-      } catch (ex) {
-        return null;
-      }
-    }
-    return null;
+var Readerable = {
+  get isEnabledForParseOnLoad() {
+    return this.isEnabled || this.isForceEnabled;
   },
 
   /**
    * Decides whether or not a document is reader-able without parsing the whole thing.
    *
    * @param doc A document to parse.
    * @return boolean Whether or not we should show the reader mode button.
    */
   isProbablyReaderable(doc) {
     // Only care about 'real' HTML documents:
     if (doc.mozSyntheticDocument || !(doc instanceof doc.defaultView.HTMLDocument)) {
       return false;
     }
 
     let uri = Services.io.newURI(doc.location.href);
-    if (!this._shouldCheckUri(uri)) {
+    if (!this.shouldCheckUri(uri)) {
       return false;
     }
 
-    let utils = this.getUtilsForWin(doc.defaultView);
-    // We pass in a helper function to determine if a node is visible, because
-    // it uses gecko APIs that the engine-agnostic readability code can't rely
-    // upon.
-    return new Readability(doc).isProbablyReaderable(this.isNodeVisible.bind(this, utils));
-  },
-
-  isNodeVisible(utils, node) {
-    let bounds = utils.getBoundsWithoutFlushing(node);
-    return bounds.height > 0 && bounds.width > 0;
-  },
-
-  getUtilsForWin(win) {
-    return win.windowUtils;
-  },
-
-  /**
-   * Gets an article from a loaded browser's document. This method will not attempt
-   * to parse certain URIs (e.g. about: URIs).
-   *
-   * @param doc A document to parse.
-   * @return {Promise}
-   * @resolves JS object representing the article, or null if no article is found.
-   */
-  parseDocument(doc) {
-    if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
-      this.log("Reader mode disabled for URI");
-      return null;
-    }
-
-    return this._readerParse(doc);
-  },
-
-  /**
-   * Downloads and parses a document from a URL.
-   *
-   * @param url URL to download and parse.
-   * @return {Promise}
-   * @resolves JS object representing the article, or null if no article is found.
-   */
-  async downloadAndParseDocument(url) {
-    let doc = await this._downloadDocument(url);
-    if (!doc) {
-      return null;
-    }
-    if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
-      this.log("Reader mode disabled for URI");
-      return null;
-    }
-
-    return this._readerParse(doc);
-  },
-
-  _downloadDocument(url) {
-    try {
-      if (!this._shouldCheckUri(Services.io.newURI(url))) {
-        return null;
-      }
-    } catch (ex) {
-      Cu.reportError(new Error(`Couldn't create URI from ${url} to download: ${ex}`));
-      return null;
-    }
-    let histogram = Services.telemetry.getHistogramById("READER_MODE_DOWNLOAD_RESULT");
-    return new Promise((resolve, reject) => {
-      let xhr = new XMLHttpRequest();
-      xhr.open("GET", url, true);
-      xhr.onerror = evt => reject(evt.error);
-      xhr.responseType = "document";
-      xhr.onload = evt => {
-        if (xhr.status !== 200) {
-          reject("Reader mode XHR failed with status: " + xhr.status);
-          histogram.add(DOWNLOAD_ERROR_XHR);
-          return;
-        }
-
-        let doc = xhr.responseXML;
-        if (!doc) {
-          reject("Reader mode XHR didn't return a document");
-          histogram.add(DOWNLOAD_ERROR_NO_DOC);
-          return;
-        }
-
-        // Manually follow a meta refresh tag if one exists.
-        let meta = doc.querySelector("meta[http-equiv=refresh]");
-        if (meta) {
-          let content = meta.getAttribute("content");
-          if (content) {
-            let urlIndex = content.toUpperCase().indexOf("URL=");
-            if (urlIndex > -1) {
-              let baseURI = Services.io.newURI(url);
-              let newURI = Services.io.newURI(content.substring(urlIndex + 4), null, baseURI);
-              let newURL = newURI.spec;
-              let ssm = Services.scriptSecurityManager;
-              let flags = ssm.LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT |
-                          ssm.DISALLOW_INHERIT_PRINCIPAL;
-              try {
-                ssm.checkLoadURIStrWithPrincipal(doc.nodePrincipal, newURL, flags);
-              } catch (ex) {
-                let errorMsg = "Reader mode disallowed meta refresh (reason: " + ex + ").";
-
-                if (Services.prefs.getBoolPref("reader.errors.includeURLs"))
-                  errorMsg += " Refresh target URI: '" + newURL + "'.";
-                reject(errorMsg);
-                return;
-              }
-              // Otherwise, pass an object indicating our new URL:
-              if (!baseURI.equalsExceptRef(newURI)) {
-                reject({newURL});
-                return;
-              }
-            }
-          }
-        }
-        let responseURL = xhr.responseURL;
-        let givenURL = url;
-        // Convert these to real URIs to make sure the escaping (or lack
-        // thereof) is identical:
-        try {
-          responseURL = Services.io.newURI(responseURL).specIgnoringRef;
-        } catch (ex) { /* Ignore errors - we'll use what we had before */ }
-        try {
-          givenURL = Services.io.newURI(givenURL).specIgnoringRef;
-        } catch (ex) { /* Ignore errors - we'll use what we had before */ }
-
-        if (responseURL != givenURL) {
-          // We were redirected without a meta refresh tag.
-          // Force redirect to the correct place:
-          reject({newURL: xhr.responseURL});
-          return;
-        }
-        resolve(doc);
-        histogram.add(DOWNLOAD_SUCCESS);
-      };
-      xhr.send();
-    });
-  },
-
-
-  /**
-   * Retrieves an article from the cache given an article URI.
-   *
-   * @param url The article URL.
-   * @return {Promise}
-   * @resolves JS object representing the article, or null if no article is found.
-   * @rejects OS.File.Error
-   */
-  async getArticleFromCache(url) {
-    let path = this._toHashedPath(url);
-    try {
-      let array = await OS.File.read(path);
-      return JSON.parse(new TextDecoder().decode(array));
-    } catch (e) {
-      if (!(e instanceof OS.File.Error) || !e.becauseNoSuchFile)
-        throw e;
-      return null;
-    }
-  },
-
-  /**
-   * Stores an article in the cache.
-   *
-   * @param article JS object representing article.
-   * @return {Promise}
-   * @resolves When the article is stored.
-   * @rejects OS.File.Error
-   */
-  async storeArticleInCache(article) {
-    let array = new TextEncoder().encode(JSON.stringify(article));
-    let path = this._toHashedPath(article.url);
-    await this._ensureCacheDir();
-    return OS.File.writeAtomic(path, array, { tmpPath: path + ".tmp" })
-      .then(success => {
-        OS.File.stat(path).then(info => {
-          return EventDispatcher.instance.sendRequest({
-            type: "Reader:AddedToCache",
-            url: article.url,
-            size: info.size,
-            path,
-          });
-        });
-      });
-  },
-
-  /**
-   * Removes an article from the cache given an article URI.
-   *
-   * @param url The article URL.
-   * @return {Promise}
-   * @resolves When the article is removed.
-   * @rejects OS.File.Error
-   */
-  async removeArticleFromCache(url) {
-    let path = this._toHashedPath(url);
-    await OS.File.remove(path);
-  },
-
-  log(msg) {
-    if (this.DEBUG)
-      dump("Reader: " + msg);
+    return isProbablyReaderable(doc, isNodeVisible);
   },
 
   _blockedHosts: [
     "amazon.com",
     "github.com",
     "mail.google.com",
     "pinterest.com",
     "reddit.com",
     "twitter.com",
     "youtube.com",
   ],
 
-  _shouldCheckUri(uri, isBaseUri = false) {
-    if (!(uri.schemeIs("http") || uri.schemeIs("https"))) {
-      this.log("Not parsing URI scheme: " + uri.scheme);
+  shouldCheckUri(uri, isBaseUri = false) {
+    if (!["http", "https"].includes(uri.scheme)) {
       return false;
     }
 
-    try {
-      uri.QueryInterface(Ci.nsIURL);
-    } catch (ex) {
-      // If this doesn't work, presumably the URL is not well-formed or something
-      return false;
-    }
-    // Sadly, some high-profile pages have false positives, so bail early for those:
-    let asciiHost = uri.asciiHost;
-    if (!isBaseUri && this._blockedHosts.some(blockedHost => asciiHost.endsWith(blockedHost))) {
-      return false;
-    }
+    if (!isBaseUri) {
+      // Sadly, some high-profile pages have false positives, so bail early for those:
+      let {host} = uri;
+      if (this._blockedHosts.some(blockedHost => host.endsWith(blockedHost))) {
+        return false;
+      }
 
-    if (!isBaseUri && (!uri.filePath || uri.filePath == "/")) {
-      this.log("Not parsing home page: " + uri.spec);
-      return false;
+      if (uri.filePath == "/") {
+        return false;
+      }
     }
 
     return true;
   },
-
-  /**
-   * Attempts to parse a document into an article. Heavy lifting happens
-   * in readerWorker.js.
-   *
-   * @param doc The document to parse.
-   * @return {Promise}
-   * @resolves JS object representing the article, or null if no article is found.
-   */
-  async _readerParse(doc) {
-    let histogram = Services.telemetry.getHistogramById("READER_MODE_PARSE_RESULT");
-    if (this.parseNodeLimit) {
-      let numTags = doc.getElementsByTagName("*").length;
-      if (numTags > this.parseNodeLimit) {
-        this.log("Aborting parse for " + doc.baseURIObject.spec + "; " + numTags + " elements found");
-        histogram.add(PARSE_ERROR_TOO_MANY_ELEMENTS);
-        return null;
-      }
-    }
-
-    // Fetch this here before we send `doc` off to the worker thread, as later on the
-    // document might be nuked but we will still want the URI.
-    let {documentURI} = doc;
-
-    let uriParam = {
-      spec: doc.baseURIObject.spec,
-      host: doc.baseURIObject.host,
-      prePath: doc.baseURIObject.prePath,
-      scheme: doc.baseURIObject.scheme,
-      pathBase: Services.io.newURI(".", null, doc.baseURIObject).spec,
-    };
-
-    let serializer = new XMLSerializer();
-    let serializedDoc = serializer.serializeToString(doc);
-
-    let options = {
-      classesToPreserve: CLASSES_TO_PRESERVE,
-    };
-
-    let article = null;
-    try {
-      article = await ReaderWorker.post("parseDocument", [uriParam, serializedDoc, options]);
-    } catch (e) {
-      Cu.reportError("Error in ReaderWorker: " + e);
-      histogram.add(PARSE_ERROR_WORKER);
-    }
-
-    // Explicitly null out doc to make it clear it might not be available from this
-    // point on.
-    doc = null;
-
-    if (!article) {
-      this.log("Worker did not return an article");
-      histogram.add(PARSE_ERROR_NO_ARTICLE);
-      return null;
-    }
-
-    // Readability returns a URI object based on the baseURI, but we only care
-    // about the original document's URL from now on. This also avoids spoofing
-    // attempts where the baseURI doesn't match the domain of the documentURI
-    article.url = documentURI;
-    delete article.uri;
-
-    let flags = Ci.nsIDocumentEncoder.OutputSelectionOnly | Ci.nsIDocumentEncoder.OutputAbsoluteLinks;
-    article.title = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils)
-                                                    .convertToPlainText(article.title, flags, 0);
-    if (gIsFirefoxDesktop) {
-      await this._assignLanguage(article);
-      this._maybeAssignTextDirection(article);
-    }
-
-    this._assignReadTime(article);
-
-    histogram.add(PARSE_SUCCESS);
-    return article;
-  },
-
-  get _cryptoHash() {
-    delete this._cryptoHash;
-    return this._cryptoHash = Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
-  },
-
-  get _unicodeConverter() {
-    delete this._unicodeConverter;
-    this._unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
-                              .createInstance(Ci.nsIScriptableUnicodeConverter);
-    this._unicodeConverter.charset = "utf8";
-    return this._unicodeConverter;
-  },
+};
 
-  /**
-   * Calculate the hashed path for a stripped article URL.
-   *
-   * @param url The article URL. This should have referrers removed.
-   * @return The file path to the cached article.
-   */
-  _toHashedPath(url) {
-    let value = this._unicodeConverter.convertToByteArray(url);
-    this._cryptoHash.init(this._cryptoHash.MD5);
-    this._cryptoHash.update(value, value.length);
-
-    let hash = CommonUtils.encodeBase32(this._cryptoHash.finish(false));
-    let fileName = hash.substring(0, hash.indexOf("=")) + ".json";
-    return OS.Path.join(OS.Constants.Path.profileDir, "readercache", fileName);
-  },
-
-  /**
-   * Ensures the cache directory exists.
-   *
-   * @return Promise
-   * @resolves When the cache directory exists.
-   * @rejects OS.File.Error
-   */
-  _ensureCacheDir() {
-    let dir = OS.Path.join(OS.Constants.Path.profileDir, "readercache");
-    return OS.File.exists(dir).then(exists => {
-      if (!exists) {
-        return OS.File.makeDir(dir);
-      }
-      return undefined;
-    });
-  },
-
-  /**
-   * Sets a global language string value if the result is confident
-   *
-   * @return Promise
-   * @resolves when the language is detected
-   */
-  _assignLanguage(article) {
-    return LanguageDetector.detectLanguage(article.textContent).then(result => {
-      article.language = result.confident ? result.language : null;
-    });
-  },
-
-  _maybeAssignTextDirection(article) {
-    // TODO: Remove the hardcoded language codes below once bug 1320265 is resolved.
-    if (!article.dir && ["ar", "fa", "he", "ug", "ur"].includes(article.language)) {
-      article.dir = "rtl";
-    }
-  },
-
-  /**
-   * Assigns the estimated reading time range of the article to the article object.
-   *
-   * @param article the article object to assign the reading time estimate to.
-   */
-  _assignReadTime(article) {
-    let lang = article.language || "en";
-    const readingSpeed = this._getReadingSpeedForLanguage(lang);
-    const charactersPerMinuteLow = readingSpeed.cpm - readingSpeed.variance;
-    const charactersPerMinuteHigh = readingSpeed.cpm + readingSpeed.variance;
-    const length = article.length;
-
-    article.readingTimeMinsSlow = Math.ceil(length / charactersPerMinuteLow);
-    article.readingTimeMinsFast  = Math.ceil(length / charactersPerMinuteHigh);
-  },
-
-  /**
-   * Returns the reading speed of a selection of languages with likely variance.
-   *
-   * Reading speed estimated from a study done on reading speeds in various languages.
-   * study can be found here: http://iovs.arvojournals.org/article.aspx?articleid=2166061
-   *
-   * @return object with characters per minute and variance. Defaults to English
-   *         if no suitable language is found in the collection.
-   */
-  _getReadingSpeedForLanguage(lang) {
-    const readingSpeed = new Map([
-      [ "en", {cpm: 987,  variance: 118 } ],
-      [ "ar", {cpm: 612,  variance: 88 } ],
-      [ "de", {cpm: 920,  variance: 86 } ],
-      [ "es", {cpm: 1025, variance: 127 } ],
-      [ "fi", {cpm: 1078, variance: 121 } ],
-      [ "fr", {cpm: 998,  variance: 126 } ],
-      [ "he", {cpm: 833,  variance: 130 } ],
-      [ "it", {cpm: 950,  variance: 140 } ],
-      [ "jw", {cpm: 357,  variance: 56 } ],
-      [ "nl", {cpm: 978,  variance: 143 } ],
-      [ "pl", {cpm: 916,  variance: 126 } ],
-      [ "pt", {cpm: 913,  variance: 145 } ],
-      [ "ru", {cpm: 986,  variance: 175 } ],
-      [ "sk", {cpm: 885,  variance: 145 } ],
-      [ "sv", {cpm: 917,  variance: 156 } ],
-      [ "tr", {cpm: 1054, variance: 156 } ],
-      [ "zh", {cpm: 255,  variance: 29 } ],
-    ]);
-
-    return readingSpeed.get(lang) || readingSpeed.get("en");
-  },
-};
+XPCOMUtils.defineLazyPreferenceGetter(
+  Readerable, "isEnabled", "reader.parse-on-load.enabled", true);
+XPCOMUtils.defineLazyPreferenceGetter(
+  Readerable, "isForceEnabled", "reader.parse-on-load.force-enabled", false);
new file mode 100644
--- /dev/null
+++ b/toolkit/components/reader/Readerable.jsm
@@ -0,0 +1,10 @@
+// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var EXPORTED_SYMBOLS = ["Readerable"];
+
+#include Readability-readerable.js
+#include Readerable.js
--- a/toolkit/components/reader/moz.build
+++ b/toolkit/components/reader/moz.build
@@ -3,24 +3,28 @@
 # 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/.
 
 JAR_MANIFESTS += ['jar.mn']
 
 EXTRA_JS_MODULES += [
   'AboutReader.jsm',
-  'ReaderMode.jsm'
+  'ReaderMode.jsm',
+]
+
+EXTRA_PP_JS_MODULES += [
+  'Readerable.jsm',
 ]
 
 EXTRA_JS_MODULES.reader = [
   'JSDOMParser.js',
   'Readability.js',
   'ReaderWorker.js',
-  'ReaderWorker.jsm'
+  'ReaderWorker.jsm',
 ]
 
 BROWSER_CHROME_MANIFESTS += [
   'test/browser.ini'
 ]
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Reader Mode')
--- a/toolkit/crashreporter/CrashAnnotations.yaml
+++ b/toolkit/crashreporter/CrashAnnotations.yaml
@@ -573,16 +573,22 @@ ProxyStreamUnmarshalStatus:
     the various value this annotation can take.
   type: string
 
 ProxyStreamValid:
   description: >
     Set to "false" when encountering an invalid IPC proxy stream.
   type: string
 
+RecordReplay:
+  description: >
+    Set to 1 if this crash happened in a Web Replay middleman, recording,
+    or replaying process.
+  type: boolean
+
 RecordReplayError:
   description: >
     Any fatal error that occurred while recording/replaying a tab.
   type: string
 
 RecordReplayHang:
   description: >
     The presence of this annotation indicates that this crash was generated in
--- a/toolkit/crashreporter/nsDummyExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp
@@ -60,16 +60,21 @@ SetupExtraData(nsIFile* aAppDataDirector
 }
 
 nsresult
 UnsetExceptionHandler()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+void
+NotifyCrashReporterClientCreated()
+{
+}
+
 nsresult
 AnnotateCrashReport(Annotation key, bool data)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
 AnnotateCrashReport(Annotation key, int data)
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -2125,18 +2125,18 @@ static void
 EnqueueDelayedNote(DelayedNote* aNote)
 {
   if (!gDelayedAnnotations) {
     gDelayedAnnotations = new nsTArray<nsAutoPtr<DelayedNote> >();
   }
   gDelayedAnnotations->AppendElement(aNote);
 }
 
-static void
-RunAndCleanUpDelayedNotes()
+void
+NotifyCrashReporterClientCreated()
 {
   if (gDelayedAnnotations) {
     for (nsAutoPtr<DelayedNote>& note : *gDelayedAnnotations) {
       note->Run();
     }
     delete gDelayedAnnotations;
     gDelayedAnnotations = nullptr;
   }
@@ -3564,17 +3564,16 @@ SetRemoteExceptionHandler(const nsACStri
     ChildFPEFilter,
     nullptr, // no minidump callback
     reinterpret_cast<void*>(aCrashTimeAnnotationFile),
     google_breakpad::ExceptionHandler::HANDLER_ALL,
     GetMinidumpType(),
     NS_ConvertASCIItoUTF16(crashPipe).get(),
     nullptr);
   gExceptionHandler->set_handle_debug_exceptions(true);
-  RunAndCleanUpDelayedNotes();
 
 #ifdef _WIN64
   SetJitExceptionHandler();
 #endif
 
   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
 
   oldTerminateHandler = std::set_terminate(&TerminateHandler);
@@ -3617,17 +3616,16 @@ SetRemoteExceptionHandler()
 
   gExceptionHandler = new google_breakpad::
     ExceptionHandler(path,
                      ChildFilter,
                      nullptr,    // no minidump callback
                      nullptr,    // no callback context
                      true,       // install signal handlers
                      gMagicChildCrashReportFd);
-  RunAndCleanUpDelayedNotes();
 
   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
 
   oldTerminateHandler = std::set_terminate(&TerminateHandler);
 
   install_rust_panic_hook();
 
   // we either do remote or nothing, no fallback to regular crash reporting
@@ -3648,17 +3646,16 @@ SetRemoteExceptionHandler(const nsACStri
 
   gExceptionHandler = new google_breakpad::
     ExceptionHandler("",
                      ChildFilter,
                      nullptr,    // no minidump callback
                      nullptr,    // no callback context
                      true,       // install signal handlers
                      crashPipe.BeginReading());
-  RunAndCleanUpDelayedNotes();
 
   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
 
   oldTerminateHandler = std::set_terminate(&TerminateHandler);
 
   install_rust_panic_hook();
 
   // we either do remote or nothing, no fallback to regular crash reporting
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -95,16 +95,20 @@ nsresult SetMinidumpPath(const nsAString
 // process, but may only be called from the main thread in a content process.
 nsresult AnnotateCrashReport(Annotation key, bool data);
 nsresult AnnotateCrashReport(Annotation key, int data);
 nsresult AnnotateCrashReport(Annotation key, unsigned int data);
 nsresult AnnotateCrashReport(Annotation key, const nsACString& data);
 nsresult RemoveCrashReportAnnotation(Annotation key);
 nsresult AppendAppNotesToCrashReport(const nsACString& data);
 
+// Called after the crash reporter client has been created in a content
+// process, allowing annotations to be processed.
+void NotifyCrashReporterClientCreated();
+
 void AnnotateOOMAllocationSize(size_t size);
 void AnnotateTexturesSize(size_t size);
 nsresult SetGarbageCollecting(bool collecting);
 void SetEventloopNestingLevel(uint32_t level);
 void SetMinidumpAnalysisAllThreads();
 
 nsresult SetRestartArgs(int argc, char** argv);
 nsresult SetupExtraData(nsIFile* aAppDataDirectory,
--- a/toolkit/crashreporter/tools/unit-symbolstore.py
+++ b/toolkit/crashreporter/tools/unit-symbolstore.py
@@ -486,17 +486,17 @@ class TestFunctional(HelperMixin, unitte
             self.target_bin = os.path.join(buildconfig.topobjdir,
                                            'dist', 'bin',
                                            'firefox.exe')
         else:
             self.dump_syms = os.path.join(buildconfig.topobjdir,
                                           'dist', 'host', 'bin',
                                           'dump_syms')
             self.target_bin = os.path.join(buildconfig.topobjdir,
-                                           'dist', 'bin', 'firefox')
+                                           'dist', 'bin', 'firefox-bin')
 
 
     def tearDown(self):
         HelperMixin.tearDown(self)
 
     def testSymbolstore(self):
         if self.skip_test:
             raise unittest.SkipTest('Skipping test in non-Firefox product')
--- a/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
+++ b/toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js
@@ -14,17 +14,21 @@ const BIN_SUFFIX = "@BIN_SUFFIX@";
 #ifdef MOZ_APP_VENDOR
 const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@";
 #else
 const MOZ_APP_VENDOR = "";
 #endif
 
 // MOZ_APP_BASENAME is not optional for tests.
 const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@";
+#ifdef XP_LINUX
+const APP_BIN_SUFFIX = "-bin";
+#else
 const APP_BIN_SUFFIX = "@BIN_SUFFIX@";
+#endif
 
 const APP_INFO_NAME = "XPCShell";
 const APP_INFO_VENDOR = "Mozilla";
 
 #ifdef XP_WIN
 const IS_WIN = true;
 #else
 const IS_WIN = false;
--- a/toolkit/recordreplay/Callback.cpp
+++ b/toolkit/recordreplay/Callback.cpp
@@ -24,18 +24,16 @@ void
 RegisterCallbackData(void* aData)
 {
   MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
   MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
   if (!aData) {
     return;
   }
 
-  RecordReplayAssert("RegisterCallbackData");
-
   AutoOrderedAtomicAccess at;
   StaticMutexAutoLock lock(gCallbackMutex);
   if (!gCallbackData) {
     gCallbackData = new ValueIndex();
   }
   gCallbackData->Insert(aData);
 }
 
@@ -67,24 +65,20 @@ EndCallback()
     child::BeginIdleTime();
   }
   thread->SetPassThrough(true);
 }
 
 void
 SaveOrRestoreCallbackData(void** aData)
 {
-  MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
   MOZ_RELEASE_ASSERT(gCallbackData);
 
   Thread* thread = Thread::Current();
-
-  RecordReplayAssert("RestoreCallbackData");
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::RestoreCallbackData);
 
   size_t index = 0;
   if (IsRecording() && *aData) {
     StaticMutexAutoLock lock(gCallbackMutex);
     index = gCallbackData->GetIndex(*aData);
   }
@@ -102,20 +96,18 @@ RemoveCallbackData(void* aData)
 
   StaticMutexAutoLock lock(gCallbackMutex);
   gCallbackData->Remove(aData);
 }
 
 void
 PassThroughThreadEventsAllowCallbacks(const std::function<void()>& aFn)
 {
-  MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-
   Thread* thread = Thread::Current();
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   if (IsRecording()) {
     if (thread->IsMainThread()) {
       child::BeginIdleTime();
     }
     thread->SetPassThrough(true);
     aFn();
     if (thread->IsMainThread()) {
--- a/toolkit/recordreplay/File.cpp
+++ b/toolkit/recordreplay/File.cpp
@@ -46,17 +46,17 @@ Stream::ReadBytes(void* aData, size_t aS
       return;
     }
 
     MOZ_RELEASE_ASSERT(mBufferPos == mBufferLength);
 
     // If we try to read off the end of a stream then we must have hit the end
     // of the replay for this thread.
     while (mChunkIndex == mChunks.length()) {
-      MOZ_RELEASE_ASSERT(mName == StreamName::Event || mName == StreamName::Assert);
+      MOZ_RELEASE_ASSERT(mName == StreamName::Event);
       HitEndOfRecording();
     }
 
     const StreamChunkLocation& chunk = mChunks[mChunkIndex++];
 
     EnsureMemory(&mBallast, &mBallastSize, chunk.mCompressedSize, BallastMaxSize(),
                  DontCopyExistingData);
     mFile->ReadChunk(mBallast.get(), chunk);
@@ -151,24 +151,83 @@ Stream::WriteScalar(size_t aValue)
     if (aValue) {
       bits |= 128;
     }
     WriteBytes(&bits, 1);
   } while (aValue);
 }
 
 void
+Stream::RecordOrReplayThreadEvent(ThreadEvent aEvent)
+{
+  if (IsRecording()) {
+    WriteScalar((size_t) aEvent);
+  } else {
+    ThreadEvent oldEvent = (ThreadEvent) ReadScalar();
+    if (oldEvent != aEvent) {
+      child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s Replayed %s",
+                              ThreadEventName(oldEvent), ThreadEventName(aEvent));
+    }
+    mLastEvent = aEvent;
+  }
+
+  // Check the execution progress counter for events executing on the main thread.
+  if (mNameIndex == MainThreadId) {
+    CheckInput(*ExecutionProgressCounter());
+  }
+}
+
+void
 Stream::CheckInput(size_t aValue)
 {
-  size_t oldValue = aValue;
-  RecordOrReplayScalar(&oldValue);
-  if (oldValue != aValue) {
-    child::ReportFatalError(Nothing(), "Input Mismatch: Recorded: %zu Replayed %zu\n",
-                            oldValue, aValue);
-    Unreachable();
+  if (IsRecording()) {
+    WriteScalar(aValue);
+  } else {
+    size_t oldValue = ReadScalar();
+    if (oldValue != aValue) {
+      child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %llu Replayed %llu",
+                              ThreadEventName(mLastEvent), oldValue, aValue);
+    }
+  }
+}
+
+void
+Stream::CheckInput(const char* aValue)
+{
+  size_t len = strlen(aValue);
+  if (IsRecording()) {
+    WriteScalar(len);
+    WriteBytes(aValue, len);
+  } else {
+    size_t oldLen = ReadScalar();
+    EnsureInputBallast(oldLen + 1);
+    ReadBytes(mInputBallast.get(), oldLen);
+    mInputBallast[oldLen] = 0;
+
+    if (len != oldLen || memcmp(aValue, mInputBallast.get(), len) != 0) {
+      child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %s Replayed %s",
+                              ThreadEventName(mLastEvent), mInputBallast.get(), aValue);
+    }
+  }
+}
+
+void
+Stream::CheckInput(const void* aData, size_t aSize)
+{
+  CheckInput(aSize);
+  if (IsRecording()) {
+    WriteBytes(aData, aSize);
+  } else {
+    EnsureInputBallast(aSize);
+    ReadBytes(mInputBallast.get(), aSize);
+
+    if (memcmp(aData, mInputBallast.get(), aSize) != 0) {
+      child::ReportFatalError(Nothing(), "Input Buffer Mismatch: %s",
+                              ThreadEventName(mLastEvent));
+    }
   }
 }
 
 void
 Stream::EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize,
                      size_t aNeededSize, size_t aMaxSize, ShouldCopy aCopy)
 {
   // Once a stream buffer grows, it never shrinks again. Buffers start out
@@ -182,16 +241,22 @@ Stream::EnsureMemory(UniquePtr<char[]>* 
       memcpy(newBuf, aBuf->get(), *aSize);
     }
     aBuf->reset(newBuf);
     *aSize = newSize;
   }
 }
 
 void
+Stream::EnsureInputBallast(size_t aSize)
+{
+  EnsureMemory(&mInputBallast, &mInputBallastSize, aSize, (size_t) -1, DontCopyExistingData);
+}
+
+void
 Stream::Flush(bool aTakeLock)
 {
   MOZ_RELEASE_ASSERT(mFile && mFile->OpenForWriting());
 
   if (!mBufferPos) {
     return;
   }
 
--- a/toolkit/recordreplay/File.h
+++ b/toolkit/recordreplay/File.h
@@ -51,17 +51,16 @@ struct StreamChunkLocation
   }
 };
 
 enum class StreamName
 {
   Main,
   Lock,
   Event,
-  Assert,
   Count
 };
 
 class File;
 
 class Stream
 {
   friend class File;
@@ -98,16 +97,23 @@ class Stream
 
   // The number of uncompressed bytes read or written from the stream.
   size_t mStreamPos;
 
   // Any buffer available for use when decompressing or compressing data.
   UniquePtr<char[]> mBallast;
   size_t mBallastSize;
 
+  // Any buffer available to check for input mismatches.
+  UniquePtr<char[]> mInputBallast;
+  size_t mInputBallastSize;
+
+  // The last event in this stream, in case of an input mismatch.
+  ThreadEvent mLastEvent;
+
   // The number of chunks that have been completely read or written. When
   // writing, this equals mChunks.length().
   size_t mChunkIndex;
 
   // When writing, the number of chunks in this stream when the file was last
   // flushed.
   size_t mFlushedChunks;
 
@@ -117,16 +123,19 @@ class Stream
     , mNameIndex(aNameIndex)
     , mBuffer(nullptr)
     , mBufferSize(0)
     , mBufferLength(0)
     , mBufferPos(0)
     , mStreamPos(0)
     , mBallast(nullptr)
     , mBallastSize(0)
+    , mInputBallast(nullptr)
+    , mInputBallastSize(0)
+    , mLastEvent((ThreadEvent) 0)
     , mChunkIndex(0)
     , mFlushedChunks(0)
   {}
 
 public:
   StreamName Name() const { return mName; }
   size_t NameIndex() const { return mNameIndex; }
 
@@ -153,40 +162,39 @@ public:
     }
   }
 
   template <typename T>
   inline void RecordOrReplayValue(T* aPtr) {
     RecordOrReplayBytes(aPtr, sizeof(T));
   }
 
-  // Make sure that a value is the same while replaying as it was while
-  // recording.
-  void CheckInput(size_t aValue);
+  // Note a new thread event for this stream, and make sure it is the same
+  // while replaying as it was while recording.
+  void RecordOrReplayThreadEvent(ThreadEvent aEvent);
 
-  // Add a thread event to this file. Each thread event in a file is followed
-  // by additional data specific to that event. Generally, CheckInput should be
-  // used while recording or replaying the data for a thread event so that any
-  // discrepancies with the recording are found immediately.
-  inline void RecordOrReplayThreadEvent(ThreadEvent aEvent) {
-    CheckInput((size_t)aEvent);
-  }
+  // Make sure that a value or buffer is the same while replaying as it was
+  // while recording.
+  void CheckInput(size_t aValue);
+  void CheckInput(const char* aValue);
+  void CheckInput(const void* aData, size_t aSize);
 
   inline size_t StreamPosition() {
     return mStreamPos;
   }
 
 private:
   enum ShouldCopy {
     DontCopyExistingData,
     CopyExistingData
   };
 
   void EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize, size_t aNeededSize, size_t aMaxSize,
                     ShouldCopy aCopy);
+  void EnsureInputBallast(size_t aSize);
   void Flush(bool aTakeLock);
 
   static size_t BallastMaxSize();
 };
 
 class File
 {
 public:
--- a/toolkit/recordreplay/Lock.cpp
+++ b/toolkit/recordreplay/Lock.cpp
@@ -63,25 +63,23 @@ static ChunkAllocator<LockAcquires> gLoc
 // every recorded lock in existence.
 typedef std::unordered_map<void*, Lock*> LockMap;
 static LockMap* gLocks;
 static ReadWriteSpinLock gLocksLock;
 
 /* static */ void
 Lock::New(void* aNativeLock)
 {
-  if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
+  Thread* thread = Thread::Current();
+  if (!thread || thread->PassThroughEvents() || HasDivergedFromRecording()) {
     Destroy(aNativeLock); // Clean up any old lock, as below.
     return;
   }
 
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-  Thread* thread = Thread::Current();
-
-  RecordReplayAssert("CreateLock");
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::CreateLock);
 
   size_t id;
   if (IsRecording()) {
     id = gNumLocks++;
   }
   thread->Events().RecordOrReplayScalar(&id);
@@ -89,17 +87,17 @@ Lock::New(void* aNativeLock)
   LockAcquires* info = gLockAcquires.Create(id);
   info->mAcquires = gRecordingFile->OpenStream(StreamName::Lock, id);
 
   if (IsReplaying()) {
     info->ReadAndNotifyNextOwner(thread);
   }
 
   // Tolerate new locks being created with identical pointers, even if there
-  // was no DestroyLock call for the old one.
+  // was no explicit Destroy() call for the old one.
   Destroy(aNativeLock);
 
   AutoWriteSpinLock ex(gLocksLock);
   thread->BeginDisallowEvents();
 
   if (!gLocks) {
     gLocks = new LockMap();
   }
@@ -148,26 +146,23 @@ Lock::Find(void* aNativeLock)
   }
 
   return nullptr;
 }
 
 void
 Lock::Enter()
 {
-  MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough() && !HasDivergedFromRecording());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-
-  RecordReplayAssert("Lock %d", (int) mId);
+  Thread* thread = Thread::Current();
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   // Include an event in each thread's record when a lock acquire begins. This
   // is not required by the replay but is used to check that lock acquire order
   // is consistent with the recording and that we will fail explicitly instead
   // of deadlocking.
-  Thread* thread = Thread::Current();
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Lock);
   thread->Events().CheckInput(mId);
 
   LockAcquires* acquires = gLockAcquires.Get(mId);
   if (IsRecording()) {
     acquires->mAcquires->WriteScalar(thread->Id());
   } else {
     // Wait until this thread is next in line to acquire the lock.
--- a/toolkit/recordreplay/ProcessRecordReplay.cpp
+++ b/toolkit/recordreplay/ProcessRecordReplay.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ProcessRecordReplay.h"
 
 #include "ipc/ChildInternal.h"
 #include "mozilla/Compression.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Sprintf.h"
-#include "mozilla/StackWalk.h"
 #include "mozilla/StaticMutex.h"
 #include "DirtyMemoryHandler.h"
 #include "Lock.h"
 #include "MemorySnapshot.h"
 #include "ProcessRedirect.h"
 #include "ProcessRewind.h"
 #include "Trigger.h"
 #include "ValueIndex.h"
@@ -40,18 +39,16 @@ BusyWait()
 ///////////////////////////////////////////////////////////////////////////////
 
 File* gRecordingFile;
 const char* gSnapshotMemoryPrefix;
 const char* gSnapshotStackPrefix;
 
 char* gInitializationFailureMessage;
 
-static void DumpRecordingAssertions();
-
 bool gInitialized;
 ProcessKind gProcessKind;
 char* gRecordingFilename;
 
 // Current process ID.
 static int gPid;
 
 // Whether to spew record/replay messages to stderr.
@@ -136,20 +133,16 @@ RecordReplayInterface_Initialize(int aAr
   Thread::InitializeThreads();
 
   Thread* thread = Thread::GetById(MainThreadId);
   MOZ_ASSERT(thread->Id() == MainThreadId);
 
   thread->BindToCurrent();
   thread->SetPassThrough(true);
 
-  if (IsReplaying() && TestEnv("DUMP_RECORDING")) {
-    DumpRecordingAssertions();
-  }
-
   InitializeTriggers();
   InitializeWeakPointers();
   InitializeMemorySnapshots();
   Thread::SpawnAllThreads();
   InitializeCountdownThread();
   SetupDirtyMemoryHandler();
 
   // Don't create a stylo thread pool when recording or replaying.
@@ -161,46 +154,38 @@ RecordReplayInterface_Initialize(int aAr
   InitializeRewindState();
 
   gInitialized = true;
 }
 
 MOZ_EXPORT size_t
 RecordReplayInterface_InternalRecordReplayValue(size_t aValue)
 {
-  MOZ_ASSERT(IsRecordingOrReplaying());
-
-  if (AreThreadEventsPassedThrough()) {
+  Thread* thread = Thread::Current();
+  if (thread->PassThroughEvents()) {
     return aValue;
   }
   EnsureNotDivergedFromRecording();
 
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-  Thread* thread = Thread::Current();
-
-  RecordReplayAssert("Value");
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Value);
   thread->Events().RecordOrReplayValue(&aValue);
   return aValue;
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRecordReplayBytes(void* aData, size_t aSize)
 {
-  MOZ_ASSERT(IsRecordingOrReplaying());
-
-  if (AreThreadEventsPassedThrough()) {
+  Thread* thread = Thread::Current();
+  if (thread->PassThroughEvents()) {
     return;
   }
   EnsureNotDivergedFromRecording();
 
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-  Thread* thread = Thread::Current();
-
-  RecordReplayAssert("Bytes %d", (int) aSize);
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
   thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Bytes);
   thread->Events().CheckInput(aSize);
   thread->Events().RecordOrReplayBytes(aData, aSize);
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalInvalidateRecording(const char* aWhy)
 {
@@ -322,302 +307,67 @@ InternalPrint(const char* aFormat, va_li
 {
   char buf1[2048];
   VsprintfLiteral(buf1, aFormat, aArgs);
   char buf2[2048];
   SprintfLiteral(buf2, "Spew[%d]: %s", gPid, buf1);
   DirectPrint(buf2);
 }
 
+const char*
+ThreadEventName(ThreadEvent aEvent)
+{
+  switch (aEvent) {
+#define EnumToString(Kind) case ThreadEvent::Kind: return #Kind;
+    ForEachThreadEvent(EnumToString)
+#undef EnumToString
+  case ThreadEvent::CallStart: break;
+  }
+  size_t callId = (size_t) aEvent - (size_t) ThreadEvent::CallStart;
+  return gRedirections[callId].mName;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Record/Replay Assertions
 ///////////////////////////////////////////////////////////////////////////////
 
-struct StackWalkData
-{
-  char* mBuf;
-  size_t mSize;
-
-  StackWalkData(char* aBuf, size_t aSize)
-    : mBuf(aBuf), mSize(aSize)
-  {}
-
-  void append(const char* aText) {
-    size_t len = strlen(aText);
-    if (len <= mSize) {
-      strcpy(mBuf, aText);
-      mBuf += len;
-      mSize -= len;
-    }
-  }
-};
-
-static void
-StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
-{
-  StackWalkData* data = (StackWalkData*) aClosure;
-
-  MozCodeAddressDetails details;
-  MozDescribeCodeAddress(aPC, &details);
-
-  data->append(" ### ");
-  data->append(details.function[0] ? details.function : "???");
-}
-
-static void
-SetCurrentStackString(const char* aAssertion, char* aBuf, size_t aSize)
-{
-  size_t frameCount = 12;
-
-  // Locking operations usually have extra stack goop.
-  if (!strcmp(aAssertion, "Lock 1")) {
-    frameCount += 8;
-  } else if (!strncmp(aAssertion, "Lock ", 5)) {
-    frameCount += 4;
-  }
-
-  StackWalkData data(aBuf, aSize);
-  MozStackWalk(StackWalkCallback, /* aSkipFrames = */ 2, frameCount, &data);
-}
-
-// For debugging.
-char*
-PrintCurrentStackString()
-{
-  AutoEnsurePassThroughThreadEvents pt;
-  char* buf = new char[1000];
-  SetCurrentStackString("", buf, 1000);
-  return buf;
-}
-
-static inline bool
-AlwaysCaptureEventStack(const char* aText)
-{
-  return false;
-}
-
-// Bit included in assertion stream when the assertion is a text assert, rather
-// than a byte sequence.
-static const size_t AssertionBit = 1;
-
 extern "C" {
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRecordReplayAssert(const char* aFormat, va_list aArgs)
 {
-#ifdef INCLUDE_RECORD_REPLAY_ASSERTIONS
-  if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
+  Thread* thread = Thread::Current();
+  if (thread->PassThroughEvents() || thread->HasDivergedFromRecording()) {
     return;
   }
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-  Thread* thread = Thread::Current();
-
-  // Record an assertion string consisting of the name of the assertion and
-  // stack information about the current point of execution.
+  // Add the asserted string to the recording.
   char text[1024];
   VsprintfLiteral(text, aFormat, aArgs);
-  if (IsRecording() && (thread->ShouldCaptureEventStacks() || AlwaysCaptureEventStack(text))) {
-    AutoPassThroughThreadEvents pt;
-    SetCurrentStackString(text, text + strlen(text), sizeof(text) - strlen(text));
-  }
 
-  size_t textLen = strlen(text);
-
-  if (IsRecording()) {
-    thread->Asserts().WriteScalar(thread->Events().StreamPosition());
-    if (thread->IsMainThread()) {
-      thread->Asserts().WriteScalar(*ExecutionProgressCounter());
-    }
-    thread->Asserts().WriteScalar((textLen << 1) | AssertionBit);
-    thread->Asserts().WriteBytes(text, textLen);
-  } else {
-    // While replaying, both the assertion's name and the current position in
-    // the thread's events need to match up with what was recorded. The stack
-    // portion of the assertion text does not need to match, it is used to help
-    // track down the reason for the mismatch.
-    bool match = true;
-    size_t streamPos = thread->Asserts().ReadScalar();
-    if (streamPos != thread->Events().StreamPosition()) {
-      match = false;
-    }
-    size_t progress = 0;
-    if (thread->IsMainThread()) {
-      progress = thread->Asserts().ReadScalar();
-      if (progress != *ExecutionProgressCounter()) {
-        match = false;
-      }
-    }
-    size_t assertLen = thread->Asserts().ReadScalar() >> 1;
-
-    char* buffer = thread->TakeBuffer(assertLen + 1);
-
-    thread->Asserts().ReadBytes(buffer, assertLen);
-    buffer[assertLen] = 0;
-
-    if (assertLen < textLen || memcmp(buffer, text, textLen) != 0) {
-      match = false;
-    }
-
-    if (!match) {
-      for (int i = Thread::NumRecentAsserts - 1; i >= 0; i--) {
-        if (thread->RecentAssert(i).mText) {
-          Print("Thread %d Recent %d: %s [%d]\n",
-                (int) thread->Id(), (int) i,
-                thread->RecentAssert(i).mText, (int) thread->RecentAssert(i).mPosition);
-        }
-      }
-
-      {
-        AutoPassThroughThreadEvents pt;
-        SetCurrentStackString(text, text + strlen(text), sizeof(text) - strlen(text));
-      }
-
-      child::ReportFatalError(Nothing(),
-                              "Assertion Mismatch: Thread %d\n"
-                              "Recorded: %s [%d,%d]\n"
-                              "Replayed: %s [%d,%d]\n",
-                              (int) thread->Id(), buffer, (int) streamPos, (int) progress, text,
-                              (int) thread->Events().StreamPosition(),
-                              (int) (thread->IsMainThread() ? *ExecutionProgressCounter() : 0));
-      Unreachable();
-    }
-
-    thread->RestoreBuffer(buffer);
-
-    // Push this assert onto the recent assertions in the thread.
-    free(thread->RecentAssert(Thread::NumRecentAsserts - 1).mText);
-    for (size_t i = Thread::NumRecentAsserts - 1; i >= 1; i--) {
-      thread->RecentAssert(i) = thread->RecentAssert(i - 1);
-    }
-    thread->RecentAssert(0).mText = strdup(text);
-    thread->RecentAssert(0).mPosition = thread->Events().StreamPosition();
-  }
-#endif // INCLUDE_RECORD_REPLAY_ASSERTIONS
+  thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Assert);
+  thread->Events().CheckInput(text);
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRecordReplayAssertBytes(const void* aData, size_t aSize)
 {
-#ifdef INCLUDE_RECORD_REPLAY_ASSERTIONS
-  RecordReplayAssert("AssertBytes");
-
-  if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
+  Thread* thread = Thread::Current();
+  if (thread->PassThroughEvents() || thread->HasDivergedFromRecording()) {
     return;
   }
-
-  MOZ_ASSERT(!AreThreadEventsDisallowed());
-  Thread* thread = Thread::Current();
-
-  if (IsRecording()) {
-    thread->Asserts().WriteScalar(thread->Events().StreamPosition());
-    thread->Asserts().WriteScalar(aSize << 1);
-    thread->Asserts().WriteBytes(aData, aSize);
-  } else {
-    bool match = true;
-    size_t streamPos = thread->Asserts().ReadScalar();
-    if (streamPos != thread->Events().StreamPosition()) {
-      match = false;
-    }
-    size_t oldSize = thread->Asserts().ReadScalar() >> 1;
-    if (oldSize != aSize) {
-      match = false;
-    }
-
-    char* buffer = thread->TakeBuffer(oldSize);
-
-    thread->Asserts().ReadBytes(buffer, oldSize);
-    if (match && memcmp(buffer, aData, oldSize) != 0) {
-      match = false;
-    }
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
-    if (!match) {
-      // On a byte mismatch, print out some of the mismatched bytes, up to a
-      // cutoff in case there are many mismatched bytes.
-      if (oldSize == aSize) {
-        static const size_t MAX_MISMATCHES = 100;
-        size_t mismatches = 0;
-        for (size_t i = 0; i < aSize; i++) {
-          if (((char*)aData)[i] != buffer[i]) {
-            Print("Position %d: %d %d\n", (int) i, (int) buffer[i], (int) ((char*)aData)[i]);
-            if (++mismatches == MAX_MISMATCHES) {
-              break;
-            }
-          }
-        }
-        if (mismatches == MAX_MISMATCHES) {
-          Print("Position ...\n");
-        }
-      }
-
-      child::ReportFatalError(Nothing(),
-                              "Byte Comparison Check Failed: Position %d %d Length %d %d\n",
-                              (int) streamPos, (int) thread->Events().StreamPosition(),
-                              (int) oldSize, (int) aSize);
-      Unreachable();
-    }
-
-    thread->RestoreBuffer(buffer);
-  }
-#endif // INCLUDE_RECORD_REPLAY_ASSERTIONS
-}
-
-MOZ_EXPORT void
-RecordReplayRust_Assert(const uint8_t* aBuffer)
-{
-  RecordReplayAssert("%s", (const char*) aBuffer);
-}
-
-MOZ_EXPORT void
-RecordReplayRust_BeginPassThroughThreadEvents()
-{
-  BeginPassThroughThreadEvents();
-}
-
-MOZ_EXPORT void
-RecordReplayRust_EndPassThroughThreadEvents()
-{
-  EndPassThroughThreadEvents();
+  thread->Events().RecordOrReplayThreadEvent(ThreadEvent::AssertBytes);
+  thread->Events().CheckInput(aData, aSize);
 }
 
 } // extern "C"
 
-static void
-DumpRecordingAssertions()
-{
-  Thread* thread = Thread::Current();
-
-  for (size_t id = MainThreadId; id <= MaxRecordedThreadId; id++) {
-    Stream* asserts = gRecordingFile->OpenStream(StreamName::Assert, id);
-    if (asserts->AtEnd()) {
-      continue;
-    }
-
-    fprintf(stderr, "Thread Assertions %d:\n", (int) id);
-    while (!asserts->AtEnd()) {
-      (void) asserts->ReadScalar();
-      size_t shiftedLen = asserts->ReadScalar();
-      size_t assertLen = shiftedLen >> 1;
-
-      char* buffer = thread->TakeBuffer(assertLen + 1);
-      asserts->ReadBytes(buffer, assertLen);
-      buffer[assertLen] = 0;
-
-      if (shiftedLen & AssertionBit) {
-        fprintf(stderr, "%s\n", buffer);
-      }
-
-      thread->RestoreBuffer(buffer);
-    }
-  }
-
-  fprintf(stderr, "Done with assertions, exiting...\n");
-  _exit(0);
-}
-
 static ValueIndex* gGenericThings;
 static StaticMutexNotRecorded gGenericThingsMutex;
 
 extern "C" {
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalRegisterThing(void* aThing)
 {
--- a/toolkit/recordreplay/ProcessRecordReplay.h
+++ b/toolkit/recordreplay/ProcessRecordReplay.h
@@ -19,78 +19,82 @@ namespace recordreplay {
 //
 // See mfbt/RecordReplay.h for the main record/replay public API and a high
 // level description of the record/replay system.
 //
 // This directory contains files used for recording, replaying, and rewinding a
 // process. The ipc subdirectory contains files used for IPC between a
 // replaying and middleman process, and between a middleman and chrome process.
 
+// Instantiate _Macro for each of the platform independent thread events.
+#define ForEachThreadEvent(_Macro)                             \
+  /* Spawned another thread. */                                \
+  _Macro(CreateThread)                                        \
+                                                               \
+  /* Created a recorded lock. */                               \
+  _Macro(CreateLock)                                           \
+                                                               \
+  /* Acquired a recorded lock. */                              \
+  _Macro(Lock)                                                 \
+                                                               \
+  /* Called RecordReplayValue. */                              \
+  _Macro(Value)                                                \
+                                                               \
+  /* Called RecordReplayBytes. */                              \
+  _Macro(Bytes)                                                \
+                                                               \
+  /* Called RecordReplayAssert or RecordReplayAssertBytes. */  \
+  _Macro(Assert)                                               \
+  _Macro(AssertBytes)                                          \
+                                                               \
+  /* Executed a nested callback (see Callback.h). */           \
+  _Macro(ExecuteCallback)                                      \
+                                                               \
+  /* Finished executing nested callbacks in a library API (see Callback.h). */ \
+  _Macro(CallbacksFinished)                                    \
+                                                               \
+  /* Restoring a data pointer used in a callback (see Callback.h). */ \
+  _Macro(RestoreCallbackData)                                  \
+                                                               \
+  /* Called RegisterTrigger. */                                \
+  _Macro(RegisterTrigger)                                      \
+                                                               \
+  /* Executed a trigger within a call to ExecuteTriggers. */   \
+  _Macro(ExecuteTrigger)                                       \
+                                                               \
+  /* Finished executing triggers within a call to ExecuteTriggers. */ \
+  _Macro(ExecuteTriggersFinished)
+
 // ID of an event in a thread's event stream. Each ID in the stream is followed
-// by data associated with the event (see File::RecordOrReplayThreadEvent).
+// by data associated with the event.
 enum class ThreadEvent : uint32_t
 {
-  // Spawned another thread.
-  CreateThread,
-
-  // Created a recorded lock.
-  CreateLock,
-
-  // Acquired a recorded lock.
-  Lock,
-
-  // Wait for a condition variable with a timeout.
-  WaitForCvarUntil,
-
-  // Called RecordReplayValue.
-  Value,
-
-  // Called RecordReplayBytes.
-  Bytes,
-
-  // Executed a nested callback (see Callback.h).
-  ExecuteCallback,
-
-  // Finished executing nested callbacks in a library API (see Callback.h).
-  CallbacksFinished,
-
-  // Restoring a data pointer used in a callback (see Callback.h).
-  RestoreCallbackData,
-
-  // Executed a trigger within a call to ExecuteTriggers.
-  ExecuteTrigger,
-
-  // Finished executing triggers within a call to ExecuteTriggers.
-  ExecuteTriggersFinished,
-
-  // Encoded information about an argument/rval used by a graphics call.
-  GraphicsArgument,
-  GraphicsRval,
+#define DefineEnum(Kind) Kind,
+  ForEachThreadEvent(DefineEnum)
+#undef DefineEnum
 
   // The start of event IDs for redirected call events. Event IDs after this
   // point are platform specific.
   CallStart
 };
 
+// Get the printable name for a thread event.
+const char* ThreadEventName(ThreadEvent aEvent);
+
 class File;
 
 // File used during recording and replay.
 extern File* gRecordingFile;
 
 // Whether record/replay state has finished initialization.
 extern bool gInitialized;
 
 // If we failed to initialize, any associated message.
 extern char* gInitializationFailureMessage;
 
-// Whether record/replay assertions should be performed.
-//#ifdef DEBUG
-#define INCLUDE_RECORD_REPLAY_ASSERTIONS 1
-//#endif
-
 // Flush any new recording data to disk.
 void FlushRecording();
 
 // Called when any thread hits the end of its event stream.
 void HitEndOfRecording();
 
 // Called when the main thread hits the latest recording endpoint it knows
 // about.
--- a/toolkit/recordreplay/ProcessRedirect.h
+++ b/toolkit/recordreplay/ProcessRedirect.h
@@ -132,43 +132,49 @@ OriginalFunction(size_t aCallId)
 #define OriginalCallABI(aName, aReturnType, aABI, ...)          \
   TokenPaste(CallFunction, aABI) <aReturnType>                  \
     (OriginalFunction(CallEvent_ ##aName), ##__VA_ARGS__)
 
 // Call the original function for a call event ID with the default ABI.
 #define OriginalCall(aName, aReturnType, ...)                   \
   OriginalCallABI(aName, aReturnType, DEFAULTABI, ##__VA_ARGS__)
 
+static inline ThreadEvent
+CallIdToThreadEvent(size_t aCallId)
+{
+  return (ThreadEvent)((uint32_t)ThreadEvent::CallStart + aCallId);
+}
+
 // State for a function redirection which performs the standard steps (see the
 // comment at the start of this file). This should not be created directly, but
 // rather through one of the macros below.
 struct AutoRecordReplayFunctionVoid
 {
   // The current thread, or null if events are being passed through.
   Thread* mThread;
 
   // Any system error generated by the call which was redirected.
   ErrorType mError;
 
 protected:
   // Information about the call being recorded.
   size_t mCallId;
-  const char* mCallName;
 
 public:
-  AutoRecordReplayFunctionVoid(size_t aCallId, const char* aCallName)
-    : mThread(AreThreadEventsPassedThrough() ? nullptr : Thread::Current()),
-      mError(0), mCallId(aCallId), mCallName(aCallName)
+  explicit AutoRecordReplayFunctionVoid(size_t aCallId)
+    : mThread(Thread::Current()), mError(0), mCallId(aCallId)
   {
-    if (mThread) {
+    if (mThread && mThread->PassThroughEvents()) {
+      mThread = nullptr;
+    } else if (mThread) {
       // Calling any redirection which performs the standard steps will cause
       // debugger operations that have diverged from the recording to fail.
       EnsureNotDivergedFromRecording();
 
-      MOZ_ASSERT(!AreThreadEventsDisallowed());
+      MOZ_RELEASE_ASSERT(mThread->CanAccessRecording());
 
       // Pass through events in case we are calling the original function.
       mThread->SetPassThrough(true);
     }
   }
 
   ~AutoRecordReplayFunctionVoid()
   {
@@ -185,48 +191,46 @@ public:
 
     // Save any system error in case we want to record/replay it.
     mError = SaveError();
 
     // Stop the event passing through that was initiated in the constructor.
     mThread->SetPassThrough(false);
 
     // Add an event for the thread.
-    RecordReplayAssert("%s", mCallName);
-    ThreadEvent ev = (ThreadEvent)((uint32_t)ThreadEvent::CallStart + mCallId);
-    mThread->Events().RecordOrReplayThreadEvent(ev);
+    mThread->Events().RecordOrReplayThreadEvent(CallIdToThreadEvent(mCallId));
   }
 };
 
 // State for a function redirection that performs the standard steps and also
 // returns a value.
 template <typename ReturnType>
 struct AutoRecordReplayFunction : AutoRecordReplayFunctionVoid
 {
   // The value which this function call should return.
   ReturnType mRval;
 
-  AutoRecordReplayFunction(size_t aCallId, const char* aCallName)
-    : AutoRecordReplayFunctionVoid(aCallId, aCallName)
+  explicit AutoRecordReplayFunction(size_t aCallId)
+    : AutoRecordReplayFunctionVoid(aCallId)
   {}
 };
 
 // Macros for recording or replaying a function that performs the standard
 // steps. These macros should be used near the start of the body of a
 // redirection function, and will fall through only if events are not
 // passed through and the outputs of the function need to be recorded or
 // replayed.
 //
 // These macros define an AutoRecordReplayFunction local |rrf| with state for
 // the redirection, and additional locals |events| and (if the function has a
 // return value) |rval| for convenient access.
 
 // Record/replay a function that returns a value and has a particular ABI.
 #define RecordReplayFunctionABI(aName, aReturnType, aABI, ...)          \
-  AutoRecordReplayFunction<aReturnType> rrf(CallEvent_ ##aName, #aName); \
+  AutoRecordReplayFunction<aReturnType> rrf(CallEvent_ ##aName);        \
   if (!rrf.mThread) {                                                   \
     return OriginalCallABI(aName, aReturnType, aABI, ##__VA_ARGS__);    \
   }                                                                     \
   if (IsRecording()) {                                                  \
     rrf.mRval = OriginalCallABI(aName, aReturnType, aABI, ##__VA_ARGS__); \
   }                                                                     \
   rrf.StartRecordReplay();                                              \
   Stream& events = rrf.mThread->Events();                               \
@@ -234,17 +238,17 @@ struct AutoRecordReplayFunction : AutoRe
   aReturnType& rval = rrf.mRval
 
 // Record/replay a function that returns a value and has the default ABI.
 #define RecordReplayFunction(aName, aReturnType, ...)                   \
   RecordReplayFunctionABI(aName, aReturnType, DEFAULTABI, ##__VA_ARGS__)
 
 // Record/replay a function that has no return value and has a particular ABI.
 #define RecordReplayFunctionVoidABI(aName, aABI, ...)                   \
-  AutoRecordReplayFunctionVoid rrf(CallEvent_ ##aName, #aName);         \
+  AutoRecordReplayFunctionVoid rrf(CallEvent_ ##aName);                 \
   if (!rrf.mThread) {                                                   \
     OriginalCallABI(aName, void, aABI, ##__VA_ARGS__);                  \
     return;                                                             \
   }                                                                     \
   if (IsRecording()) {                                                  \
     OriginalCallABI(aName, void, aABI, ##__VA_ARGS__);                  \
   }                                                                     \
   rrf.StartRecordReplay();                                              \
--- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp
+++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp
@@ -659,18 +659,16 @@ RR_mmap(void* aAddress, size_t aSize, in
     } else if (memory && memory != (void*)-1) {
       RegisterAllocatedMemory(memory, RoundupSizeToPageBoundary(aSize), MemoryKind::Tracked);
     }
   }
 
   if (!(aFlags & MAP_ANON) && !AreThreadEventsPassedThrough()) {
     // Include the data just mapped in the recording.
     MOZ_RELEASE_ASSERT(memory && memory != (void*)-1);
-    RecordReplayAssert("mmap");
-    MOZ_RELEASE_ASSERT(aSize == RecordReplayValue(aSize));
     RecordReplayBytes(memory, aSize);
   }
 
   return memory;
 }
 
 static ssize_t
 RR_munmap(void* aAddress, size_t aSize)
@@ -1172,17 +1170,16 @@ static ssize_t
 WaitForCvar(pthread_mutex_t* aMutex, bool aRecordReturnValue,
             const std::function<ssize_t()>& aCallback)
 {
   Lock* lock = Lock::Find(aMutex);
   if (!lock) {
     AutoEnsurePassThroughThreadEvents pt;
     return aCallback();
   }
-  RecordReplayAssert("WaitForCvar %d", (int) lock->Id());
   ssize_t rv = 0;
   if (IsRecording()) {
     AutoPassThroughThreadEvents pt;
     rv = aCallback();
   } else {
     DirectUnlockMutex(aMutex);
   }
   lock->Exit();
@@ -1729,23 +1726,25 @@ struct NSFastEnumerationState
 // thrown by mutating the array while it is being iterated over.
 static unsigned long gNeverChange;
 
 extern "C" {
 
 size_t __attribute__((used))
 RecordReplayInterceptObjCMessage(MessageArguments* aArguments)
 {
-  if (AreThreadEventsPassedThrough()) {
+  Thread* thread = Thread::Current();
+  if (!thread || thread->PassThroughEvents()) {
     aArguments->scratch = (size_t) OriginalFunction(CallEvent_objc_msgSend);
     return 1;
   }
   EnsureNotDivergedFromRecording();
 
-  RecordReplayAssert("objc_msgSend: %s", aArguments->msg);
+  thread->Events().RecordOrReplayThreadEvent(CallIdToThreadEvent(CallEvent_objc_msgSend));
+  thread->Events().CheckInput(aArguments->msg);
 
   size_t rval = 0;
   double floatRval = 0;
   bool handled = false;
 
   // Watch for some top level NSApplication messages that can cause Gecko
   // events to be processed.
   if ((!strcmp(aArguments->msg, "run") ||
--- a/toolkit/recordreplay/ProcessRewind.cpp
+++ b/toolkit/recordreplay/ProcessRewind.cpp
@@ -178,34 +178,37 @@ NewCheckpoint(bool aTemporary)
 
   gRewindInfo->mLastCheckpoint = checkpoint;
 
   navigation::AfterCheckpoint(checkpoint);
 
   return reachedCheckpoint;
 }
 
-static bool gRecordingDiverged;
 static bool gUnhandledDivergeAllowed;
 
 void
 DivergeFromRecording()
 {
-  MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
   MOZ_RELEASE_ASSERT(IsReplaying());
-  gRecordingDiverged = true;
+
+  Thread* thread = Thread::Current();
+  MOZ_RELEASE_ASSERT(thread->IsMainThread());
+  thread->DivergeFromRecording();
+
   gUnhandledDivergeAllowed = true;
 }
 
 extern "C" {
 
 MOZ_EXPORT bool
 RecordReplayInterface_InternalHasDivergedFromRecording()
 {
-  return Thread::CurrentIsMainThread() && gRecordingDiverged;
+  Thread* thread = Thread::Current();
+  return thread && thread->HasDivergedFromRecording();
 }
 
 } // extern "C"
 
 void
 DisallowUnhandledDivergeFromRecording()
 {
   MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
@@ -245,17 +248,17 @@ MainThreadShouldPause()
   return gMainThreadShouldPause;
 }
 
 void
 PauseMainThreadAndServiceCallbacks()
 {
   MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
   MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
-  MOZ_RELEASE_ASSERT(!gRecordingDiverged);
+  MOZ_RELEASE_ASSERT(!HasDivergedFromRecording());
 
   // Whether there is a PauseMainThreadAndServiceCallbacks frame on the stack.
   static bool gMainThreadIsPaused = false;
 
   if (gMainThreadIsPaused) {
     return;
   }
   gMainThreadIsPaused = true;
@@ -278,17 +281,17 @@ PauseMainThreadAndServiceCallbacks()
   }
 
   // As for RestoreCheckpointAndResume, we shouldn't resume the main thread while
   // it still has callbacks to execute.
   MOZ_RELEASE_ASSERT(gMainThreadCallbacks.empty());
 
   // If we diverge from the recording the only way we can get back to resuming
   // normal execution is to rewind to a checkpoint prior to the divergence.
-  MOZ_RELEASE_ASSERT(!gRecordingDiverged);
+  MOZ_RELEASE_ASSERT(!HasDivergedFromRecording());
 
   gMainThreadIsPaused = false;
 }
 
 void
 PauseMainThreadAndInvokeCallback(const std::function<void()>& aCallback)
 {
   {
--- a/toolkit/recordreplay/Thread.cpp
+++ b/toolkit/recordreplay/Thread.cpp
@@ -120,17 +120,16 @@ Thread::InitializeThreads()
     Thread* thread = &gThreads[i];
     PodZero(thread);
     new(thread) Thread();
 
     thread->mId = i;
 
     if (i <= MaxRecordedThreadId) {
       thread->mEvents = gRecordingFile->OpenStream(StreamName::Event, i);
-      thread->mAsserts = gRecordingFile->OpenStream(StreamName::Assert, i);
     }
 
     DirectCreatePipe(&thread->mNotifyfd, &thread->mIdlefd);
   }
 
   if (!gTlsThreadKey.init()) {
     MOZ_CRASH();
   }
@@ -230,24 +229,20 @@ Thread::SpawnThread(Thread* aThread)
 {
   DirectSpawnThread(ThreadMain, aThread);
   WaitUntilInitialized(aThread);
 }
 
 /* static */ NativeThreadId
 Thread::StartThread(Callback aStart, void* aArgument, bool aNeedsJoin)
 {
-  MOZ_ASSERT(IsRecordingOrReplaying());
-  MOZ_ASSERT(!AreThreadEventsPassedThrough());
-  MOZ_ASSERT(!AreThreadEventsDisallowed());
+  EnsureNotDivergedFromRecording();
 
-  EnsureNotDivergedFromRecording();
   Thread* thread = Thread::Current();
-
-  RecordReplayAssert("StartThread");
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   MonitorAutoLock lock(*gMonitor);
 
   size_t id = 0;
   if (IsRecording()) {
     // Look for an idle thread.
     for (id = MainThreadId + 1; id <= MaxRecordedThreadId; id++) {
       Thread* targetThread = Thread::GetById(id);
@@ -296,43 +291,16 @@ Thread::Join()
       mNeedsJoin = false;
       break;
     }
     gMonitor->Wait();
   }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Thread Buffers
-///////////////////////////////////////////////////////////////////////////////
-
-char*
-Thread::TakeBuffer(size_t aSize)
-{
-  MOZ_ASSERT(mBuffer != (char*) 0x1);
-  if (aSize > mBufferCapacity) {
-    mBufferCapacity = aSize;
-    mBuffer = (char*) realloc(mBuffer, aSize);
-  }
-  char* buf = mBuffer;
-
-  // Poison the buffer in case this thread tries to use it again reentrantly.
-  mBuffer = (char*) 0x1;
-
-  return buf;
-}
-
-void
-Thread::RestoreBuffer(char* aBuf)
-{
-  MOZ_ASSERT(mBuffer == (char*) 0x1);
-  mBuffer = aBuf;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Thread Public API Accessors
 ///////////////////////////////////////////////////////////////////////////////
 
 extern "C" {
 
 MOZ_EXPORT void
 RecordReplayInterface_InternalBeginPassThroughThreadEvents()
 {
@@ -376,30 +344,16 @@ RecordReplayInterface_InternalEndDisallo
 MOZ_EXPORT bool
 RecordReplayInterface_InternalAreThreadEventsDisallowed()
 {
   MOZ_ASSERT(IsRecordingOrReplaying());
   Thread* thread = Thread::Current();
   return thread && thread->AreEventsDisallowed();
 }
 
-MOZ_EXPORT void
-RecordReplayInterface_InternalBeginCaptureEventStacks()
-{
-  MOZ_ASSERT(IsRecordingOrReplaying());
-  Thread::Current()->BeginCaptureEventStacks();
-}
-
-MOZ_EXPORT void
-RecordReplayInterface_InternalEndCaptureEventStacks()
-{
-  MOZ_ASSERT(IsRecordingOrReplaying());
-  Thread::Current()->EndCaptureEventStacks();
-}
-
 } // extern "C"
 
 ///////////////////////////////////////////////////////////////////////////////
 // Thread Coordination
 ///////////////////////////////////////////////////////////////////////////////
 
 // Whether all threads should attempt to idle.
 static Atomic<bool, SequentiallyConsistent, Behavior::DontPreserve> gThreadsShouldIdle;
--- a/toolkit/recordreplay/Thread.h
+++ b/toolkit/recordreplay/Thread.h
@@ -73,67 +73,50 @@ typedef pthread_t NativeThreadId;
 
 // Information about the execution state of a thread.
 class Thread
 {
 public:
   // Signature for the start function of a thread.
   typedef void (*Callback)(void*);
 
-  // Number of recent assertions remembered.
-  static const size_t NumRecentAsserts = 128;
-
-  struct RecentAssertInfo {
-    char* mText;
-    size_t mPosition;
-  };
-
 private:
   // Monitor used to protect various thread information (see Thread.h) and to
   // wait on or signal progress for a thread.
   static Monitor* gMonitor;
 
   // Thread ID in the recording, fixed at creation.
   size_t mId;
 
   // Whether to pass events in the thread through without recording/replaying.
   // This is only used by the associated thread.
   bool mPassThroughEvents;
 
   // Whether to crash if we try to record/replay thread events. This is only
   // used by the associated thread.
   size_t mDisallowEvents;
 
-  // Whether to capture stack information for events while recording. This is
-  // only used by the associated thread.
-  size_t mCaptureEventStacks;
+  // Whether execution has diverged from the recording and the thread's
+  // recorded events cannot be accessed.
+  bool mDivergedFromRecording;
 
   // Start routine and argument which the thread is currently executing. This
   // is cleared after the routine finishes and another start routine may be
   // assigned to the thread. mNeedsJoin specifies whether the thread must be
   // joined before it is completely dead and can be reused. This is protected
   // by the thread monitor.
   Callback mStart;
   void* mStartArg;
   bool mNeedsJoin;
 
   // ID for this thread used by the system.
   NativeThreadId mNativeId;
 
-  // Streams with events and assertions for the thread. These are only used by
-  // the associated thread.
+  // Stream with events for the thread. This is only used on the thread itself.
   Stream* mEvents;
-  Stream* mAsserts;
-
-  // Recent assertions that have been encountered, for debugging.
-  RecentAssertInfo mRecentAsserts[NumRecentAsserts];
-
-  // Buffer for general use. This is only used by the associated thread.
-  char* mBuffer;
-  size_t mBufferCapacity;
 
   // Stack boundary of the thread, protected by the thread monitor.
   uint8_t* mStackBase;
   size_t mStackSize;
 
   // File descriptor to block on when the thread is idle, fixed at creation.
   FileHandle mIdlefd;
 
@@ -153,68 +136,59 @@ public:
 ///////////////////////////////////////////////////////////////////////////////
 // Public Routines
 ///////////////////////////////////////////////////////////////////////////////
 
   // Accessors for some members that never change.
   size_t Id() { return mId; }
   NativeThreadId NativeId() { return mNativeId; }
   Stream& Events() { return *mEvents; }
-  Stream& Asserts() { return *mAsserts; }
   uint8_t* StackBase() { return mStackBase; }
   size_t StackSize() { return mStackSize; }
 
-  inline bool IsMainThread() { return mId == MainThreadId; }
-  inline bool IsRecordedThread() { return mId <= MaxRecordedThreadId; }
-  inline bool IsNonMainRecordedThread() { return IsRecordedThread() && !IsMainThread(); }
+  inline bool IsMainThread() const { return mId == MainThreadId; }
+  inline bool IsRecordedThread() const { return mId <= MaxRecordedThreadId; }
+  inline bool IsNonMainRecordedThread() const { return IsRecordedThread() && !IsMainThread(); }
 
   // Access the flag for whether this thread is passing events through.
   void SetPassThrough(bool aPassThrough) {
     MOZ_RELEASE_ASSERT(mPassThroughEvents == !aPassThrough);
     mPassThroughEvents = aPassThrough;
   }
-  bool PassThroughEvents() {
+  bool PassThroughEvents() const {
     return mPassThroughEvents;
   }
 
   // Access the counter for whether events are disallowed in this thread.
   void BeginDisallowEvents() {
     mDisallowEvents++;
   }
   void EndDisallowEvents() {
     MOZ_RELEASE_ASSERT(mDisallowEvents);
     mDisallowEvents--;
   }
-  bool AreEventsDisallowed() {
+  bool AreEventsDisallowed() const {
     return mDisallowEvents != 0;
   }
 
-  // Access the counter for whether event stacks are captured while recording.
-  void BeginCaptureEventStacks() {
-    mCaptureEventStacks++;
+  // Access the flag for whether this thread's execution has diverged from the
+  // recording. Once set, this is only unset by rewinding to a point where the
+  // flag is clear.
+  void DivergeFromRecording() {
+    mDivergedFromRecording = true;
   }
-  void EndCaptureEventStacks() {
-    MOZ_RELEASE_ASSERT(mCaptureEventStacks);
-    mCaptureEventStacks--;
-  }
-  bool ShouldCaptureEventStacks() {
-    return mCaptureEventStacks != 0;
+  bool HasDivergedFromRecording() const {
+    return mDivergedFromRecording;
   }
 
-  // Access the array of recent assertions in the thread.
-  RecentAssertInfo& RecentAssert(size_t i) {
-    MOZ_ASSERT(i < NumRecentAsserts);
-    return mRecentAsserts[i];
+  // Return whether this thread may read or write to its recorded event stream.
+  bool CanAccessRecording() const {
+    return !PassThroughEvents() && !AreEventsDisallowed() && !HasDivergedFromRecording();
   }
 
-  // Access a thread local buffer of a guaranteed size. The buffer must be
-  // restored before it can be taken again.
-  char* TakeBuffer(size_t aSize);
-  void RestoreBuffer(char* aBuf);
-
   // The actual start routine at the root of all recorded threads, and of all
   // threads when replaying.
   static void ThreadMain(void* aArgument);
 
   // Bind this Thread to the current system thread, setting Thread::Current()
   // and some other basic state.
   void BindToCurrent();
 
--- a/toolkit/recordreplay/Trigger.cpp
+++ b/toolkit/recordreplay/Trigger.cpp
@@ -53,47 +53,44 @@ InitializeTriggers()
   gTriggerInfoMap = new TriggerInfoMap();
 }
 
 extern "C" {
 
 MOZ_EXPORT void
 RecordReplayInterface_RegisterTrigger(void* aObj, const std::function<void()>& aCallback)
 {
-  MOZ_ASSERT(IsRecordingOrReplaying());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
   MOZ_RELEASE_ASSERT(aObj);
 
-  if (HasDivergedFromRecording()) {
+  Thread* thread = Thread::Current();
+  if (thread->HasDivergedFromRecording()) {
     return;
   }
-
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-
-  size_t threadId = Thread::Current()->Id();
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   size_t id;
   {
     AutoOrderedAtomicAccess order;
     StaticMutexAutoLock lock(gTriggersMutex);
 
     TriggerInfoMap::iterator iter = gTriggerInfoMap->find(aObj);
     if (iter != gTriggerInfoMap->end()) {
       id = gTriggers->GetIndex(aObj);
-      MOZ_RELEASE_ASSERT(iter->second.mThreadId == threadId);
+      MOZ_RELEASE_ASSERT(iter->second.mThreadId == thread->Id());
       iter->second.mCallback = aCallback;
       iter->second.mRegisterCount++;
     } else {
       id = gTriggers->Insert(aObj);
-      TriggerInfo info(threadId, aCallback);
+      TriggerInfo info(thread->Id(), aCallback);
       gTriggerInfoMap->insert(TriggerInfoMap::value_type(aObj, info));
     }
   }
 
-  RecordReplayAssert("RegisterTrigger %zu", id);
+  thread->Events().RecordOrReplayThreadEvent(ThreadEvent::RegisterTrigger);
+  thread->Events().CheckInput(id);
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_UnregisterTrigger(void* aObj)
 {
   MOZ_ASSERT(IsRecordingOrReplaying());
   MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
 
@@ -154,54 +151,47 @@ RemoveTriggerCallbackForThreadId(size_t 
     }
   }
   return Nothing();
 }
 
 MOZ_EXPORT void
 RecordReplayInterface_ExecuteTriggers()
 {
-  MOZ_ASSERT(IsRecordingOrReplaying());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
-  MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
-
   Thread* thread = Thread::Current();
-
-  RecordReplayAssert("ExecuteTriggers");
+  MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
 
   if (IsRecording()) {
     // Invoke the callbacks for any triggers waiting for execution, including
     // any whose callbacks are triggered by earlier callback invocations.
     while (true) {
       Maybe<size_t> id = RemoveTriggerCallbackForThreadId(thread->Id());
       if (id.isNothing()) {
         break;
       }
 
-      thread->Events().RecordOrReplayThreadEvent(ThreadEvent::ExecuteTrigger);
+      thread->Events().WriteScalar((size_t) ThreadEvent::ExecuteTrigger);
       thread->Events().WriteScalar(id.ref());
       InvokeTriggerCallback(id.ref());
     }
-    thread->Events().RecordOrReplayThreadEvent(ThreadEvent::ExecuteTriggersFinished);
+    thread->Events().WriteScalar((size_t) ThreadEvent::ExecuteTriggersFinished);
   } else {
     // Execute the same callbacks which were executed at this point while
     // recording.
     while (true) {
       ThreadEvent ev = (ThreadEvent) thread->Events().ReadScalar();
       if (ev != ThreadEvent::ExecuteTrigger) {
         if (ev != ThreadEvent::ExecuteTriggersFinished) {
           child::ReportFatalError(Nothing(), "ExecuteTrigger Mismatch");
           Unreachable();
         }
         break;
       }
       size_t id = thread->Events().ReadScalar();
       InvokeTriggerCallback(id);
     }
   }
-
-  RecordReplayAssert("ExecuteTriggers DONE");
 }
 
 } // extern "C"
 
 } // namespace recordreplay
 } // namespace mozilla
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp
+++ b/toolkit/recordreplay/ipc/ChildIPC.cpp
@@ -13,16 +13,17 @@
 #include "base/task.h"
 #include "chrome/common/child_thread.h"
 #include "chrome/common/mach_ipc_mac.h"
 #include "ipc/Channel.h"
 #include "mac/handler/exception_handler.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/Sprintf.h"
+#include "mozilla/StackWalk.h"
 #include "mozilla/VsyncDispatcher.h"
 
 #include "InfallibleVector.h"
 #include "MemorySnapshot.h"
 #include "ParentInternal.h"
 #include "ProcessRecordReplay.h"
 #include "ProcessRedirect.h"
 #include "ProcessRewind.h"
@@ -321,16 +322,56 @@ DebuggerRunsInMiddleman()
 }
 
 void
 MaybeCreateInitialCheckpoint()
 {
   NewCheckpoint(/* aTemporary = */ false);
 }
 
+struct StackWalkData
+{
+  // Current buffer and allocated size, which may be internal to the original
+  // allocation.
+  char* mBuf;
+  size_t mSize;
+
+  StackWalkData(char* aBuf, size_t aSize)
+    : mBuf(aBuf), mSize(aSize)
+  {}
+
+  void append(const char* aText) {
+    size_t len = strlen(aText);
+    if (len <= mSize) {
+      memcpy(mBuf, aText, len);
+      mBuf += len;
+      mSize -= len;
+    }
+  }
+};
+
+static void
+StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
+{
+  StackWalkData* data = (StackWalkData*) aClosure;
+
+  MozCodeAddressDetails details;
+  MozDescribeCodeAddress(aPC, &details);
+
+  data->append(" ### ");
+  data->append(details.function[0] ? details.function : "???");
+}
+
+static void
+SetCurrentStackString(const char* aAssertion, char* aBuf, size_t aSize)
+{
+  StackWalkData data(aBuf, aSize);
+  MozStackWalk(StackWalkCallback, /* aSkipFrames = */ 2, /* aFrameCount = */ 32, &data);
+}
+
 void
 ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
 {
   // Unprotect any memory which might be written while producing the minidump.
   UnrecoverableSnapshotFailure();
 
   AutoEnsurePassThroughThreadEvents pt;
 
@@ -343,16 +384,23 @@ ReportFatalError(const Maybe<MinidumpInf
 #endif
 
   va_list ap;
   va_start(ap, aFormat);
   char buf[2048];
   VsprintfLiteral(buf, aFormat, ap);
   va_end(ap);
 
+  // Include stack information in the error message as well, if we are on the
+  // thread where the fatal error occurred.
+  if (aMinidump.isNothing()) {
+    size_t len = strlen(buf);
+    SetCurrentStackString(buf, buf + len, sizeof(buf) - len);
+  }
+
   // Construct a FatalErrorMessage on the stack, to avoid touching the heap.
   char msgBuf[4096];
   size_t header = sizeof(FatalErrorMessage);
   size_t len = std::min(strlen(buf) + 1, sizeof(msgBuf) - header);
   FatalErrorMessage* msg = new(msgBuf) FatalErrorMessage(header + len);
   memcpy(&msgBuf[header], buf, len);
   msgBuf[sizeof(msgBuf) - 1] = 0;
 
--- a/toolkit/recordreplay/ipc/ParentForwarding.cpp
+++ b/toolkit/recordreplay/ipc/ParentForwarding.cpp
@@ -142,16 +142,25 @@ struct MOZ_RAII AutoMarkMainThreadWaitin
     gMainThreadIsWaitingForIPDLReply = true;
   }
 
   ~AutoMarkMainThreadWaitingForIPDLReply() {
     gMainThreadIsWaitingForIPDLReply = false;
   }
 };
 
+static void
+BeginShutdown()
+{
+  // If there is a channel error or anything that could result from the child
+  // crashing, cleanly shutdown this process so that we don't generate a
+  // separate minidump which masks the initial failure.
+  MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
+}
+
 class MiddlemanProtocol : public ipc::IToplevelProtocol
 {
 public:
   ipc::Side mSide;
   MiddlemanProtocol* mOpposite;
   MessageLoop* mOppositeMessageLoop;
 
   explicit MiddlemanProtocol(ipc::Side aSide)
@@ -167,17 +176,18 @@ public:
 
   static void ForwardMessageAsync(MiddlemanProtocol* aProtocol, Message* aMessage) {
     if (ActiveChildIsRecording() || AlwaysForwardMessage(*aMessage)) {
       PrintSpew("ForwardAsyncMsg %s %s %d\n",
                 (aProtocol->mSide == ipc::ChildSide) ? "Child" : "Parent",
                 IPC::StringFromIPCMessageType(aMessage->type()),
                 (int) aMessage->routing_id());
       if (!aProtocol->GetIPCChannel()->Send(aMessage)) {
-        MOZ_CRASH("MiddlemanProtocol::ForwardMessageAsync");
+        MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
+        BeginShutdown();
       }
     } else {
       delete aMessage;
     }
   }
 
   virtual Result OnMessageReceived(const Message& aMessage) override {
     // If we do not have a recording process then just see if the message can
@@ -204,17 +214,18 @@ public:
   }
 
   static void ForwardMessageSync(MiddlemanProtocol* aProtocol, Message* aMessage, Message** aReply) {
     PrintSpew("ForwardSyncMsg %s\n", IPC::StringFromIPCMessageType(aMessage->type()));
 
     MOZ_RELEASE_ASSERT(!*aReply);
     Message* nReply = new Message();
     if (!aProtocol->GetIPCChannel()->Send(aMessage, nReply)) {
-      MOZ_CRASH("MiddlemanProtocol::ForwardMessageSync");
+      MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
+      BeginShutdown();
     }
 
     MonitorAutoLock lock(*gMonitor);
     *aReply = nReply;
     gMonitor->Notify();
   }
 
   virtual Result OnMessageReceived(const Message& aMessage, Message*& aReply) override {
@@ -240,17 +251,18 @@ public:
   }
 
   static void ForwardCallMessage(MiddlemanProtocol* aProtocol, Message* aMessage, Message** aReply) {
     PrintSpew("ForwardSyncCall %s\n", IPC::StringFromIPCMessageType(aMessage->type()));
 
     MOZ_RELEASE_ASSERT(!*aReply);
     Message* nReply = new Message();
     if (!aProtocol->GetIPCChannel()->Call(aMessage, nReply)) {
-      MOZ_CRASH("MiddlemanProtocol::ForwardCallMessage");
+      MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
+      BeginShutdown();
     }
 
     MonitorAutoLock lock(*gMonitor);
     *aReply = nReply;
     gMonitor->Notify();
   }
 
   virtual Result OnCallReceived(const Message& aMessage, Message*& aReply) override {
@@ -276,21 +288,21 @@ public:
   }
 
   virtual int32_t GetProtocolTypeId() override {
     MOZ_CRASH("MiddlemanProtocol::GetProtocolTypeId");
   }
 
   virtual void OnChannelClose() override {
     MOZ_RELEASE_ASSERT(mSide == ipc::ChildSide);
-    MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
+    BeginShutdown();
   }
 
   virtual void OnChannelError() override {
-    MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
+    BeginShutdown();
   }
 };
 
 static MiddlemanProtocol* gChildProtocol;
 static MiddlemanProtocol* gParentProtocol;
 
 ipc::MessageChannel*
 ChannelToUIProcess()
--- a/toolkit/recordreplay/ipc/ParentIPC.cpp
+++ b/toolkit/recordreplay/ipc/ParentIPC.cpp
@@ -873,16 +873,18 @@ ParentProcessId()
 
 void
 InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid,
                     const base::SharedMemoryHandle& aPrefsHandle,
                     const ipc::FileDescriptor& aPrefMapHandle)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 
+  CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RecordReplay, true);
+
   gParentPid = aParentPid;
 
   // Construct the message that will be sent to each child when starting up.
   IntroductionMessage* msg =
     IntroductionMessage::New(aParentPid, aArgc, aArgv);
   ChildProcessInfo::SetIntroductionMessage(msg);
 
   MOZ_RELEASE_ASSERT(gProcessKind == ProcessKind::MiddlemanRecording ||