Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 06 Feb 2017 17:52:26 -0800
changeset 479884 330ab4695793c499110152a6582afca8e87ae46c
parent 479883 f3da0505833f946d1b1767986ebb8e3d7a63f5c1 (current diff)
parent 479651 af8a2573d0f1e9cc6f2ba0ab67d7a702a197f177 (diff)
child 479885 270900fec93245a4c8e93df3e74be837735766d7
push id44393
push userVYV03354@nifty.ne.jp
push dateTue, 07 Feb 2017 13:53:48 +0000
reviewersmerge
milestone54.0a1
Merge m-c to autoland, a=merge MozReview-Commit-ID: 2iqmlA6R1S4
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
security/nss/coreconf/sanitizers.mk
--- a/.cron.yml
+++ b/.cron.yml
@@ -20,8 +20,18 @@ jobs:
           treeherder-symbol: Na
           triggered-by: nightly
           target-tasks-method: nightly_fennec
       run-on-projects:
           - mozilla-central
           - date
       when: []  # never (temporary)
 
+    - name: nightly-mochitest-valgrind
+      job:
+          type: decision-task
+          treeherder-symbol: Vg
+          target-tasks-method: mochitest_valgrind
+      run-on-projects:
+          - mozilla-central
+      when:
+          - {hour: 16, minute: 0}
+          - {hour: 4, minute: 0}
--- a/.eslintignore
+++ b/.eslintignore
@@ -110,17 +110,16 @@ devtools/server/actors/object.js
 devtools/server/actors/script.js
 devtools/server/actors/styleeditor.js
 devtools/server/actors/stylesheets.js
 devtools/server/tests/browser/**
 !devtools/server/tests/browser/browser_webextension_inspected_window.js
 devtools/server/tests/mochitest/**
 devtools/server/tests/unit/**
 devtools/shared/heapsnapshot/**
-devtools/shared/transport/tests/unit/**
 devtools/shared/webconsole/test/**
 
 # Ignore devtools pre-processed files
 devtools/client/framework/toolbox-process-window.js
 devtools/client/performance/system.js
 devtools/client/webide/webide-prefs.js
 devtools/client/preferences/**
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -698,16 +698,17 @@
                    aria-label="&urlbar.viewSiteInfo.label;"
                    onclick="gIdentityHandler.handleIdentityButtonEvent(event);"
                    onkeypress="gIdentityHandler.handleIdentityButtonEvent(event);"
                    ondragstart="gIdentityHandler.onDragStart(event);">
                 <image id="identity-icon"
                        consumeanchor="identity-box"
                        onclick="PageProxyClickHandler(event);"/>
                 <image id="sharing-icon" mousethrough="always"/>
+                <image id="tracking-protection-icon"/>
                 <box id="blocked-permissions-container" align="center">
                   <image data-permission-id="geo" class="blocked-permission-icon geo-icon" role="button"
                          tooltiptext="&urlbar.geolocationBlocked.tooltip;"/>
                   <image data-permission-id="desktop-notification" class="blocked-permission-icon desktop-notification-icon" role="button"
                          tooltiptext="&urlbar.webNotificationsBlocked.tooltip;"/>
                   <image data-permission-id="camera" class="blocked-permission-icon camera-icon" role="button"
                          tooltiptext="&urlbar.cameraBlocked.tooltip;"/>
                   <image data-permission-id="indexedDB" class="blocked-permission-icon indexedDB-icon" role="button"
@@ -746,17 +747,16 @@
                          tooltiptext="&urlbar.servicesNotificationAnchor.tooltip;"/>
                   <image id="translate-notification-icon" class="notification-anchor-icon translation-icon" role="button"
                          tooltiptext="&urlbar.translateNotificationAnchor.tooltip;"/>
                   <image id="translated-notification-icon" class="notification-anchor-icon translation-icon in-use" role="button"
                          tooltiptext="&urlbar.translatedNotificationAnchor.tooltip;"/>
                   <image id="eme-notification-icon" class="notification-anchor-icon drm-icon" role="button"
                          tooltiptext="&urlbar.emeNotificationAnchor.tooltip;"/>
                 </box>
-                <image id="tracking-protection-icon"/>
                 <image id="connection-icon"/>
                 <hbox id="identity-icon-labels">
                   <label id="identity-icon-label" class="plain" flex="1"/>
                   <label id="identity-icon-country-label" class="plain"/>
                 </hbox>
               </box>
               <box id="urlbar-display-box" align="center">
                 <label id="switchtab" class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
+++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_screen.js
@@ -316,17 +316,17 @@ var gTests = [
     yield checkSharingUI({audio: true, screen: "Screen"});
     yield closeStream();
   }
 },
 
 
 {
   desc: "getUserMedia screen: clicking through without selecting a screen denies",
-  run: function* checkReloading() {
+  run: function* checkClickThroughDenies() {
     let promise = promisePopupNotificationShown("webRTC-shareDevices");
     yield promiseRequestDevice(false, true, null, "screen");
     yield promise;
     yield expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(false, false, true);
 
     yield promiseMessage(permissionError, () => {
       PopupNotifications.panel.firstChild.button.click();
--- a/browser/base/content/test/webrtc/head.js
+++ b/browser/base/content/test/webrtc/head.js
@@ -402,22 +402,24 @@ function* closeStream(aAlreadyClosed, aF
   if (promises)
     yield Promise.all(promises);
 
   yield* assertWebRTCIndicatorStatus(null);
 }
 
 function* reloadAndAssertClosedStreams() {
   info("reloading the web page");
-  let promise = promiseObserverCalled("recording-device-events");
+  let promises = [
+    promiseObserverCalled("recording-device-events"),
+    promiseObserverCalled("recording-window-ended")
+  ];
   yield ContentTask.spawn(gBrowser.selectedBrowser, null,
                           "() => content.location.reload()");
-  yield promise;
+  yield Promise.all(promises);
 
-  yield expectObserverCalled("recording-window-ended");
   yield expectNoObserverCalled();
   yield checkNotSharing();
 }
 
 function checkDeviceSelectors(aAudio, aVideo, aScreen) {
   let micSelector = document.getElementById("webRTC-selectMicrophone");
   if (aAudio)
     ok(!micSelector.hidden, "microphone selector visible");
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/debug-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/linux64/debug"
+
+ac_add_options --enable-webrender
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/linux64/opt-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
+
+ac_add_options --enable-webrender
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/macosx64/debug-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/macosx64/debug"
+
+ac_add_options --enable-webrender
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/macosx64/opt-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/macosx64/nightly"
+
+ac_add_options --enable-webrender
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/win64/debug-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/win64/debug"
+
+ac_add_options --enable-webrender
new file mode 100644
--- /dev/null
+++ b/browser/config/mozconfigs/win64/opt-qr
@@ -0,0 +1,3 @@
+. "$topsrcdir/browser/config/mozconfigs/win64/nightly"
+
+ac_add_options --enable-webrender
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -8,18 +8,22 @@ this.EXPORTED_SYMBOLS = ["E10SUtils"];
 
 const {interfaces: Ci, utils: Cu, classes: Cc} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyPreferenceGetter(this, "useRemoteWebExtensions",
                                       "extensions.webextensions.remote", false);
+XPCOMUtils.defineLazyPreferenceGetter(this, "useSeparateFileUriProcess",
+                                      "browser.tabs.remote.separateFileUriProcess", false);
 XPCOMUtils.defineLazyModuleGetter(this, "Utils",
                                   "resource://gre/modules/sessionstore/Utils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+                                  "resource://gre/modules/Console.jsm");
 
 function getAboutModule(aURL) {
   // Needs to match NS_GetAboutModuleName
   let moduleName = aURL.path.replace(/[#?].*/, "").toLowerCase();
   let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName;
   try {
     return Cc[contract].getService(Ci.nsIAboutModule);
   } catch (e) {
@@ -51,112 +55,125 @@ this.E10SUtils = {
 
   canLoadURIInProcess(aURL, aProcess) {
     let remoteType = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT
                      ? DEFAULT_REMOTE_TYPE : NOT_REMOTE;
     return remoteType == this.getRemoteTypeForURI(aURL, true, remoteType);
   },
 
   getRemoteTypeForURI(aURL, aMultiProcess,
-                                aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
+                      aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
     if (!aMultiProcess) {
       return NOT_REMOTE;
     }
 
     // loadURI in browser.xml treats null as about:blank
     if (!aURL) {
       aURL = "about:blank";
     }
 
-    // Javascript urls can load in any process, they apply to the current document
-    if (aURL.startsWith("javascript:")) {
-      return aPreferredRemoteType;
-    }
-
-    // We need data: URI's to load in a remote process, because some of our
-    // tests rely on this. For blob: URI's, load them in their originating
-    // process unless it is non-remote. In that case, favor a remote (sandboxed)
-    // process with fewer privileges to limit exposure.
-    if (aURL.startsWith("data:") || aURL.startsWith("blob:")) {
-      return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE
-                                                : aPreferredRemoteType;
-    }
-
-    if (aURL.startsWith("file:")) {
-      return Services.prefs.getBoolPref("browser.tabs.remote.separateFileUriProcess")
-             ? FILE_REMOTE_TYPE : DEFAULT_REMOTE_TYPE;
+    let uri;
+    try {
+      uri = Services.io.newURI(aURL);
+    } catch (e) {
+      // If we have an invalid URI, it's still possible that it might get
+      // fixed-up into a valid URI later on. However, we don't want to return
+      // aPreferredRemoteType here, in case the URI gets fixed-up into
+      // something that wouldn't normally run in that process.
+      return DEFAULT_REMOTE_TYPE;
     }
 
-    if (aURL.startsWith("about:")) {
-      // We need to special case about:blank because it needs to load in any.
-      if (aURL == "about:blank") {
-        return aPreferredRemoteType;
-      }
+    return this.getRemoteTypeForURIObject(uri, aMultiProcess,
+                                          aPreferredRemoteType);
+  },
 
-      let url = Services.io.newURI(aURL);
-      let module = getAboutModule(url);
-      // If the module doesn't exist then an error page will be loading, that
-      // should be ok to load in any process
-      if (!module) {
-        return aPreferredRemoteType;
-      }
-
-      let flags = module.getURIFlags(url);
-      if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
-        return DEFAULT_REMOTE_TYPE;
-      }
-
-      // If the about page can load in parent or child, it should be safe to
-      // load in any remote type.
-      if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) {
-        return aPreferredRemoteType;
-      }
-
+  getRemoteTypeForURIObject(aURI, aMultiProcess,
+                            aPreferredRemoteType = DEFAULT_REMOTE_TYPE) {
+    if (!aMultiProcess) {
       return NOT_REMOTE;
     }
 
-    if (aURL.startsWith("chrome:")) {
-      let url;
-      try {
-        // This can fail for invalid Chrome URIs, in which case we will end up
-        // not loading anything anyway.
-        url = Services.io.newURI(aURL);
-      } catch (ex) {
+    switch (aURI.scheme) {
+      case "javascript":
+        // javascript URIs can load in any, they apply to the current document.
         return aPreferredRemoteType;
-      }
+
+      case "data":
+      case "blob":
+        // We need data: and blob: URIs to load in any remote process, because
+        // they need to be able to load in whatever is the current process
+        // unless it is non-remote. In that case we don't want to load them in
+        // the parent process, so we load them in the default remote process,
+        // which is sandboxed and limits any risk.
+        return aPreferredRemoteType == NOT_REMOTE ? DEFAULT_REMOTE_TYPE
+                                                  : aPreferredRemoteType;
 
-      let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
-                      getService(Ci.nsIXULChromeRegistry);
-      if (chromeReg.mustLoadURLRemotely(url)) {
-        return DEFAULT_REMOTE_TYPE;
-      }
+      case "file":
+        return useSeparateFileUriProcess ? FILE_REMOTE_TYPE
+                                         : DEFAULT_REMOTE_TYPE;
+
+      case "about":
+        let module = getAboutModule(aURI);
+        // If the module doesn't exist then an error page will be loading, that
+        // should be ok to load in any process
+        if (!module) {
+          return aPreferredRemoteType;
+        }
+
+        let flags = module.getURIFlags(aURI);
+        if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
+          return DEFAULT_REMOTE_TYPE;
+        }
 
-      if (chromeReg.canLoadURLRemotely(url) &&
-          aPreferredRemoteType != NOT_REMOTE) {
-        return DEFAULT_REMOTE_TYPE;
-      }
+        // If the about page can load in parent or child, it should be safe to
+        // load in any remote type.
+        if (flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD) {
+          return aPreferredRemoteType;
+        }
+
+        return NOT_REMOTE;
 
-      return NOT_REMOTE;
-    }
+      case "chrome":
+        let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
+                        getService(Ci.nsIXULChromeRegistry);
+        if (chromeReg.mustLoadURLRemotely(aURI)) {
+          return DEFAULT_REMOTE_TYPE;
+        }
+
+        if (chromeReg.canLoadURLRemotely(aURI) &&
+            aPreferredRemoteType != NOT_REMOTE) {
+          return DEFAULT_REMOTE_TYPE;
+        }
 
-    if (aURL.startsWith("moz-extension:")) {
-      return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
-    }
+        return NOT_REMOTE;
+
+      case "moz-extension":
+        return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
 
-    if (aURL.startsWith("view-source:")) {
-      return this.getRemoteTypeForURI(aURL.substr("view-source:".length),
-                                      aMultiProcess, aPreferredRemoteType);
+      default:
+        // For any other nested URIs, we use the innerURI to determine the
+        // remote type. In theory we should use the innermost URI, but some URIs
+        // have fake inner URIs (e.g. about URIs with inner moz-safe-about) and
+        // if such URIs are wrapped in other nested schemes like view-source:,
+        // we don't want to "skip" past "about:" by going straight to the
+        // innermost URI. Any URIs like this will need to be handled in the
+        // cases above, so we don't still end up using the fake inner URI here.
+        if (aURI instanceof Ci.nsINestedURI) {
+          let innerURI = aURI.QueryInterface(Ci.nsINestedURI).innerURI;
+          return this.getRemoteTypeForURIObject(innerURI, aMultiProcess,
+                                                aPreferredRemoteType);
+        }
+
+        return validatedWebRemoteType(aPreferredRemoteType);
     }
-
-    return validatedWebRemoteType(aPreferredRemoteType);
   },
 
   shouldLoadURIInThisProcess(aURI) {
     let remoteType = Services.appinfo.remoteType;
-    return remoteType == this.getRemoteTypeForURI(aURI.spec, true, remoteType);
+    return remoteType == this.getRemoteTypeForURIObject(aURI, true, remoteType);
   },
 
   shouldLoadURI(aDocShell, aURI, aReferrer) {
     // Inner frames should always load in the current process
     if (aDocShell.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeParent)
       return true;
 
     // If we are in a Large-Allocation process, and it wouldn't be content visible
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/xpcshell/test_E10SUtils_nested_URIs.js
@@ -0,0 +1,94 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+
+const {utils: Cu, interfaces: Ci} = Components;
+
+Cu.import("resource:///modules/E10SUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+var TEST_PREFERRED_REMOTE_TYPES = [
+  E10SUtils.WEB_REMOTE_TYPE,
+  E10SUtils.NOT_REMOTE,
+  "fakeRemoteType",
+]
+
+// These test cases give a nestedURL and a plainURL that should always load in
+// the same remote type. By making these tests comparisons, they should work
+// with any pref combination.
+var TEST_CASES = [
+  {
+    nestedURL: "jar:file:///some.file!/",
+    plainURL: "file:///some.file",
+  },
+  {
+    nestedURL: "jar:jar:file:///some.file!/!/",
+    plainURL: "file:///some.file",
+  },
+  {
+    nestedURL: "jar:http://some.site/file!/",
+    plainURL: "http://some.site/file",
+  },
+  {
+    nestedURL: "feed:http://some.site",
+    plainURL: "http://some.site",
+  },
+  {
+    nestedURL: "pcast:http://some.site",
+    plainURL: "http://some.site",
+  },
+  {
+    nestedURL: "view-source:http://some.site",
+    plainURL: "http://some.site",
+  },
+  {
+    nestedURL: "view-source:file:///some.file",
+    plainURL: "file:///some.file",
+  },
+  {
+    nestedURL: "view-source:about:home",
+    plainURL: "about:home",
+  },
+  {
+    nestedURL: "view-source:about:robots",
+    plainURL: "about:robots",
+  },
+  {
+    nestedURL: "view-source:feed:http://some.site",
+    plainURL: "http://some.site",
+  },
+  {
+    nestedURL: "view-source:pcast:http://some.site",
+    plainURL: "http://some.site",
+  },
+]
+
+function run_test() {
+  for (let testCase of TEST_CASES) {
+    for (let preferredRemoteType of TEST_PREFERRED_REMOTE_TYPES) {
+      let plainUri = Services.io.newURI(testCase.plainURL);
+      let plainRemoteType =
+        E10SUtils.getRemoteTypeForURIObject(plainUri, true, preferredRemoteType);
+
+      let nestedUri = Services.io.newURI(testCase.nestedURL);
+      let nestedRemoteType =
+        E10SUtils.getRemoteTypeForURIObject(nestedUri, true, preferredRemoteType);
+
+      let nestedStr = nestedUri.scheme + ":";
+      do {
+        nestedUri = nestedUri.QueryInterface(Ci.nsINestedURI).innerURI;
+        if (nestedUri.scheme == "about") {
+          nestedStr += nestedUri.spec;
+          break;
+        }
+
+        nestedStr += nestedUri.scheme + ":";
+      } while (nestedUri instanceof Ci.nsINestedURI);
+
+      let plainStr = plainUri.scheme == "about" ? plainUri.spec
+                                                : plainUri.scheme + ":";
+      equal(nestedRemoteType, plainRemoteType,
+            `Check that ${nestedStr} loads in same remote type as ${plainStr}`
+            + ` with preferred remote type: ${preferredRemoteType}`);
+    }
+  }
+}
--- a/browser/modules/test/xpcshell/xpcshell.ini
+++ b/browser/modules/test/xpcshell/xpcshell.ini
@@ -1,10 +1,11 @@
 [DEFAULT]
 head =
 firefox-appdir = browser
 skip-if = toolkit == 'android'
 
 [test_AttributionCode.js]
 skip-if = os != 'win'
 [test_DirectoryLinksProvider.js]
+[test_E10SUtils_nested_URIs.js]
 [test_SitePermissions.js]
 [test_LaterRun.js]
--- a/config/system-headers
+++ b/config/system-headers
@@ -484,16 +484,17 @@ ft2build.h
 fts.h
 gconf/gconf-client.h
 Gdiplus.h
 gdk/gdk.h
 gdk/gdkkeysyms.h
 gdk/gdkprivate.h
 gdk/gdkx.h
 gdk/gdkdirectfb.h
+gdk/gdkwayland.h
 gdk-pixbuf/gdk-pixbuf.h
 Gestalt.h
 getopt.h
 glibconfig.h
 glib.h
 glib-object.h
 gmodule.h
 gnome.h
--- a/devtools/shared/transport/tests/unit/head_dbg.js
+++ b/devtools/shared/transport/tests/unit/head_dbg.js
@@ -1,262 +1,157 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+/* exported Cr, CC, NetUtil, defer, errorCount, initTestDebuggerServer,
+            writeTestTempFile, socket_transport, local_transport, really_long
+*/
+
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 var CC = Components.Constructor;
 
 const { require } =
   Cu.import("resource://devtools/shared/Loader.jsm", {});
 const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
 const promise = require("promise");
 const defer = require("devtools/shared/defer");
 const { Task } = require("devtools/shared/task");
 
 const Services = require("Services");
-const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 
 // We do not want to log packets by default, because in some tests,
 // we can be sending large amounts of data. The test harness has
 // trouble dealing with logging all the data, and we end up with
 // intermittent time outs (e.g. bug 775924).
 // Services.prefs.setBoolPref("devtools.debugger.log", true);
 // Services.prefs.setBoolPref("devtools.debugger.log.verbose", true);
 // Enable remote debugging for the relevant tests.
 Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
 
 const { DebuggerServer } = require("devtools/server/main");
 const { DebuggerClient } = require("devtools/shared/client/main");
 
-function testExceptionHook(ex) {
-  try {
-    do_report_unexpected_exception(ex);
-  } catch (ex) {
-    return {throw: ex};
+// Convert an nsIScriptError 'flags' value into an appropriate string.
+function scriptErrorFlagsToKind(flags) {
+  let kind;
+  if (flags & Ci.nsIScriptError.warningFlag) {
+    kind = "warning";
   }
-  return undefined;
-}
+  if (flags & Ci.nsIScriptError.exceptionFlag) {
+    kind = "exception";
+  } else {
+    kind = "error";
+  }
 
-// Convert an nsIScriptError 'aFlags' value into an appropriate string.
-function scriptErrorFlagsToKind(aFlags) {
-  var kind;
-  if (aFlags & Ci.nsIScriptError.warningFlag)
-    kind = "warning";
-  if (aFlags & Ci.nsIScriptError.exceptionFlag)
-    kind = "exception";
-  else
-    kind = "error";
-
-  if (aFlags & Ci.nsIScriptError.strictFlag)
+  if (flags & Ci.nsIScriptError.strictFlag) {
     kind = "strict " + kind;
+  }
 
   return kind;
 }
 
 // Register a console listener, so console messages don't just disappear
 // into the ether.
 var errorCount = 0;
 var listener = {
-  observe: function (aMessage) {
+  observe: function (message) {
     errorCount++;
+    let string = "";
     try {
       // If we've been given an nsIScriptError, then we can print out
       // something nicely formatted, for tools like Emacs to pick up.
-      var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
-      dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
-           scriptErrorFlagsToKind(aMessage.flags) + ": " +
-           aMessage.errorMessage + "\n");
-      var string = aMessage.errorMessage;
+      message.QueryInterface(Ci.nsIScriptError);
+      dump(message.sourceName + ":" + message.lineNumber + ": " +
+           scriptErrorFlagsToKind(message.flags) + ": " +
+           message.errorMessage + "\n");
+      string = message.errorMessage;
     } catch (x) {
       // Be a little paranoid with message, as the whole goal here is to lose
       // no information.
       try {
-        var string = "" + aMessage.message;
-      } catch (x) {
-        var string = "<error converting error message to string>";
+        string = message.message;
+      } catch (e) {
+        string = "<error converting error message to string>";
       }
     }
 
     // Make sure we exit all nested event loops so that the test can finish.
     while (DebuggerServer.xpcInspector.eventLoopNestLevel > 0) {
       DebuggerServer.xpcInspector.exitNestedEventLoop();
     }
 
     // Throw in most cases, but ignore the "strict" messages
-    if (!(aMessage.flags & Ci.nsIScriptError.strictFlag)) {
+    if (!(message.flags & Ci.nsIScriptError.strictFlag)) {
       do_throw("head_dbg.js got console message: " + string + "\n");
     }
   }
 };
 
 var consoleService = Cc["@mozilla.org/consoleservice;1"]
                      .getService(Ci.nsIConsoleService);
 consoleService.registerListener(listener);
 
-function check_except(func) {
-  try {
-    func();
-  } catch (e) {
-    do_check_true(true);
-    return;
-  }
-  dump("Should have thrown an exception: " + func.toString());
-  do_check_true(false);
-}
-
-function testGlobal(aName) {
-  let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
-    .createInstance(Ci.nsIPrincipal);
-
-  let sandbox = Cu.Sandbox(systemPrincipal);
-  sandbox.__name = aName;
-  return sandbox;
-}
-
-function addTestGlobal(aName)
-{
-  let global = testGlobal(aName);
-  DebuggerServer.addTestGlobal(global);
-  return global;
-}
-
-// List the DebuggerClient |aClient|'s tabs, look for one whose title is
-// |aTitle|, and apply |aCallback| to the packet's entry for that tab.
-function getTestTab(aClient, aTitle, aCallback) {
-  aClient.listTabs(function (aResponse) {
-    for (let tab of aResponse.tabs) {
-      if (tab.title === aTitle) {
-        aCallback(tab);
-        return;
-      }
-    }
-    aCallback(null);
-  });
-}
-
-// Attach to |aClient|'s tab whose title is |aTitle|; pass |aCallback| the
-// response packet and a TabClient instance referring to that tab.
-function attachTestTab(aClient, aTitle, aCallback) {
-  getTestTab(aClient, aTitle, function (aTab) {
-    aClient.attachTab(aTab.actor, aCallback);
-  });
-}
-
-// Attach to |aClient|'s tab whose title is |aTitle|, and then attach to
-// that tab's thread. Pass |aCallback| the thread attach response packet, a
-// TabClient referring to the tab, and a ThreadClient referring to the
-// thread.
-function attachTestThread(aClient, aTitle, aCallback) {
-  attachTestTab(aClient, aTitle, function (aResponse, aTabClient) {
-    function onAttach(aResponse, aThreadClient) {
-      aCallback(aResponse, aTabClient, aThreadClient);
-    }
-    aTabClient.attachThread({ useSourceMaps: true }, onAttach);
-  });
-}
-
-// Attach to |aClient|'s tab whose title is |aTitle|, attach to the tab's
-// thread, and then resume it. Pass |aCallback| the thread's response to
-// the 'resume' packet, a TabClient for the tab, and a ThreadClient for the
-// thread.
-function attachTestTabAndResume(aClient, aTitle, aCallback) {
-  attachTestThread(aClient, aTitle, function (aResponse, aTabClient, aThreadClient) {
-    aThreadClient.resume(function (aResponse) {
-      aCallback(aResponse, aTabClient, aThreadClient);
-    });
-  });
-}
-
 /**
  * Initialize the testing debugger server.
  */
 function initTestDebuggerServer() {
   DebuggerServer.registerModule("devtools/server/actors/script", {
     prefix: "script",
     constructor: "ScriptActor",
     type: { global: true, tab: true }
   });
   DebuggerServer.registerModule("xpcshell-test/testactors");
   // Allow incoming connections.
   DebuggerServer.init();
 }
 
-function finishClient(aClient) {
-  aClient.close().then(function () {
-    do_test_finished();
-  });
-}
-
-/**
- * Takes a relative file path and returns the absolute file url for it.
- */
-function getFileUrl(aName, aAllowMissing = false) {
-  let file = do_get_file(aName, aAllowMissing);
-  return Services.io.newFileURI(file).spec;
-}
-
-/**
- * Returns the full path of the file with the specified name in a
- * platform-independent and URL-like form.
- */
-function getFilePath(aName, aAllowMissing = false) {
-  let file = do_get_file(aName, aAllowMissing);
-  let path = Services.io.newFileURI(file).spec;
-  let filePrePath = "file://";
-  if ("nsILocalFileWin" in Ci &&
-      file instanceof Ci.nsILocalFileWin) {
-    filePrePath += "/";
-  }
-  return path.slice(filePrePath.length);
-}
-
 /**
  * Wrapper around do_get_file to prefix files with the name of current test to
  * avoid collisions when running in parallel.
  */
 function getTestTempFile(fileName, allowMissing) {
   let thisTest = _TEST_FILE.toString().replace(/\\/g, "/");
   thisTest = thisTest.substring(thisTest.lastIndexOf("/") + 1);
   thisTest = thisTest.replace(/\..*$/, "");
   return do_get_file(fileName + "-" + thisTest, allowMissing);
 }
 
-function writeTestTempFile(aFileName, aContent) {
-  let file = getTestTempFile(aFileName, true);
+function writeTestTempFile(fileName, content) {
+  let file = getTestTempFile(fileName, true);
   let stream = Cc["@mozilla.org/network/file-output-stream;1"]
     .createInstance(Ci.nsIFileOutputStream);
   stream.init(file, -1, -1, 0);
   try {
     do {
-      let numWritten = stream.write(aContent, aContent.length);
-      aContent = aContent.slice(numWritten);
-    } while (aContent.length > 0);
+      let numWritten = stream.write(content, content.length);
+      content = content.slice(numWritten);
+    } while (content.length > 0);
   } finally {
     stream.close();
   }
 }
 
 /** * Transport Factories ***/
 
 var socket_transport = Task.async(function* () {
   if (!DebuggerServer.listeningSockets) {
     let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT");
     let authenticator = new AuthenticatorType.Server();
     authenticator.allowConnection = () => {
       return DebuggerServer.AuthenticationResult.ALLOW;
     };
-    let listener = DebuggerServer.createListener();
-    listener.portOrPath = -1;
-    listener.authenticator = authenticator;
-    yield listener.open();
+    let debuggerListener = DebuggerServer.createListener();
+    debuggerListener.portOrPath = -1;
+    debuggerListener.authenticator = authenticator;
+    yield debuggerListener.open();
   }
   let port = DebuggerServer._listeners[0].port;
   do_print("Debugger server port is " + port);
   return DebuggerClient.socketConnect({ host: "127.0.0.1", port });
 });
 
 function local_transport() {
   return promise.resolve(DebuggerServer.connectPipe());
--- a/devtools/shared/transport/tests/unit/test_bulk_error.js
+++ b/devtools/shared/transport/tests/unit/test_bulk_error.js
@@ -68,18 +68,18 @@ function json_reply(client, response) {
     actor: response.testBulk,
     type: "jsonReply",
     length: reallyLong.length
   });
 
   // Send bulk data to server
   let copyDeferred = defer();
   request.on("bulk-send-ready", ({writer, done}) => {
-    let input = Cc["@mozilla.org/io/string-input-stream;1"].
-                  createInstance(Ci.nsIStringInputStream);
+    let input = Cc["@mozilla.org/io/string-input-stream;1"]
+                  .createInstance(Ci.nsIStringInputStream);
     input.setData(reallyLong, reallyLong.length);
     try {
       writer.copyFrom(input, () => {
         input.close();
         done();
       });
       do_throw(new Error("Copying should fail, the stream is not async."));
     } catch (e) {
--- a/devtools/shared/transport/tests/unit/test_client_server_bulk.js
+++ b/devtools/shared/transport/tests/unit/test_client_server_bulk.js
@@ -145,35 +145,37 @@ var test_bulk_request_cs = Task.async(fu
   let transport = yield transportFactory();
 
   let client = new DebuggerClient(transport);
   client.connect().then(([app, traits]) => {
     do_check_eq(traits.bulk, true);
     client.listTabs(clientDeferred.resolve);
   });
 
+  function bulkSendReadyCallback({copyFrom}) {
+    NetUtil.asyncFetch({
+      uri: NetUtil.newURI(getTestTempFile("bulk-input")),
+      loadUsingSystemPrincipal: true
+    }, input => {
+      copyFrom(input).then(() => {
+        input.close();
+        bulkCopyDeferred.resolve();
+      });
+    });
+  }
+
   clientDeferred.promise.then(response => {
     let request = client.startBulkRequest({
       actor: response.testBulk,
       type: actorType,
       length: really_long().length
     });
 
     // Send bulk data to server
-    request.on("bulk-send-ready", ({copyFrom}) => {
-      NetUtil.asyncFetch({
-        uri: NetUtil.newURI(getTestTempFile("bulk-input")),
-        loadUsingSystemPrincipal: true
-      }, input => {
-        copyFrom(input).then(() => {
-          input.close();
-          bulkCopyDeferred.resolve();
-        });
-      });
-    });
+    request.on("bulk-send-ready", bulkSendReadyCallback);
 
     // Set up reply handling for this type
     replyHandlers[replyType](request).then(() => {
       client.close();
       transport.close();
     });
   }).then(null, do_throw);
 
--- a/devtools/shared/transport/tests/unit/test_dbgsocket.js
+++ b/devtools/shared/transport/tests/unit/test_dbgsocket.js
@@ -1,28 +1,27 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 var gPort;
 var gExtraListener;
 
-function run_test()
-{
+function run_test() {
   do_print("Starting test at " + new Date().toTimeString());
   initTestDebuggerServer();
 
   add_task(test_socket_conn);
   add_task(test_socket_shutdown);
   add_test(test_pipe_conn);
 
   run_next_test();
 }
 
-function* test_socket_conn()
-{
+function* test_socket_conn() {
   do_check_eq(DebuggerServer.listeningSockets, 0);
   let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT");
   let authenticator = new AuthenticatorType.Server();
   authenticator.allowConnection = () => {
     return DebuggerServer.AuthenticationResult.ALLOW;
   };
   let listener = DebuggerServer.createListener();
   do_check_true(listener);
@@ -48,77 +47,74 @@ function* test_socket_conn()
 
   // Assert that connection settings are available on transport object
   let settings = transport.connectionSettings;
   do_check_eq(settings.host, "127.0.0.1");
   do_check_eq(settings.port, gPort);
 
   let closedDeferred = defer();
   transport.hooks = {
-    onPacket: function (aPacket) {
-      this.onPacket = function (aPacket) {
-        do_check_eq(aPacket.unicode, unicodeString);
+    onPacket: function (packet) {
+      this.onPacket = function ({unicode}) {
+        do_check_eq(unicode, unicodeString);
         transport.close();
       };
       // Verify that things work correctly when bigger than the output
       // transport buffers and when transporting unicode...
       transport.send({to: "root",
                       type: "echo",
                       reallylong: really_long(),
                       unicode: unicodeString});
-      do_check_eq(aPacket.from, "root");
+      do_check_eq(packet.from, "root");
     },
-    onClosed: function (aStatus) {
+    onClosed: function (status) {
       closedDeferred.resolve();
     },
   };
   transport.ready();
   return closedDeferred.promise;
 }
 
-function* test_socket_shutdown()
-{
+function* test_socket_shutdown() {
   do_check_eq(DebuggerServer.listeningSockets, 2);
   gExtraListener.close();
   do_check_eq(DebuggerServer.listeningSockets, 1);
   do_check_true(DebuggerServer.closeAllListeners());
   do_check_eq(DebuggerServer.listeningSockets, 0);
   // Make sure closing the listener twice does nothing.
   do_check_false(DebuggerServer.closeAllListeners());
   do_check_eq(DebuggerServer.listeningSockets, 0);
 
   do_print("Connecting to a server socket at " + new Date().toTimeString());
   try {
-    let transport = yield DebuggerClient.socketConnect({
+    yield DebuggerClient.socketConnect({
       host: "127.0.0.1",
       port: gPort
     });
   } catch (e) {
     if (e.result == Cr.NS_ERROR_CONNECTION_REFUSED ||
         e.result == Cr.NS_ERROR_NET_TIMEOUT) {
       // The connection should be refused here, but on slow or overloaded
       // machines it may just time out.
       do_check_true(true);
       return;
-    } else {
-      throw e;
     }
+    throw e;
   }
 
   // Shouldn't reach this, should never connect.
   do_check_true(false);
 }
 
-function test_pipe_conn()
-{
+function test_pipe_conn() {
   let transport = DebuggerServer.connectPipe();
   transport.hooks = {
-    onPacket: function (aPacket) {
-      do_check_eq(aPacket.from, "root");
+    onPacket: function (packet) {
+      do_check_eq(packet.from, "root");
       transport.close();
     },
-    onClosed: function (aStatus) {
+    onClosed: function (status) {
       run_next_test();
     }
   };
 
   transport.ready();
 }
--- a/devtools/shared/transport/tests/unit/test_dbgsocket_connection_drop.js
+++ b/devtools/shared/transport/tests/unit/test_dbgsocket_connection_drop.js
@@ -2,16 +2,17 @@
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 /**
  * Bug 755412 - checks if the server drops the connection on an improperly
  * framed packet, i.e. when the length header is invalid.
  */
+"use strict";
 
 const { RawPacket } = require("devtools/shared/transport/packets");
 
 function run_test() {
   do_print("Starting test at " + new Date().toTimeString());
   initTestDebuggerServer();
 
   add_task(test_socket_conn_drops_after_invalid_header);
@@ -56,26 +57,26 @@ var test_helper = Task.async(function* (
   listener.open();
 
   let transport = yield DebuggerClient.socketConnect({
     host: "127.0.0.1",
     port: listener.port
   });
   let closedDeferred = defer();
   transport.hooks = {
-    onPacket: function (aPacket) {
-      this.onPacket = function (aPacket) {
+    onPacket: function (packet) {
+      this.onPacket = function () {
         do_throw(new Error("This connection should be dropped."));
         transport.close();
       };
 
       // Inject the payload directly into the stream.
       transport._outgoing.push(new RawPacket(transport, payload));
       transport._flushOutgoing();
     },
-    onClosed: function (aStatus) {
+    onClosed: function (status) {
       do_check_true(true);
       closedDeferred.resolve();
     },
   };
   transport.ready();
   return closedDeferred.promise;
 });
--- a/devtools/shared/transport/tests/unit/test_delimited_read.js
+++ b/devtools/shared/transport/tests/unit/test_delimited_read.js
@@ -1,10 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 const StreamUtils = require("devtools/shared/transport/stream-utils");
 
 const StringInputStream = CC("@mozilla.org/io/string-input-stream;1",
                              "nsIStringInputStream", "setData");
 
 function run_test() {
   add_task(function* () {
--- a/devtools/shared/transport/tests/unit/test_no_bulk.js
+++ b/devtools/shared/transport/tests/unit/test_no_bulk.js
@@ -15,24 +15,22 @@ function run_test() {
   });
 
   run_next_test();
 }
 
 /** * Tests ***/
 
 var test_bulk_send_error = Task.async(function* (transportFactory) {
-  let deferred = defer();
   let transport = yield transportFactory();
 
   let client = new DebuggerClient(transport);
   return client.connect().then(([app, traits]) => {
     do_check_false(traits.bulk);
 
     try {
       client.startBulkRequest();
       do_throw(new Error("Can't use bulk since server doesn't support it"));
     } catch (e) {
       do_check_true(true);
     }
-
   });
 });
--- a/devtools/shared/transport/tests/unit/test_packet.js
+++ b/devtools/shared/transport/tests/unit/test_packet.js
@@ -1,10 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 const { JSONPacket, BulkPacket } =
   require("devtools/shared/transport/packets");
 
 function run_test() {
   add_test(test_packet_done);
   run_next_test();
 }
--- a/devtools/shared/transport/tests/unit/test_transport_bulk.js
+++ b/devtools/shared/transport/tests/unit/test_transport_bulk.js
@@ -69,19 +69,19 @@ var test_bulk_transfer_transport = Task.
         clientDeferred.resolve();
       };
       transport.close();
     });
   }
 
   // Client
   transport.hooks = {
-    onPacket: function (aPacket) {
+    onPacket: function (packet) {
       // We've received the initial start up packet
-      do_check_eq(aPacket.from, "root");
+      do_check_eq(packet.from, "root");
 
       // Server
       do_check_eq(Object.keys(DebuggerServer._connections).length, 1);
       do_print(Object.keys(DebuggerServer._connections));
       for (let connId in DebuggerServer._connections) {
         DebuggerServer._connections[connId].onBulkPacket = on_bulk_packet;
       }
 
--- a/devtools/shared/transport/tests/unit/testactors-no-bulk.js
+++ b/devtools/shared/transport/tests/unit/testactors-no-bulk.js
@@ -1,19 +1,20 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 const { RootActor } = require("devtools/server/actors/root");
 const { DebuggerServer } = require("devtools/server/main");
 
 /**
  * Root actor that doesn't have the bulk trait.
  */
-function createRootActor(aConnection) {
-  let root = new RootActor(aConnection, {
+function createRootActor(connection) {
+  let root = new RootActor(connection, {
     globalActorFactories: DebuggerServer.globalActorFactories
   });
   root.applicationType = "xpcshell-tests";
   root.traits = {
     bulk: false
   };
   return root;
 }
--- a/devtools/shared/transport/tests/unit/testactors.js
+++ b/devtools/shared/transport/tests/unit/testactors.js
@@ -1,72 +1,73 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
 
 const { ActorPool, appendExtraActors, createExtraActors } =
   require("devtools/server/actors/common");
 const { RootActor } = require("devtools/server/actors/root");
 const { ThreadActor } = require("devtools/server/actors/script");
 const { DebuggerServer } = require("devtools/server/main");
 const promise = require("promise");
 
 var gTestGlobals = [];
-DebuggerServer.addTestGlobal = function (aGlobal) {
-  gTestGlobals.push(aGlobal);
+DebuggerServer.addTestGlobal = function (global) {
+  gTestGlobals.push(global);
 };
 
 // A mock tab list, for use by tests. This simply presents each global in
 // gTestGlobals as a tab, and the list is fixed: it never calls its
 // onListChanged handler.
 //
 // As implemented now, we consult gTestGlobals when we're constructed, not
 // when we're iterated over, so tests have to add their globals before the
 // root actor is created.
-function TestTabList(aConnection) {
-  this.conn = aConnection;
+function TestTabList(connection) {
+  this.conn = connection;
 
   // An array of actors for each global added with
   // DebuggerServer.addTestGlobal.
   this._tabActors = [];
 
   // A pool mapping those actors' names to the actors.
-  this._tabActorPool = new ActorPool(aConnection);
+  this._tabActorPool = new ActorPool(connection);
 
   for (let global of gTestGlobals) {
-    let actor = new TestTabActor(aConnection, global);
+    let actor = new TestTabActor(connection, global);
     actor.selected = false;
     this._tabActors.push(actor);
     this._tabActorPool.addActor(actor);
   }
   if (this._tabActors.length > 0) {
     this._tabActors[0].selected = true;
   }
 
-  aConnection.addActorPool(this._tabActorPool);
+  connection.addActorPool(this._tabActorPool);
 }
 
 TestTabList.prototype = {
   constructor: TestTabList,
   getList: function () {
     return promise.resolve([...this._tabActors]);
   }
 };
 
-function createRootActor(aConnection) {
-  let root = new RootActor(aConnection, {
-    tabList: new TestTabList(aConnection),
+function createRootActor(connection) {
+  let root = new RootActor(connection, {
+    tabList: new TestTabList(connection),
     globalActorFactories: DebuggerServer.globalActorFactories
   });
   root.applicationType = "xpcshell-tests";
   return root;
 }
 
-function TestTabActor(aConnection, aGlobal) {
-  this.conn = aConnection;
-  this._global = aGlobal;
+function TestTabActor(connection, global) {
+  this.conn = connection;
+  this._global = global;
   this._threadActor = new ThreadActor(this, this._global);
   this.conn.addActor(this._threadActor);
   this._attached = false;
   this._extraActors = {};
 }
 
 TestTabActor.prototype = {
   constructor: TestTabActor,
@@ -91,28 +92,28 @@ TestTabActor.prototype = {
       this.conn.addActorPool(this._tabActorPool);
     }
 
     this._appendExtraActors(response);
 
     return response;
   },
 
-  onAttach: function (aRequest) {
+  onAttach: function (request) {
     this._attached = true;
 
     let response = { type: "tabAttached", threadActor: this._threadActor.actorID };
     this._appendExtraActors(response);
 
     return response;
   },
 
-  onDetach: function (aRequest) {
+  onDetach: function (request) {
     if (!this._attached) {
-      return { "error":"wrongState" };
+      return { "error": "wrongState" };
     }
     return { type: "detached" };
   },
 
   /* Support for DebuggerServer.addTabActor. */
   _createExtraActors: createExtraActors,
   _appendExtraActors: appendExtraActors
 };
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7567,17 +7567,23 @@ nsDocShell::EndPageLoad(nsIWebProgress* 
                         nsIChannel* aChannel, nsresult aStatus)
 {
   if (!aChannel) {
     return NS_ERROR_NULL_POINTER;
   }
 
   nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
   if (reporter) {
-    reporter->FlushConsoleReports(GetDocument());
+    nsCOMPtr<nsILoadGroup> loadGroup;
+    aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
+    if (loadGroup) {
+      reporter->FlushConsoleReports(loadGroup);
+    } else {
+      reporter->FlushConsoleReports(GetDocument());
+    }
   }
 
   nsCOMPtr<nsIURI> url;
   nsresult rv = aChannel->GetURI(getter_AddRefs(url));
   if (NS_FAILED(rv)) {
     return rv;
   }
 
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -928,28 +928,38 @@ TimeoutManager::Timeouts::ResetTimersFor
 
       // Since we reset When() we need to move |timeout| to the right
       // place in the list so that it remains sorted by When().
 
       // Get the pointer to the next timeout now, before we move the
       // current timeout in the list.
       Timeout* nextTimeout = timeout->getNext();
 
-      // It is safe to remove and re-insert because When() is now
-      // strictly smaller than it used to be, so we know we'll insert
-      // |timeout| before nextTimeout.
-      NS_ASSERTION(!nextTimeout ||
-                   timeout->When() < nextTimeout->When(), "How did that happen?");
-      timeout->remove();
-      // Insert() will addref |timeout| and reset mFiringDepth.  Make sure to
-      // undo that after calling it.
-      uint32_t firingDepth = timeout->mFiringDepth;
-      Insert(timeout, aSortBy);
-      timeout->mFiringDepth = firingDepth;
-      timeout->Release();
+      // Since we are only reducing intervals in this method we can
+      // make an optimization here.  If the reduction does not cause us
+      // to fall before our previous timeout then we do not have to
+      // remove and re-insert the current timeout.  This is important
+      // because re-insertion makes this algorithm O(n^2).  Since we
+      // will typically be shifting a lot of timers at once this
+      // optimization saves us a lot of work.
+      Timeout* prevTimeout = timeout->getPrevious();
+      if (prevTimeout && prevTimeout->When() > timeout->When()) {
+        // It is safe to remove and re-insert because When() is now
+        // strictly smaller than it used to be, so we know we'll insert
+        // |timeout| before nextTimeout.
+        NS_ASSERTION(!nextTimeout ||
+                     timeout->When() < nextTimeout->When(), "How did that happen?");
+        timeout->remove();
+        // Insert() will addref |timeout| and reset mFiringDepth.  Make sure to
+        // undo that after calling it.
+        uint32_t firingDepth = timeout->mFiringDepth;
+        Insert(timeout, aSortBy);
+        timeout->mFiringDepth = firingDepth;
+        timeout->Release();
+      }
 
       nsresult rv = timeout->InitTimer(aQueue, delay.ToMilliseconds());
 
       if (NS_FAILED(rv)) {
         NS_WARNING("Error resetting non background timer for DOM timeout!");
         return rv;
       }
 
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -1792,18 +1792,17 @@ nsContentUtils::ParseLegacyFontSize(cons
 
   return clamped(value, 1, 7);
 }
 
 /* static */
 bool
 nsContentUtils::IsControlledByServiceWorker(nsIDocument* aDocument)
 {
-  if (aDocument &&
-      aDocument->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
+  if (nsContentUtils::IsInPrivateBrowsing(aDocument)) {
     return false;
   }
 
   RefPtr<workers::ServiceWorkerManager> swm =
     workers::ServiceWorkerManager::GetInstance();
   MOZ_ASSERT(swm);
 
   ErrorResult rv;
@@ -3201,16 +3200,50 @@ nsContentUtils::GetOriginAttributes(nsIL
     nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
     if (loadContext && loadContext->GetOriginAttributes(attrs)) {
       attrs.StripAttributes(OriginAttributes::STRIP_ADDON_ID);
     }
   }
   return attrs;
 }
 
+// static
+bool
+nsContentUtils::IsInPrivateBrowsing(nsIDocument* aDoc)
+{
+  if (!aDoc) {
+    return false;
+  }
+
+  nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
+  if (loadGroup) {
+    return IsInPrivateBrowsing(loadGroup);
+  }
+
+  nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
+  return channel && NS_UsePrivateBrowsing(channel);
+}
+
+// static
+bool
+nsContentUtils::IsInPrivateBrowsing(nsILoadGroup* aLoadGroup)
+{
+  if (!aLoadGroup) {
+    return false;
+  }
+  bool isPrivate = false;
+  nsCOMPtr<nsIInterfaceRequestor> callbacks;
+  aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
+  if (callbacks) {
+    nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
+    isPrivate = loadContext && loadContext->UsePrivateBrowsing();
+  }
+  return isPrivate;
+}
+
 bool
 nsContentUtils::DocumentInactiveForImageLoads(nsIDocument* aDocument)
 {
   if (aDocument && !IsChromeDoc(aDocument) && !aDocument->IsResourceDoc()) {
     nsCOMPtr<nsPIDOMWindowInner> win =
       do_QueryInterface(aDocument->GetScopeObject());
     return !win || !win->GetDocShell();
   }
@@ -3220,36 +3253,19 @@ nsContentUtils::DocumentInactiveForImage
 imgLoader*
 nsContentUtils::GetImgLoaderForDocument(nsIDocument* aDoc)
 {
   NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aDoc), nullptr);
 
   if (!aDoc) {
     return imgLoader::NormalLoader();
   }
-
-  nsCOMPtr<nsILoadGroup> loadGroup = aDoc->GetDocumentLoadGroup();
-  if (loadGroup) {
-    nsCOMPtr<nsIInterfaceRequestor> callbacks;
-    loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
-    if (callbacks) {
-      nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
-      if (loadContext && loadContext->UsePrivateBrowsing()) {
-        return imgLoader::PrivateBrowsingLoader();
-      }
-    }
-    return imgLoader::NormalLoader();
-  }
-
-  nsCOMPtr<nsIChannel> channel = aDoc->GetChannel();
-  if (channel && NS_UsePrivateBrowsing(channel)) {
-    return imgLoader::PrivateBrowsingLoader();
-  }
-
-  return imgLoader::NormalLoader();
+  bool isPrivate = IsInPrivateBrowsing(aDoc);
+  return isPrivate ? imgLoader::PrivateBrowsingLoader()
+                   : imgLoader::NormalLoader();
 }
 
 // static
 imgLoader*
 nsContentUtils::GetImgLoaderForChannel(nsIChannel* aChannel,
                                        nsIDocument* aContext)
 {
   NS_ENSURE_TRUE(!DocumentInactiveForImageLoads(aContext), nullptr);
@@ -3671,16 +3687,32 @@ nsContentUtils::ReportToConsoleNonLocali
   uint64_t innerWindowID = 0;
   if (aDocument) {
     if (!aURI) {
       aURI = aDocument->GetDocumentURI();
     }
     innerWindowID = aDocument->InnerWindowID();
   }
 
+  return ReportToConsoleByWindowID(aErrorText, aErrorFlags, aCategory,
+                                   innerWindowID, aURI, aSourceLine,
+                                   aLineNumber, aColumnNumber, aLocationMode);
+}
+
+/* static */ nsresult
+nsContentUtils::ReportToConsoleByWindowID(const nsAString& aErrorText,
+                                          uint32_t aErrorFlags,
+                                          const nsACString& aCategory,
+                                          uint64_t aInnerWindowID,
+                                          nsIURI* aURI,
+                                          const nsAFlatString& aSourceLine,
+                                          uint32_t aLineNumber,
+                                          uint32_t aColumnNumber,
+                                          MissingErrorLocationMode aLocationMode)
+{
   nsresult rv;
   if (!sConsoleService) { // only need to bother null-checking here
     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsAutoCString spec;
   if (!aLineNumber && aLocationMode == eUSE_CALLING_LOCATION) {
@@ -3697,17 +3729,17 @@ nsContentUtils::ReportToConsoleNonLocali
       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = errorObject->InitWithWindowID(aErrorText,
                                      NS_ConvertUTF8toUTF16(spec), // file name
                                      aSourceLine,
                                      aLineNumber, aColumnNumber,
                                      aErrorFlags, aCategory,
-                                     innerWindowID);
+                                     aInnerWindowID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return sConsoleService->LogMessage(errorObject);
 }
 
 void
 nsContentUtils::LogMessageToConsole(const char* aMsg)
 {
@@ -7336,18 +7368,28 @@ nsContentUtils::GetInnerWindowID(nsIRequ
 
   nsCOMPtr<nsILoadGroup> loadGroup;
   nsresult rv = aRequest->GetLoadGroup(getter_AddRefs(loadGroup));
 
   if (NS_FAILED(rv) || !loadGroup) {
     return 0;
   }
 
+  return GetInnerWindowID(loadGroup);
+}
+
+uint64_t
+nsContentUtils::GetInnerWindowID(nsILoadGroup* aLoadGroup)
+{
+  if (!aLoadGroup) {
+    return 0;
+  }
+
   nsCOMPtr<nsIInterfaceRequestor> callbacks;
-  rv = loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
+  nsresult rv = aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
   if (NS_FAILED(rv) || !callbacks) {
     return 0;
   }
 
   nsCOMPtr<nsILoadContext> loadContext = do_GetInterface(callbacks);
   if (!loadContext) {
     return 0;
   }
@@ -8620,17 +8662,17 @@ nsContentUtils::InternalStorageAllowedFo
   if (aWindow) {
     // If the document is sandboxed, then it is not permitted to use storage
     nsIDocument* document = aWindow->GetExtantDoc();
     if (document->GetSandboxFlags() & SANDBOXED_ORIGIN) {
       return StorageAccess::eDeny;
     }
 
     // Check if we are in private browsing, and record that fact
-    if (document->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
+    if (IsInPrivateBrowsing(document)) {
       access = StorageAccess::ePrivateBrowsing;
     }
   }
 
   nsCOMPtr<nsIPermissionManager> permissionManager =
     services::GetPermissionManager();
   if (!permissionManager) {
     return StorageAccess::eDeny;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -817,16 +817,26 @@ public:
 
   /**
    * Returns origin attributes of the load group.
    **/
   static mozilla::OriginAttributes
   GetOriginAttributes(nsILoadGroup* aLoadGroup);
 
   /**
+   * Returns true if this document is in a Private Browsing window.
+   */
+  static bool IsInPrivateBrowsing(nsIDocument* aDoc);
+
+  /**
+   * Returns true if this loadGroup uses Private Browsing.
+   */
+  static bool IsInPrivateBrowsing(nsILoadGroup* aLoadGroup);
+
+  /**
    * If aNode is not an element, return true exactly when aContent's binding
    * parent is null.
    *
    * If aNode is an element, return true exactly when aContent's binding parent
    * is the same as aNode's.
    *
    * This method is particularly useful for callers who are trying to ensure
    * that they are working with a non-anonymous descendant of a given node.  If
@@ -884,16 +894,47 @@ public:
                                               const nsAFlatString& aSourceLine
                                                 = EmptyString(),
                                               uint32_t aLineNumber = 0,
                                               uint32_t aColumnNumber = 0,
                                               MissingErrorLocationMode aLocationMode
                                                 = eUSE_CALLING_LOCATION);
 
   /**
+   * Report a non-localized error message to the error console base on the
+   * innerWindowID.
+   *   @param aErrorText the error message
+   *   @param aErrorFlags See nsIScriptError.
+   *   @param aCategory Name of module reporting error.
+   *   @param [aInnerWindowID] Inner window ID for document which triggered the
+   *          message.
+   *   @param [aURI=nullptr] (Optional) URI of resource containing error.
+   *   @param [aSourceLine=EmptyString()] (Optional) The text of the line that
+              contains the error (may be empty).
+   *   @param [aLineNumber=0] (Optional) Line number within resource
+              containing error.
+   *   @param [aColumnNumber=0] (Optional) Column number within resource
+              containing error.
+              If aURI is null, then aDocument->GetDocumentURI() is used.
+   *   @param [aLocationMode] (Optional) Specifies the behavior if
+              error location information is omitted.
+   */
+  static nsresult ReportToConsoleByWindowID(const nsAString& aErrorText,
+                                            uint32_t aErrorFlags,
+                                            const nsACString& aCategory,
+                                            uint64_t aInnerWindowID,
+                                            nsIURI* aURI = nullptr,
+                                            const nsAFlatString& aSourceLine
+                                              = EmptyString(),
+                                            uint32_t aLineNumber = 0,
+                                            uint32_t aColumnNumber = 0,
+                                            MissingErrorLocationMode aLocationMode
+                                              = eUSE_CALLING_LOCATION);
+
+  /**
    * Report a localized error message to the error console.
    *   @param aErrorFlags See nsIScriptError.
    *   @param aCategory Name of module reporting error.
    *   @param aDocument Reference to the document which triggered the message.
    *   @param aFile Properties file containing localized message.
    *   @param aMessageName Name of localized message.
    *   @param [aParams=nullptr] (Optional) Parameters to be substituted into
               localized message.
@@ -2446,21 +2487,26 @@ public:
 
   /**
    * Returns whether a given header is forbidden for an XHR or fetch
    * response.
    */
   static bool IsForbiddenResponseHeader(const nsACString& aHeader);
 
   /**
-   * Returns the inner window ID for the window associated with a request,
+   * Returns the inner window ID for the window associated with a request.
    */
   static uint64_t GetInnerWindowID(nsIRequest* aRequest);
 
   /**
+   * Returns the inner window ID for the window associated with a load group.
+   */
+  static uint64_t GetInnerWindowID(nsILoadGroup* aLoadGroup);
+
+  /**
    * If the hostname for aURI is an IPv6 it encloses it in brackets,
    * otherwise it just outputs the hostname in aHost.
    */
   static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
   static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
 
   /*
    * Call the given callback on all remote children of the given top-level
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -2483,17 +2483,22 @@ nsScriptLoader::OnStreamComplete(nsIIncr
     MOZ_ASSERT(mReporter);
 
     nsAutoCString sourceUri;
     if (mDocument && mDocument->GetDocumentURI()) {
       mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
     }
     rv = aSRIDataVerifier->Verify(aRequest->mIntegrity, channel, sourceUri,
                                   mReporter);
-    mReporter->FlushConsoleReports(mDocument);
+    if (channelRequest) {
+      mReporter->FlushReportsToConsole(
+        nsContentUtils::GetInnerWindowID(channelRequest));
+    } else {
+      mReporter->FlushConsoleReports(mDocument);
+    }
     if (NS_FAILED(rv)) {
       rv = NS_ERROR_SRI_CORRUPT;
     }
   } else {
     nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
 
     if (loadInfo->GetEnforceSRI()) {
       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
--- a/dom/console/ConsoleReportCollector.cpp
+++ b/dom/console/ConsoleReportCollector.cpp
@@ -34,64 +34,85 @@ ConsoleReportCollector::AddConsoleReport
 
   mPendingReports.AppendElement(PendingReport(aErrorFlags, aCategory,
                                               aPropertiesFile, aSourceFileURI,
                                               aLineNumber, aColumnNumber,
                                               aMessageName, aStringParams));
 }
 
 void
-ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
-                                            ReportAction aAction)
+ConsoleReportCollector::FlushReportsToConsole(uint64_t aInnerWindowID,
+                                              ReportAction aAction)
 {
-  MOZ_ASSERT(NS_IsMainThread());
-
   nsTArray<PendingReport> reports;
 
   {
     MutexAutoLock lock(mMutex);
     if (aAction == ReportAction::Forget) {
       mPendingReports.SwapElements(reports);
     } else {
       reports = mPendingReports;
     }
   }
 
   for (uint32_t i = 0; i < reports.Length(); ++i) {
     PendingReport& report = reports[i];
 
+    nsXPIDLString errorText;
+    nsresult rv;
+    if (!report.mStringParams.IsEmpty()) {
+      rv = nsContentUtils::FormatLocalizedString(report.mPropertiesFile,
+                                                 report.mMessageName.get(),
+                                                 report.mStringParams,
+                                                 errorText);
+    } else {
+      rv = nsContentUtils::GetLocalizedString(report.mPropertiesFile,
+                                              report.mMessageName.get(),
+                                              errorText);
+    }
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      continue;
+    }
+
     // It would be nice if we did not have to do this since ReportToConsole()
     // just turns around and converts it back to a spec.
     nsCOMPtr<nsIURI> uri;
     if (!report.mSourceFileURI.IsEmpty()) {
       nsresult rv = NS_NewURI(getter_AddRefs(uri), report.mSourceFileURI);
       MOZ_ALWAYS_SUCCEEDS(rv);
       if (NS_FAILED(rv)) {
         continue;
       }
     }
 
-    // Convert back from nsTArray<nsString> to the char16_t** format required
-    // by our l10n libraries and ReportToConsole. (bug 1219762)
-    UniquePtr<const char16_t*[]> params;
-    uint32_t paramsLength = report.mStringParams.Length();
-    if (paramsLength > 0) {
-      params = MakeUnique<const char16_t*[]>(paramsLength);
-      for (uint32_t j = 0; j < paramsLength; ++j) {
-        params[j] = report.mStringParams[j].get();
-      }
-    }
+    nsContentUtils::ReportToConsoleByWindowID(errorText,
+                                              report.mErrorFlags,
+                                              report.mCategory,
+                                              aInnerWindowID,
+                                              uri,
+                                              EmptyString(),
+                                              report.mLineNumber,
+                                              report.mColumnNumber);
+  }
+}
 
-    nsContentUtils::ReportToConsole(report.mErrorFlags, report.mCategory,
-                                    aDocument, report.mPropertiesFile,
-                                    report.mMessageName.get(),
-                                    params.get(),
-                                    paramsLength, uri, EmptyString(),
-                                    report.mLineNumber, report.mColumnNumber);
-  }
+void
+ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument,
+                                            ReportAction aAction)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  FlushReportsToConsole(aDocument ? aDocument->InnerWindowID() : 0, aAction);
+}
+
+void
+ConsoleReportCollector::FlushConsoleReports(nsILoadGroup* aLoadGroup,
+                                            ReportAction aAction)
+{
+  FlushReportsToConsole(nsContentUtils::GetInnerWindowID(aLoadGroup), aAction);
 }
 
 void
 ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
 {
   MOZ_ASSERT(aCollector);
 
   nsTArray<PendingReport> reports;
@@ -106,81 +127,16 @@ ConsoleReportCollector::FlushConsoleRepo
     aCollector->AddConsoleReport(report.mErrorFlags, report.mCategory,
                                  report.mPropertiesFile, report.mSourceFileURI,
                                  report.mLineNumber, report.mColumnNumber,
                                  report.mMessageName, report.mStringParams);
   }
 }
 
 void
-ConsoleReportCollector::FlushReportsByWindowId(uint64_t aWindowId,
-                                               ReportAction aAction)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  nsTArray<PendingReport> reports;
-
-  {
-    MutexAutoLock lock(mMutex);
-    if (aAction == ReportAction::Forget) {
-      mPendingReports.SwapElements(reports);
-    } else {
-      reports = mPendingReports;
-    }
-  }
-
-  nsCOMPtr<nsIConsoleService> consoleService =
-    do_GetService(NS_CONSOLESERVICE_CONTRACTID);
-  if (!consoleService) {
-    NS_WARNING("GetConsoleService failed");
-    return;
-  }
-
-  nsresult rv;
-  for (uint32_t i = 0; i < reports.Length(); ++i) {
-    PendingReport& report = reports[i];
-
-    nsXPIDLString errorText;
-    if (!report.mStringParams.IsEmpty()) {
-      rv = nsContentUtils::FormatLocalizedString(report.mPropertiesFile,
-                                                 report.mMessageName.get(),
-                                                 report.mStringParams,
-                                                 errorText);
-    } else {
-      rv = nsContentUtils::GetLocalizedString(report.mPropertiesFile,
-                                              report.mMessageName.get(),
-                                              errorText);
-    }
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      continue;
-    }
-
-    nsCOMPtr<nsIScriptError> errorObject =
-    do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      continue;
-    }
-
-    rv = errorObject->InitWithWindowID(errorText,
-                                       NS_ConvertUTF8toUTF16(report.mSourceFileURI),
-                                       EmptyString(),
-                                       report.mLineNumber,
-                                       report.mColumnNumber,
-                                       report.mErrorFlags,
-                                       report.mCategory,
-                                       aWindowId);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      continue;
-    }
-
-    consoleService->LogMessage(errorObject);
-  }
-}
-
-void
 ConsoleReportCollector::ClearConsoleReports()
 {
   MutexAutoLock lock(mMutex);
 
   mPendingReports.Clear();
 }
 
 ConsoleReportCollector::~ConsoleReportCollector()
--- a/dom/console/ConsoleReportCollector.h
+++ b/dom/console/ConsoleReportCollector.h
@@ -22,27 +22,31 @@ public:
   AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
                    nsContentUtils::PropertiesFile aPropertiesFile,
                    const nsACString& aSourceFileURI,
                    uint32_t aLineNumber, uint32_t aColumnNumber,
                    const nsACString& aMessageName,
                    const nsTArray<nsString>& aStringParams) override;
 
   void
+  FlushReportsToConsole(uint64_t aInnerWindowID,
+                        ReportAction aAction = ReportAction::Forget) override;
+
+  void
   FlushConsoleReports(nsIDocument* aDocument,
                       ReportAction aAction = ReportAction::Forget) override;
 
   void
+  FlushConsoleReports(nsILoadGroup* aLoadGroup,
+                      ReportAction aAction = ReportAction::Forget) override;
+
+  void
   FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
 
   void
-  FlushReportsByWindowId(uint64_t aWindowId,
-                         ReportAction aAction = ReportAction::Forget) override;
-
-  void
   ClearConsoleReports() override;
 
 private:
   ~ConsoleReportCollector();
 
   struct PendingReport
   {
     PendingReport(uint32_t aErrorFlags, const nsACString& aCategory,
--- a/dom/console/nsIConsoleReportCollector.h
+++ b/dom/console/nsIConsoleReportCollector.h
@@ -69,47 +69,58 @@ public:
   // An enum calss to indicate whether should free the pending reports or not.
   // Forget        Free the pending reports.
   // Save          Keep the pending reports.
   enum class ReportAction {
     Forget,
     Save
   };
 
+  // Flush all pending reports to the console.  May be called from any thread.
+  //
+  // aInnerWindowID A inner window ID representing where to flush the reports.
+  // aAction        An action to determine whether to reserve the pending
+  //                reports. Defalut action is to forget the report.
+  virtual void
+  FlushReportsToConsole(uint64_t aInnerWindowID,
+                        ReportAction aAction = ReportAction::Forget) = 0;
+
   // Flush all pending reports to the console.  Main thread only.
   //
   // aDocument      An optional document representing where to flush the
   //                reports.  If provided, then the corresponding window's
   //                web console will get the reports.  Otherwise the reports
   //                go to the browser console.
   // aAction        An action to determine whether to reserve the pending
   //                reports. Defalut action is to forget the report.
   virtual void
   FlushConsoleReports(nsIDocument* aDocument,
                       ReportAction aAction = ReportAction::Forget) = 0;
 
+  // Flush all pending reports to the console.  May be called from any thread.
+  //
+  // aLoadGroup     An optional loadGroup representing where to flush the
+  //                reports.  If provided, then the corresponding window's
+  //                web console will get the reports.  Otherwise the reports
+  //                go to the browser console.
+  // aAction        An action to determine whether to reserve the pending
+  //                reports. Defalut action is to forget the report.
+  virtual void
+  FlushConsoleReports(nsILoadGroup* aLoadGroup,
+                      ReportAction aAction = ReportAction::Forget) = 0;
+
+
   // Flush all pending reports to another collector.  May be called from any
   // thread.
   //
   // aCollector     A required collector object that will effectively take
   //                ownership of our currently console reports.
   virtual void
   FlushConsoleReports(nsIConsoleReportCollector* aCollector) = 0;
 
-  // Flush all pending reports to the console accroding to window ID. Main
-  // thread only.
-  //
-  // aWindowId      A window ID representing where to flush the reports and it's
-  //                typically the inner window ID.
-  //
-  // aAction        An action to decide whether free the pending reports or not.
-  virtual void
-  FlushReportsByWindowId(uint64_t aWindowId,
-                         ReportAction aAction = ReportAction::Forget) = 0;
-
   // Clear all pending reports.
   virtual void
   ClearConsoleReports() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIConsoleReportCollector, NS_NSICONSOLEREPORTCOLLECTOR_IID)
 
 #endif // nsIConsoleReportCollector_h
--- a/dom/fetch/Fetch.cpp
+++ b/dom/fetch/Fetch.cpp
@@ -95,41 +95,41 @@ private:
   FlushConsoleReport() override;
 };
 
 class MainThreadFetchResolver final : public FetchDriverObserver
 {
   RefPtr<Promise> mPromise;
   RefPtr<Response> mResponse;
 
-  nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   NS_DECL_OWNINGTHREAD
 public:
   explicit MainThreadFetchResolver(Promise* aPromise);
 
   void
   OnResponseAvailableInternal(InternalResponse* aResponse) override;
 
-  void SetDocument(nsIDocument* aDocument)
+  void SetLoadGroup(nsILoadGroup* aLoadGroup)
   {
-    mDocument = aDocument;
+    mLoadGroup = aLoadGroup;
   }
 
   virtual void OnResponseEnd() override
   {
     FlushConsoleReport();
   }
 
 private:
   ~MainThreadFetchResolver();
 
   void FlushConsoleReport() override
   {
-    mReporter->FlushConsoleReports(mDocument);
+    mReporter->FlushConsoleReports(mLoadGroup);
   }
 };
 
 class MainThreadFetchRunnable : public Runnable
 {
   RefPtr<WorkerFetchResolver> mResolver;
   RefPtr<InternalRequest> mRequest;
 
@@ -233,17 +233,17 @@ FetchRequest(nsIGlobalObject* aGlobal, c
       }
     }
 
     Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
 
     RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(p);
     RefPtr<FetchDriver> fetch = new FetchDriver(r, principal, loadGroup);
     fetch->SetDocument(doc);
-    resolver->SetDocument(doc);
+    resolver->SetLoadGroup(loadGroup);
     aRv = fetch->Fetch(resolver);
     if (NS_WARN_IF(aRv.Failed())) {
       return nullptr;
     }
   } else {
     WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     MOZ_ASSERT(worker);
 
@@ -448,40 +448,40 @@ WorkerFetchResolver::FlushConsoleReport(
   MOZ_ASSERT(mPromiseProxy);
 
   if(!mReporter) {
     return;
   }
 
   workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
   if (!worker) {
-    mReporter->FlushConsoleReports((nsIDocument*)nullptr);
+    mReporter->FlushReportsToConsole(0);
     return;
   }
 
   if (worker->IsServiceWorker()) {
     // Flush to service worker
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     if (!swm) {
-      mReporter->FlushConsoleReports((nsIDocument*)nullptr);
+      mReporter->FlushReportsToConsole(0);
       return;
     }
 
     swm->FlushReportsToAllClients(worker->WorkerName(), mReporter);
     return;
   }
 
   if (worker->IsSharedWorker()) {
     // Flush to shared worker
     worker->FlushReportsToSharedWorkers(mReporter);
     return;
   }
 
   // Flush to dedicated worker
-  mReporter->FlushConsoleReports(worker->GetDocument());
+  mReporter->FlushConsoleReports(worker->GetLoadGroup());
 }
 
 nsresult
 ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
                           nsIInputStream** aStream,
                           nsCString& aContentTypeWithCharset,
                           uint64_t& aContentLength)
 {
--- a/dom/file/File.cpp
+++ b/dom/file/File.cpp
@@ -31,16 +31,17 @@
 #include "nsPrintfCString.h"
 #include "mozilla/SHA1.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "nsThreadUtils.h"
 #include "nsStreamUtils.h"
 #include "SlicedInputStream.h"
 
 namespace mozilla {
 namespace dom {
@@ -465,25 +466,28 @@ File::WrapObject(JSContext* aCx, JS::Han
 
 void
 File::GetName(nsAString& aFileName) const
 {
   mImpl->GetName(aFileName);
 }
 
 void
-File::GetPath(nsAString& aPath) const
+File::GetRelativePath(nsAString& aPath) const
 {
-  mImpl->GetPath(aPath);
-}
+  aPath.Truncate();
 
-void
-File::SetPath(const nsAString& aPath)
-{
-  mImpl->SetPath(aPath);
+  nsAutoString path;
+  mImpl->GetDOMPath(path);
+
+  // WebkitRelativePath doesn't start with '/'
+  if (!path.IsEmpty()) {
+    MOZ_ASSERT(path[0] == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
+    aPath.Assign(Substring(path, 1));
+  }
 }
 
 Date
 File::GetLastModifiedDate(ErrorResult& aRv)
 {
   int64_t value = GetLastModified(aRv);
   if (aRv.Failed()) {
     return Date();
@@ -665,24 +669,24 @@ NS_IMPL_ISUPPORTS_INHERITED0(BlobImplFil
 void
 BlobImplBase::GetName(nsAString& aName) const
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   aName = mName;
 }
 
 void
-BlobImplBase::GetPath(nsAString& aPath) const
+BlobImplBase::GetDOMPath(nsAString& aPath) const
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   aPath = mPath;
 }
 
 void
-BlobImplBase::SetPath(const nsAString& aPath)
+BlobImplBase::SetDOMPath(const nsAString& aPath)
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   mPath = aPath;
 }
 
 void
 BlobImplBase::GetMozFullPath(nsAString& aFileName,
                              SystemCallerGuarantee /* unused */,
--- a/dom/file/File.h
+++ b/dom/file/File.h
@@ -220,23 +220,17 @@ public:
                     ErrorResult& aRv);
 
   void GetName(nsAString& aName) const;
 
   int64_t GetLastModified(ErrorResult& aRv);
 
   Date GetLastModifiedDate(ErrorResult& aRv);
 
-  // GetPath and SetPath are currently used only for the webkitRelativePath
-  // attribute and they are only used when this File object is created from a
-  // Directory, generated by a Directory Picker.
-
-  void GetPath(nsAString& aName) const;
-
-  void SetPath(const nsAString& aName);
+  void GetRelativePath(nsAString& aPath) const;
 
   void GetMozFullPath(nsAString& aFilename, SystemCallerGuarantee aGuarantee,
                       ErrorResult& aRv) const;
 
   void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv) const;
 
 protected:
   virtual bool HasFileInterface() const override { return true; }
@@ -255,19 +249,19 @@ class BlobImpl : public nsISupports
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(BLOBIMPL_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
 
   BlobImpl() {}
 
   virtual void GetName(nsAString& aName) const = 0;
 
-  virtual void GetPath(nsAString& aName) const = 0;
+  virtual void GetDOMPath(nsAString& aName) const = 0;
 
-  virtual void SetPath(const nsAString& aName) = 0;
+  virtual void SetDOMPath(const nsAString& aName) = 0;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
 
   virtual void SetLastModified(int64_t aLastModified) = 0;
 
   virtual void GetMozFullPath(nsAString& aName,
                               SystemCallerGuarantee /* unused */,
                               ErrorResult& aRv) const = 0;
@@ -401,19 +395,19 @@ public:
   {
     MOZ_ASSERT(aLength != UINT64_MAX, "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
   virtual void GetName(nsAString& aName) const override;
 
-  virtual void GetPath(nsAString& aName) const override;
+  virtual void GetDOMPath(nsAString& aName) const override;
 
-  virtual void SetPath(const nsAString& aName) override;
+  virtual void SetDOMPath(const nsAString& aName) override;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) override;
 
   virtual void SetLastModified(int64_t aLastModified) override;
 
   virtual void GetMozFullPath(nsAString& aName,
                               SystemCallerGuarantee /* unused */,
                               ErrorResult& aRv) const override;
--- a/dom/file/ipc/Blob.cpp
+++ b/dom/file/ipc/Blob.cpp
@@ -2066,20 +2066,20 @@ public:
   NoteDyingActor();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   void
   GetName(nsAString& aName) const override;
 
   void
-  GetPath(nsAString& aPath) const override;
+  GetDOMPath(nsAString& aPath) const override;
 
   void
-  SetPath(const nsAString& aPath) override;
+  SetDOMPath(const nsAString& aPath) override;
 
   int64_t
   GetLastModified(ErrorResult& aRv) override;
 
   void
   SetLastModified(int64_t aLastModified) override;
 
   void
@@ -2170,27 +2170,27 @@ private:
  * BlobChild::RemoteBlobImpl
  ******************************************************************************/
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
                                BlobImpl* aRemoteBlobImpl,
                                const nsAString& aName,
                                const nsAString& aContentType,
-                               const nsAString& aPath,
+                               const nsAString& aDOMPath,
                                uint64_t aLength,
                                int64_t aModDate,
                                BlobImplIsDirectory aIsDirectory,
                                bool aIsSameProcessBlob)
   : BlobImplBase(aName, aContentType, aLength, aModDate)
   , mWorkerPrivate(nullptr)
   , mMutex("BlobChild::RemoteBlobImpl::mMutex")
   , mIsSlice(false), mIsDirectory(aIsDirectory == eDirectory)
 {
-  SetPath(aPath);
+  SetDOMPath(aDOMPath);
 
   if (aIsSameProcessBlob) {
     MOZ_ASSERT(aRemoteBlobImpl);
     mSameProcessBlobImpl = aRemoteBlobImpl;
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   } else {
     mDifferentProcessBlobImpl = aRemoteBlobImpl;
   }
@@ -2838,26 +2838,26 @@ void
 BlobParent::
 RemoteBlobImpl::GetName(nsAString& aName) const
 {
   mBlobImpl->GetName(aName);
 }
 
 void
 BlobParent::
-RemoteBlobImpl::GetPath(nsAString& aPath) const
+RemoteBlobImpl::GetDOMPath(nsAString& aPath) const
 {
-  mBlobImpl->GetPath(aPath);
+  mBlobImpl->GetDOMPath(aPath);
 }
 
 void
 BlobParent::
-RemoteBlobImpl::SetPath(const nsAString& aPath)
+RemoteBlobImpl::SetDOMPath(const nsAString& aPath)
 {
-  mBlobImpl->SetPath(aPath);
+  mBlobImpl->SetDOMPath(aPath);
 }
 
 int64_t
 BlobParent::
 RemoteBlobImpl::GetLastModified(ErrorResult& aRv)
 {
   return mBlobImpl->GetLastModified(aRv);
 }
@@ -3191,28 +3191,28 @@ BlobChild::CommonInit(BlobChild* aOther,
   uint64_t length = otherImpl->GetSize(rv);
   MOZ_ASSERT(!rv.Failed());
 
   RemoteBlobImpl* remoteBlob = nullptr;
   if (otherImpl->IsFile()) {
     nsAutoString name;
     otherImpl->GetName(name);
 
-    nsAutoString path;
-    otherImpl->GetPath(path);
+    nsAutoString domPath;
+    otherImpl->GetDOMPath(domPath);
 
     int64_t modDate = otherImpl->GetLastModified(rv);
     MOZ_ASSERT(!rv.Failed());
 
     RemoteBlobImpl::BlobImplIsDirectory directory = otherImpl->IsDirectory() ?
       RemoteBlobImpl::BlobImplIsDirectory::eDirectory :
       RemoteBlobImpl::BlobImplIsDirectory::eNotDirectory;
 
     remoteBlob =
-      new RemoteBlobImpl(this, otherImpl, name, contentType, path,
+      new RemoteBlobImpl(this, otherImpl, name, contentType, domPath,
                          length, modDate, directory,
                          false /* SameProcessBlobImpl */);
   } else {
     remoteBlob = new RemoteBlobImpl(this, otherImpl, contentType, length,
                                     false /* SameProcessBlobImpl */);
   }
 
   // This RemoteBlob must be kept alive untill RecvCreatedFromKnownBlob is
@@ -3286,33 +3286,33 @@ BlobChild::CommonInit(const ChildBlobCon
 
       nsString contentType;
       blobImpl->GetType(contentType);
 
       if (blobImpl->IsFile()) {
         nsAutoString name;
         blobImpl->GetName(name);
 
-        nsAutoString path;
-        blobImpl->GetPath(path);
+        nsAutoString domPath;
+        blobImpl->GetDOMPath(domPath);
 
         int64_t lastModifiedDate = blobImpl->GetLastModified(rv);
         MOZ_ASSERT(!rv.Failed());
 
         RemoteBlobImpl::BlobImplIsDirectory directory =
           blobImpl->IsDirectory() ?
             RemoteBlobImpl::BlobImplIsDirectory::eDirectory :
             RemoteBlobImpl::BlobImplIsDirectory::eNotDirectory;
 
         remoteBlob =
           new RemoteBlobImpl(this,
                              blobImpl,
                              name,
                              contentType,
-                             path,
+                             domPath,
                              size,
                              lastModifiedDate,
                              directory,
                              true /* SameProcessBlobImpl */);
       } else {
         remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size,
                                         true /* SameProcessBlobImpl */);
       }
@@ -3485,24 +3485,24 @@ BlobChild::GetOrCreateFromImpl(ChildMana
     ErrorResult rv;
     uint64_t length = aBlobImpl->GetSize(rv);
     MOZ_ASSERT(!rv.Failed());
 
     if (aBlobImpl->IsFile()) {
       nsAutoString name;
       aBlobImpl->GetName(name);
 
-      nsAutoString path;
-      aBlobImpl->GetPath(path);
+      nsAutoString domPath;
+      aBlobImpl->GetDOMPath(domPath);
 
       int64_t modDate = aBlobImpl->GetLastModified(rv);
       MOZ_ASSERT(!rv.Failed());
 
       blobParams =
-        FileBlobConstructorParams(name, contentType, path, length, modDate,
+        FileBlobConstructorParams(name, contentType, domPath, length, modDate,
                                   aBlobImpl->IsDirectory(), blobData);
     } else {
       blobParams = NormalBlobConstructorParams(contentType, length, blobData);
     }
   }
 
   auto* actor = new BlobChild(aManager, aBlobImpl);
 
@@ -4038,24 +4038,24 @@ BlobParent::GetOrCreateFromImpl(ParentMa
       ErrorResult rv;
       uint64_t length = aBlobImpl->GetSize(rv);
       MOZ_ASSERT(!rv.Failed());
 
       if (aBlobImpl->IsFile()) {
         nsAutoString name;
         aBlobImpl->GetName(name);
 
-        nsAutoString path;
-        aBlobImpl->GetPath(path);
+        nsAutoString domPath;
+        aBlobImpl->GetDOMPath(domPath);
 
         int64_t modDate = aBlobImpl->GetLastModified(rv);
         MOZ_ASSERT(!rv.Failed());
 
         blobParams =
-          FileBlobConstructorParams(name, contentType, path, length, modDate,
+          FileBlobConstructorParams(name, contentType, domPath, length, modDate,
                                     aBlobImpl->IsDirectory(), void_t());
       } else {
         blobParams = NormalBlobConstructorParams(contentType, length, void_t());
       }
     }
   }
 
   nsID id;
--- a/dom/file/moz.build
+++ b/dom/file/moz.build
@@ -18,16 +18,17 @@ EXPORTS += [
     'nsHostObjectURI.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'BlobSet.h',
     'File.h',
     'FileList.h',
     'FileReader.h',
+    'MultipartBlobImpl.h',
     'MutableBlobStorage.h',
     'MutableBlobStreamListener.h',
 ]
 
 UNIFIED_SOURCES += [
     'BlobSet.cpp',
     'File.cpp',
     'FileList.cpp',
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -247,17 +247,17 @@ GetDirectoryListingTaskParent::GetSucces
       // This is specific for unix root filesystem.
       if (!mDOMPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
         filePath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
       }
 
       nsAutoString name;
       blobImpl->GetName(name);
       filePath.Append(name);
-      blobImpl->SetPath(filePath);
+      blobImpl->SetDOMPath(filePath);
 
       fileData.blobParent() =
         BlobParent::GetOrCreate(mRequestParent->Manager(), blobImpl);
       inputs.AppendElement(fileData);
     } else {
       MOZ_ASSERT(mTargetData[i].mType == FileOrDirectoryPath::eDirectoryPath);
       FileSystemDirectoryListingResponseDirectory directoryData;
       directoryData.directoryRealPath() = mTargetData[i].mPath;
--- a/dom/filesystem/GetFilesHelper.cpp
+++ b/dom/filesystem/GetFilesHelper.cpp
@@ -272,27 +272,27 @@ GetFilesHelper::RunIO()
   MOZ_ASSERT(!mListingCompleted);
 
   nsCOMPtr<nsIFile> file;
   mErrorResult = NS_NewLocalFile(mDirectoryPath, true, getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
     return;
   }
 
-  nsAutoString path;
-  mErrorResult = file->GetLeafName(path);
+  nsAutoString leafName;
+  mErrorResult = file->GetLeafName(leafName);
   if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
     return;
   }
 
-  if (path.IsEmpty()) {
-    path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
-  }
+  nsAutoString domPath;
+  domPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+  domPath.Append(leafName);
 
-  mErrorResult = ExploreDirectory(path, file);
+  mErrorResult = ExploreDirectory(domPath, file);
 }
 
 void
 GetFilesHelper::RunMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mDirectoryPath.IsEmpty());
   MOZ_ASSERT(!mListingCompleted);
@@ -379,17 +379,17 @@ GetFilesHelperBase::ExploreDirectory(con
     nsAutoString leafName;
     if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
       continue;
     }
     domPath.Append(leafName);
 
     if (isFile) {
       RefPtr<BlobImpl> blobImpl = new BlobImplFile(currFile);
-      blobImpl->SetPath(domPath);
+      blobImpl->SetDOMPath(domPath);
 
       if (!mTargetBlobImplArray.AppendElement(blobImpl, fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       continue;
     }
 
--- a/dom/filesystem/compat/FileSystemFileEntry.cpp
+++ b/dom/filesystem/compat/FileSystemFileEntry.cpp
@@ -2,43 +2,74 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "FileSystemFileEntry.h"
 #include "CallbackRunnables.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/MultipartBlobImpl.h"
 #include "mozilla/dom/FileSystemFileEntryBinding.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 class FileCallbackRunnable final : public Runnable
 {
 public:
-  FileCallbackRunnable(FileCallback* aCallback, File* aFile)
+  FileCallbackRunnable(FileCallback* aCallback, ErrorCallback* aErrorCallback,
+                       File* aFile)
     : mCallback(aCallback)
+    , mErrorCallback(aErrorCallback)
     , mFile(aFile)
   {
     MOZ_ASSERT(aCallback);
     MOZ_ASSERT(aFile);
   }
 
   NS_IMETHOD
   Run() override
   {
-    mCallback->HandleEvent(*mFile);
+    // Here we clone the File object.
+
+    nsAutoString name;
+    mFile->GetName(name);
+
+    nsAutoString type;
+    mFile->GetType(type);
+
+    nsTArray<RefPtr<BlobImpl>> blobImpls;
+    blobImpls.AppendElement(mFile->Impl());
+
+    ErrorResult rv;
+    RefPtr<BlobImpl> blobImpl =
+      MultipartBlobImpl::Create(Move(blobImpls), name, type, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      if (mErrorCallback) {
+        RefPtr<DOMException> exception =
+          DOMException::Create(rv.StealNSResult());
+        mErrorCallback->HandleEvent(*exception);
+      }
+
+      return NS_OK;
+    }
+
+    RefPtr<File> file = File::Create(mFile->GetParentObject(), blobImpl);
+    MOZ_ASSERT(file);
+
+    mCallback->HandleEvent(*file);
     return NS_OK;
   }
 
 private:
   RefPtr<FileCallback> mCallback;
+  RefPtr<ErrorCallback> mErrorCallback;
   RefPtr<File> mFile;
 };
 
 } // anonymous namespace
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemFileEntry, FileSystemEntry, mFile)
 
 NS_IMPL_ADDREF_INHERITED(FileSystemFileEntry, FileSystemEntry)
@@ -72,17 +103,17 @@ void
 FileSystemFileEntry::GetName(nsAString& aName, ErrorResult& aRv) const
 {
   mFile->GetName(aName);
 }
 
 void
 FileSystemFileEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
 {
-  mFile->GetPath(aPath);
+  mFile->Impl()->GetDOMPath(aPath);
   if (aPath.IsEmpty()) {
     // We're under the root directory. webkitRelativePath
     // (implemented as GetPath) is for cases when file is selected because its
     // ancestor directory is selected. But that is not the case here, so need to
     // manually prepend '/'.
     nsAutoString name;
     mFile->GetName(name);
     aPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
@@ -90,15 +121,18 @@ FileSystemFileEntry::GetFullPath(nsAStri
   }
 }
 
 void
 FileSystemFileEntry::GetFile(FileCallback& aSuccessCallback,
                              const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const
 {
   RefPtr<FileCallbackRunnable> runnable =
-    new FileCallbackRunnable(&aSuccessCallback, mFile);
+    new FileCallbackRunnable(&aSuccessCallback,
+                             aErrorCallback.WasPassed()
+                               ? &aErrorCallback.Value() : nullptr,
+                             mFile);
   DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
   NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/filesystem/compat/tests/test_basic.html
+++ b/dom/filesystem/compat/tests/test_basic.html
@@ -403,16 +403,35 @@ function test_getParent(entry, parentEnt
     } else {
       test_getParent(e, parentEntry, false);
     }
   }, function(e) {
     ok(false, "This should not happen.");
   });
 }
 
+function test_webkitRelativePath() {
+  fileEntry.file(function(file1) {
+    ok(file1, "We have a file here!");
+    ok(!file1.webkitRelativePath, "webkitRelativePath is an empty string");
+
+    fileEntry.file(function(file2) {
+      ok(file2, "We have a file here!");
+      ok(!file2.webkitRelativePath, "webkitRelativePath is an empty string");
+      isnot(file1, file2, "The 2 files are not the same");
+
+      next();
+    }, function() {
+      ok(false, "Something when wrong!");
+    });
+  }, function() {
+    ok(false, "Something when wrong!");
+  });
+}
+
 var tests = [
   setup_tests,
   populate_entries,
 
   test_entries,
 
   test_fileEntry,
   test_fileEntry_file,
@@ -447,16 +466,18 @@ var tests = [
 
   test_root_getDirectory_securityError,
   test_root_getDirectory_typeMismatchError,
   test_root_getDirectory_nonValidPath,
   test_root_getDirectory_nonExistingPath,
   test_root_getDirectory_simple,
   test_root_getDirectory_deep,
 
+  test_webkitRelativePath,
+
   cleanUpTestingFiles,
 ];
 
 function next() {
   if (!tests.length) {
     SimpleTest.finish();
     return;
   }
--- a/dom/filesystem/tests/filesystem_commons.js
+++ b/dom/filesystem/tests/filesystem_commons.js
@@ -1,12 +1,18 @@
 function createPath(parentDir, dirOrFile) {
   return parentDir.path + (parentDir.path == '/' ? '' : '/') + dirOrFile.name;
 }
 
+function createRelativePath(parentDir, dirOrFile) {
+  let path = createPath(parentDir, dirOrFile);
+  is(path[0], "/", "The full path should start with '/'");
+  return path.substring(1);
+}
+
 function setup_tests(aNext) {
   SimpleTest.requestLongerTimeout(2);
   SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
                                      ["dom.webkitBlink.dirPicker.enabled", true]]}, aNext);
 }
 
 function test_basic(aDirectory, aNext) {
   ok(aDirectory, "Directory exists.");
@@ -24,17 +30,17 @@ function test_getFilesAndDirectories(aDi
           if (data[i] instanceof Directory) {
             isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
             isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
             isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
             is(data[i].path, createPath(dir, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
           }
 
           if (data[i] instanceof File) {
-            is(data[i].webkitRelativePath, createPath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath);
+            is(data[i].webkitRelativePath, createRelativePath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath);
           }
         }
       }
     );
   }
 
   aDirectory.getFilesAndDirectories().then(
     function(data) {
@@ -46,34 +52,35 @@ function test_getFilesAndDirectories(aDi
           isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
           is(data[i].path, createPath(aDirectory, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
           if (aRecursive) {
             promises.push(checkSubDir(data[i]));
           }
         }
 
         if (data[i] instanceof File) {
-          is(data[i].webkitRelativePath, createPath(aDirectory, data[i]), "File.webkitRelativePath should be called '/' + file.name: " + data[i].webkitRelativePath);
+          is(data[i].webkitRelativePath, createRelativePath(aDirectory, data[i]), "File.webkitRelativePath should be called file.name: " + data[i].webkitRelativePath);
         }
       }
 
       return Promise.all(promises);
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
 }
 
 function test_getFiles(aDirectory, aRecursive, aNext) {
   aDirectory.getFiles(aRecursive).then(
     function(data) {
       for (var i = 0; i < data.length; ++i) {
         ok(data[i] instanceof File, "File: " + data[i].name);
-        ok(data[i].webkitRelativePath.indexOf(aDirectory.path) == 0 &&
+        is(aDirectory.path[0], '/', "Directory path must start with '/'");
+        ok(data[i].webkitRelativePath.indexOf(aDirectory.path.substring(1)) == 0 &&
            data[i].webkitRelativePath.indexOf('/' + data[i].name) + ('/' + data[i].name).length == data[i].webkitRelativePath.length,
            "File.webkitRelativePath should be called dir.path + '/' + file.name: " + data[i].webkitRelativePath);
       }
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
--- a/dom/html/HTMLFormSubmission.cpp
+++ b/dom/html/HTMLFormSubmission.cpp
@@ -506,21 +506,21 @@ FSMultipartFormData::AddNameBlobOrNullPa
   nsAutoCString contentType;
   nsCOMPtr<nsIInputStream> fileStream;
 
   if (aBlob) {
     nsAutoString filename16;
 
     RefPtr<File> file = aBlob->ToFile();
     if (file) {
-      nsAutoString path;
-      file->GetPath(path);
+      nsAutoString relativePath;
+      file->GetRelativePath(relativePath);
       if (Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr) &&
-          !path.IsEmpty()) {
-        filename16 = path;
+          !relativePath.IsEmpty()) {
+        filename16 = relativePath;
       }
 
       if (filename16.IsEmpty()) {
         RetrieveFileName(aBlob, filename16);
       }
     }
 
     rv = EncodeVal(filename16, filename, true);
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -55,25 +55,25 @@ private:
   // BlobImpl
   virtual void
   GetName(nsAString& aName) const override
   {
     mBlobImpl->GetName(aName);
   }
 
   virtual void
-  GetPath(nsAString& aPath) const override
+  GetDOMPath(nsAString& aPath) const override
   {
-    mBlobImpl->GetPath(aPath);
+    mBlobImpl->GetDOMPath(aPath);
   }
 
   virtual void
-  SetPath(const nsAString& aPath) override
+  SetDOMPath(const nsAString& aPath) override
   {
-    mBlobImpl->SetPath(aPath);
+    mBlobImpl->SetDOMPath(aPath);
   }
 
   virtual int64_t
   GetLastModified(ErrorResult& aRv) override
   {
     return mBlobImpl->GetLastModified(aRv);
   }
 
--- a/dom/security/test/contentverifier/browser.ini
+++ b/dom/security/test/contentverifier/browser.ini
@@ -11,11 +11,9 @@ support-files =
   file_about_newtab_sri.html
   file_about_newtab_sri_signature
   goodChain.pem
   head.js
   script.js
   style.css
 
 [browser_verify_content_about_newtab.js]
-skip-if = true # This started permafailing randomly (Bug 1336654)
 [browser_verify_content_about_newtab2.js]
-skip-if = true # This started permafailing randomly (Bug 1336654)
--- a/dom/security/test/contentverifier/file_about_newtab_good_signature
+++ b/dom/security/test/contentverifier/file_about_newtab_good_signature
@@ -1,1 +1,1 @@
--mqpvTYdZX4HYQDW1nScojL7ICw5yj8UF2gzxyLbSCx9UIfHH-gWZ40F_PFtqjHxoC1J3dHDb3VedVhOYczdaLrNKbRvPrlnkdGx7Rl8qEBrtZpF1py1Z9uAGoCrgUHa
\ No newline at end of file
+HUndgHvxHNMiAe1SXoeyOOraUJCdxHqWkAYTu0Cq1KpAHcWZEVelNTvyXGbTLWj8btsmqNLAm08UlyK43q_2oO9DQfez3Fo8DhsKvm7TqgSXCkhUoxsYNanxWXhqw-Jw
\ No newline at end of file
--- a/dom/security/test/contentverifier/goodChain.pem
+++ b/dom/security/test/contentverifier/goodChain.pem
@@ -1,51 +1,51 @@
 -----BEGIN CERTIFICATE-----
-MIICUzCCAT2gAwIBAgIUNy0IWlDRDL53zwvj1lq0GCpIe2EwCwYJKoZIhvcNAQEL
-MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE0MTEyNzAwMDAwMFoYDzIwMTcwMjA0
+MIICUzCCAT2gAwIBAgIUJ1BtYqWRwUsVaZCGPp9eTHIC04QwCwYJKoZIhvcNAQEL
+MBExDzANBgNVBAMMBmludC1DQTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
 MDAwMDAwWjAUMRIwEAYDVQQDDAllZS1pbnQtQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
 IgNiAAShaHJDNitcexiJ83kVRhWhxz+0je6GPgIpFdtgjiUt5LcTLajOmOgxU05q
 nAwLCcjWOa3oMgbluoE0c6EfozDgXajJbkOD/ieHPalxA74oiM/wAvBa9xof3cyD
 dKpuqc6jTjBMMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDUGA1UdEQQuMCyCKnJlbW90
 ZW5ld3RhYi5jb250ZW50LXNpZ25hdHVyZS5tb3ppbGxhLm9yZzALBgkqhkiG9w0B
-AQsDggEBAIeB4WKghknsrow+lj3qzDiHrPBc9AMlb4aZvS6yzazmXr80rXxnsKkb
-ZV1PW/cU6xXH5srWHpfJwypvvYS74btNtuacjKVH2AJdua4482WQIi9gCkXIufRx
-2nSS6pYgYZ4vD+yG8v+3SCChOCXnLjRaN9WxMi8tldbOW9pH44O3vrSSL70pQ2Ph
-8ncUbUbCNNtYhtOe2Z4XT9Cswmfkf4OIQ3gy9eYK2ySEUWP+lHs9KnnNXrLcA/ae
-cSUdI00i3C3OS9yldeyNHzVb8mSsZ5d1WkJrkf/hnXWGrMHRTtlJlG7t7cN8S0Oi
-tQoinJyxrZ+zabFIyl/euDc+Y/dijOU=
+AQsDggEBALiLck6k50ok9ahVq45P3feY1PeUXcIYZkJd8aPDYM+0kfg5+JyJBykA
+mtHWPE1QQjs7VRMfaLfu04E4UJMI2V1AON1qtgR9BQLctW85KFACg2omfiCKwJh0
+5Q8cxBFx9BpNMayqLJwHttB6oluxZFTB8CL/hfpbYpHz1bMEDCVSRP588YBrc8mV
+OLqzQK+k3ewwGvfD6SvXmTny37MxqwxdTPFJNnpqzKAsQIvz8Skic9BkA1NFk0Oq
+lsKKoiibbOCmwS9XY/laAkBaC3winuhciYAC0ImAopZ4PBCU0AOHGrNbhZXWYQxt
+uHBj34FqvIRCqgM06JCEwN0ULgix4kI=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIIC0TCCAbugAwIBAgIULYyr3v/0zZ+XiR22NH7hOcnj2FcwCwYJKoZIhvcNAQEL
-MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
+MIIC0TCCAbugAwIBAgIUPcKbBQpKwTzrrlqzM+d3z5DWiNUwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
 MDBaMBExDzANBgNVBAMMBmludC1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
 AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
 nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
 wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
 4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
 yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
 j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMlMCMwDAYDVR0TBAUwAwEB/zAT
-BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADfRBKSM08JF6vqz
-0EA+KNc0XIEAWApuHuwX6XXWeLgo6QN4E/9qfrsaO+C366WT+JDsjDOi40wW46SA
-XbguxtZQeZasNDUWp/leZix4RSJoHB7OllG1rgZJfN76zKVaXRGUmyQObkMMOJZe
-wIA0OBURT8ik9Z89pD0IWrqscds71Edfjt0hHgg63wVvIaklReZXvFOD3VmSCPNn
-2wB6ZzECcbhJpnzxZdsoMSGH0C6apYnNNTjqZjO90JVm/Ph/7nbi/KncYXA6ccl6
-Jz2mfiAquWIua2+CzBGbqjZVSATTpWCp+cXQJE1xka+hWUaL5HPTq1bTULRFlauZ
-HGl5lJk=
+BgNVHSUEDDAKBggrBgEFBQcDAzALBgkqhkiG9w0BAQsDggEBADDPjITgz8joxLRW
+wpLxELKSgO/KQ6iAXztjMHq9ovT7Fy0fqBnQ1mMVFr+sBXLgtUCM45aip6PjhUXc
+zs5Dq5STg+kz7qtmAjEQvOPcyictbgdu/K7+uMhXQhlzhOgyW88Uk5vrAezNTc/e
+TvSmWp1FcgVAfaeMN/90nzD1KIHoUt7zqZIz9ub8jXPVzQNZq4vh33smZhmbdTdV
+DaHUyef5cR1VTEGB+L1qzUIQqpHmD4UkMNP1nYedWfauiQhRt6Ql3rJSCRuEvsOA
+iBTJlwai/EFwfyfHkOV2GNgv+A5wHHEjBtF5c4PCxQEL5Vw+mfZHLsDVqF3279ZY
+lQ6jQ9g=
 -----END CERTIFICATE-----
 -----BEGIN CERTIFICATE-----
-MIICzTCCAbegAwIBAgIUIVkGGA8HiO3RIKGjdOjVi+d6EVkwCwYJKoZIhvcNAQEL
-MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
+MIICzTCCAbegAwIBAgIUKRLJoCmk0A6PHrNc8CxFn//4BYcwCwYJKoZIhvcNAQEL
+MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
 MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
 AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
 Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
 7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
 qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
 HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
 uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoyUwIzAMBgNVHRMEBTADAQH/MBMGA1Ud
-JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAlpbRzRIPnf43AwGfMvKP
-zOtntRy2nE9GlmY9I00uioHUnUrPLs8aw3UDtyiDWMGqcYysXGx9EX2Vk0POS4gf
-G6PA95F6GxTtbzIEZmTPVuzA/cfc9HU3HXDPqh+dySJ8/Ta4c4vX1lgeGGAvstNe
-q+9DaCGXs8MqMF8KtXNmOm3eS9q622hKEvTVEoxqj1t365kwKHaNpbObddQ6Xcny
-akvfh2L+8QbJSflcm8fL/JTup/2/cRG1ytOsaiXEr9JBEITOtQO0Ot/4Qzq+MJjv
-weaJ3hZ0c+cTy3tEvt+I7+lnW4Q5dB7aLR2/BZfLubhxz1SUVMuHfLH64fc0Uf1Q
-Nw==
+JQQMMAoGCCsGAQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAABgMK6EyVIXTjD5qaxPO
+DWz6yREACmAQBcowKWvfhwgi27DPSXyFGDbzTPEo+7RrIcXJkVAhLouGT51fCwTZ
+zb6Sgf6ztX7VSppY9AT4utvlZKP1xQ5WhIYsMtdHCHLHIkRjeWyoBEfUx50UXNLK
+Snl+A02GKYWiX+TLLg2DPN2s7v/mm8NLMQNgUlL7KakB2FHFyPa8otPpL4llg7UJ
+iBTVQ0c3JoiVbwZaY1Z8QinfMXUrTK9egUC4BAcId1dE8glzA5RRlw1fTLWpGApt
+hUmbDnl9N2a9NhGX323ypNzIATexafipzWe7bc4u/+bFdrUqnKUoEka73pZBdHdA
+FQ==
 -----END CERTIFICATE-----
--- a/dom/security/test/contentverifier/head.js
+++ b/dom/security/test/contentverifier/head.js
@@ -78,17 +78,17 @@ function* doTest(aExpectedStrings, reloa
     aboutNewTabService.newTabURL = aNewTabPref;
   }
 
   // set prefs
   yield pushPrefs(
       ["browser.newtabpage.remote.content-signing-test", true],
       ["browser.newtabpage.remote", true],
       ["security.content.signature.root_hash",
-       "65:AE:D8:1E:B5:12:AE:B0:6B:38:58:BC:7C:47:35:3D:D4:EA:25:F1:63:DA:08:BB:86:3A:2E:97:39:66:8F:55"]);
+       "CC:BE:04:87:74:B2:98:24:4A:C6:7A:71:BC:6F:DB:D6:C0:48:17:29:57:51:96:47:38:CC:24:C8:E4:F9:DD:CB"]);
 
   if (aNewTabPref === URI_BAD_CSP) {
     // Use stricter CSP to test CSP violation.
     yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self'; style-src 'self'"]);
   } else {
     // Use weaker CSP to test normal content.
     yield pushPrefs(["security.signed_content.CSP.default", "script-src 'self' 'unsafe-inline'; style-src 'self'"]);
   }
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -28,17 +28,17 @@ dictionary ChromeFilePropertyBag : FileP
   DOMString name = "";
 };
 
 // Mozilla extensions
 partial interface File {
   [GetterThrows, Deprecated="FileLastModifiedDate"]
   readonly attribute Date lastModifiedDate;
 
-  [BinaryName="path", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
+  [BinaryName="relativePath", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
   readonly attribute USVString webkitRelativePath;
 
   [GetterThrows, ChromeOnly, NeedsCallerType]
   readonly attribute DOMString mozFullPath;
 
   [ChromeOnly, Throws, NeedsCallerType]
   static File createFromNsIFile(nsIFile file,
                                 optional ChromeFilePropertyBag options);
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -44,17 +44,17 @@ ServiceWorkerContainer::IsEnabled(JSCont
 
   JS::Rooted<JSObject*> global(aCx, aGlobal);
   nsCOMPtr<nsPIDOMWindowInner> window = Navigator::GetWindowFromGlobal(global);
   if (!window) {
     return false;
   }
 
   nsIDocument* doc = window->GetExtantDoc();
-  if (!doc || doc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
+  if (!doc || nsContentUtils::IsInPrivateBrowsing(doc)) {
     return false;
   }
 
   return Preferences::GetBool("dom.serviceWorkers.enabled", false);
 }
 
 ServiceWorkerContainer::ServiceWorkerContainer(nsPIDOMWindowInner* aWindow)
   : DOMEventTargetHelper(aWindow)
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -1649,20 +1649,21 @@ ServiceWorkerManager::FlushReportsToAllC
       continue;
     }
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(iter.Key());
     if (!doc || !doc->IsCurrentActiveDocument() || !doc->GetWindow()) {
       continue;
     }
 
-    windows.AppendElement(doc->InnerWindowID());
-
-    aReporter->FlushConsoleReports(doc,
-                                   nsIConsoleReportCollector::ReportAction::Save);
+    uint64_t innerWindowId = doc->InnerWindowID();
+    windows.AppendElement(innerWindowId);
+
+    aReporter->FlushReportsToConsole(
+      innerWindowId, nsIConsoleReportCollector::ReportAction::Save);
   }
 
   // Report to any documents that have called .register() for this scope.  They
   // may not be controlled, but will still want to see error reports.
   WeakDocumentList* regList = mRegisteringDocuments.Get(aScope);
   if (regList) {
     for (int32_t i = regList->Length() - 1; i >= 0; --i) {
       nsCOMPtr<nsIDocument> doc = do_QueryReferent(regList->ElementAt(i));
@@ -1677,18 +1678,18 @@ ServiceWorkerManager::FlushReportsToAllC
 
       uint64_t innerWindowId = doc->InnerWindowID();
       if (windows.Contains(innerWindowId)) {
         continue;
       }
 
       windows.AppendElement(innerWindowId);
 
-      aReporter->FlushConsoleReports(doc,
-                                     nsIConsoleReportCollector::ReportAction::Save);
+      aReporter->FlushReportsToConsole(
+        innerWindowId, nsIConsoleReportCollector::ReportAction::Save);
     }
 
     if (regList->IsEmpty()) {
       regList = nullptr;
       nsAutoPtr<WeakDocumentList> doomed;
       mRegisteringDocuments.RemoveAndForget(aScope, doomed);
     }
   }
@@ -1707,25 +1708,25 @@ ServiceWorkerManager::FlushReportsToAllC
 
       uint64_t innerWindowId = nsContentUtils::GetInnerWindowID(inner);
       if (innerWindowId == 0 || windows.Contains(innerWindowId)) {
         continue;
       }
 
       windows.AppendElement(innerWindowId);
 
-      aReporter->FlushReportsByWindowId(innerWindowId,
-                                        nsIConsoleReportCollector::ReportAction::Save);
+      aReporter->FlushReportsToConsole(
+        innerWindowId, nsIConsoleReportCollector::ReportAction::Save);
     }
   }
 
   // If there are no documents to report to, at least report something to the
   // browser console.
   if (windows.IsEmpty()) {
-    aReporter->FlushConsoleReports((nsIDocument*)nullptr);
+    aReporter->FlushReportsToConsole(0);
     return;
   }
 
   aReporter->ClearConsoleReports();
 }
 
 void
 ServiceWorkerManager::HandleError(JSContext* aCx,
@@ -2555,17 +2556,17 @@ ServiceWorkerManager::IsAvailable(nsIPri
   return registration && registration->GetActive();
 }
 
 bool
 ServiceWorkerManager::IsControlled(nsIDocument* aDoc, ErrorResult& aRv)
 {
   MOZ_ASSERT(aDoc);
 
-  if (aDoc->NodePrincipal()->OriginAttributesRef().mPrivateBrowsingId) {
+  if (nsContentUtils::IsInPrivateBrowsing(aDoc)) {
     // Handle the case where a service worker was previously registered in
     // a non-private window (bug 1255621).
     return false;
   }
 
   RefPtr<ServiceWorkerRegistrationInfo> registration;
   nsresult rv = GetDocumentRegistration(aDoc, getter_AddRefs(registration));
   if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE)) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -3730,25 +3730,26 @@ WorkerPrivateParent<Derived>::FlushRepor
   }
 
   bool reportErrorToBrowserConsole = true;
 
   // Flush the reports.
   for (uint32_t index = 0; index < windowActions.Length(); index++) {
     WindowAction& windowAction = windowActions[index];
 
-    aReporter->FlushConsoleReports(windowAction.mWindow->GetExtantDoc(),
-                                   nsIConsoleReportCollector::ReportAction::Save);
+    aReporter->FlushReportsToConsole(
+      windowAction.mWindow->WindowID(),
+      nsIConsoleReportCollector::ReportAction::Save);
     reportErrorToBrowserConsole = false;
   }
 
   // Finally report to broswer console if there is no any window or shared
   // worker.
   if (reportErrorToBrowserConsole) {
-    aReporter->FlushConsoleReports((nsIDocument*)nullptr);
+    aReporter->FlushReportsToConsole(0);
     return;
   }
 
   aReporter->ClearConsoleReports();
 }
 
 template <class Derived>
 NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
new file mode 100644
--- /dev/null
+++ b/embedding/moz.build
@@ -0,0 +1,3 @@
+with Files("**"):
+    BUG_COMPONENT = ("Core", "General")
+
--- a/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp
+++ b/gfx/skia/skia/src/ports/SkScalerContext_win_dw.cpp
@@ -677,20 +677,23 @@ static void bilevel_to_bw(const uint8_t*
 template<bool APPLY_PREBLEND>
 static void rgb_to_a8(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph, const uint8_t* table8) {
     const size_t dstRB = glyph.rowBytes();
     const U16CPU width = glyph.fWidth;
     uint8_t* SK_RESTRICT dst = static_cast<uint8_t*>(glyph.fImage);
 
     for (U16CPU y = 0; y < glyph.fHeight; y++) {
         for (U16CPU i = 0; i < width; i++) {
-            U8CPU r = *(src++);
-            U8CPU g = *(src++);
-            U8CPU b = *(src++);
-            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>((r + g + b) / 3, table8);
+            U8CPU g = src[1];
+            src += 3;
+
+            // Ignore the R, B channels. It looks the closest to what
+            // D2D with grayscale AA has. But there's no way
+            // to just get a grayscale AA alpha texture from a glyph run.
+            dst[i] = sk_apply_lut_if<APPLY_PREBLEND>(g, table8);
         }
         dst = (uint8_t*)((char*)dst + dstRB);
     }
 }
 
 template<bool APPLY_PREBLEND, bool RGB>
 static void rgb_to_lcd16(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
                          const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2068,25 +2068,25 @@ gfxFont::Draw(const gfxTextRun *aTextRun
         if (aTextRun->UseCenterBaseline()) {
             gfxPoint baseAdj(0, (metrics.emAscent - metrics.emDescent) / 2);
             mat.Translate(baseAdj);
         }
 
         aRunParams.context->SetMatrix(mat);
     }
 
-    UniquePtr<SVGContextPaint> contextPaint;
+    RefPtr<SVGContextPaint> contextPaint;
     if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) {
         // If no pattern is specified for fill, use the current pattern
         NS_ASSERTION((int(aRunParams.drawMode) & int(DrawMode::GLYPH_STROKE)) == 0,
                      "no pattern supplied for stroking text");
         RefPtr<gfxPattern> fillPattern = aRunParams.context->GetPattern();
-        contextPaint.reset(
+        contextPaint =
             new SimpleTextContextPaint(fillPattern, nullptr,
-                                       aRunParams.context->CurrentMatrix()));
+                                       aRunParams.context->CurrentMatrix());
         fontParams.contextPaint = contextPaint.get();
     }
 
     // Synthetic-bold strikes are each offset one device pixel in run direction.
     // (these values are only needed if IsSyntheticBold() is true)
     if (IsSyntheticBold()) {
         double xscale = CalcXScale(aRunParams.context->GetDrawTarget());
         fontParams.synBoldOnePixelOffset = aRunParams.direction * xscale;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/Cargo.toml
@@ -0,0 +1,44 @@
+[package]
+name = "webrender"
+version = "0.11.1"
+authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
+license = "MPL-2.0"
+repository = "https://github.com/servo/webrender"
+build = "build.rs"
+workspace = ".."
+
+[features]
+default = ["codegen", "freetype-lib"]
+codegen = ["webrender_traits/codegen"]
+freetype-lib = ["freetype/servo-freetype-sys"]
+serde_derive = ["webrender_traits/serde_derive"]
+
+[dependencies]
+app_units = "0.3"
+bincode = "0.6"
+bit-set = "0.4"
+byteorder = "0.5"
+euclid = "0.10.3"
+fnv="1.0"
+gleam = "0.2.30"
+lazy_static = "0.2"
+log = "0.3"
+num-traits = "0.1.32"
+offscreen_gl_context = {version = "0.5", features = ["serde_serialization", "osmesa"]}
+time = "0.1"
+threadpool = "1.3.2"
+webrender_traits = {path = "../webrender_traits", default-features = false}
+bitflags = "0.7"
+
+[dev-dependencies]
+angle = {git = "https://github.com/servo/angle", branch = "servo"}
+
+[target.'cfg(any(target_os = "android", all(unix, not(target_os = "macos"))))'.dependencies]
+freetype = { version = "0.2", default-features = false }
+
+[target.'cfg(target_os = "windows")'.dependencies]
+dwrote = "0.1.5"
+
+[target.'cfg(target_os = "macos")'.dependencies]
+core-graphics = "0.5.0"
+core-text = "2.0"
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/build.rs
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::env;
+use std::path::{Path, PathBuf};
+use std::io::prelude::*;
+use std::fs::{canonicalize, read_dir, File};
+
+fn write_shaders(glsl_files: Vec<PathBuf>, shader_file_path: &Path) {
+    let mut shader_file = File::create(shader_file_path).unwrap();
+
+    write!(shader_file, "/// AUTO GENERATED BY build.rs\n\n").unwrap();
+    write!(shader_file, "use std::collections::HashMap;\n").unwrap();
+    write!(shader_file, "lazy_static! {{\n").unwrap();
+    write!(shader_file, "  pub static ref SHADERS: HashMap<&'static str, &'static str> = {{\n").unwrap();
+    write!(shader_file, "    let mut h = HashMap::with_capacity({});\n", glsl_files.len()).unwrap();
+    for glsl in glsl_files {
+        let shader_name = glsl.file_name().unwrap().to_str().unwrap();
+        // strip .glsl
+        let shader_name = shader_name.replace(".glsl", "");
+        let full_path = canonicalize(&glsl).unwrap();
+        let full_name = full_path.as_os_str().to_str().unwrap();
+        // if someone is building on a network share, I'm sorry.
+        let full_name = full_name.replace("\\\\?\\", "");
+        let full_name = full_name.replace("\\", "/");
+        write!(shader_file, "    h.insert(\"{}\", include_str!(\"{}\"));\n",
+               shader_name, full_name).unwrap();
+    }
+    write!(shader_file, "    h\n").unwrap(); 
+    write!(shader_file, "  }};\n").unwrap(); 
+    write!(shader_file, "}}\n").unwrap(); 
+}
+
+fn main() {
+    let out_dir = env::var("OUT_DIR").unwrap_or("out".to_owned());
+
+    let shaders_file = Path::new(&out_dir).join("shaders.rs");
+    let mut glsl_files = vec![];
+
+    println!("cargo:rerun-if-changed=res");
+    let res_dir = Path::new("res");
+    for entry in read_dir(res_dir).unwrap() {
+        let entry = entry.unwrap();
+        let path = entry.path();
+
+        if entry.file_name().to_str().unwrap().ends_with(".glsl") {
+            println!("cargo:rerun-if-changed={}", path.display());
+            glsl_files.push(path.to_owned());
+        }
+    }
+
+    write_shaders(glsl_files, &shaders_file);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/clip_shared.glsl
@@ -0,0 +1,91 @@
+#line 1
+/* 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/. */
+
+#ifdef WR_VERTEX_SHADER
+
+#define SEGMENT_ALL         0
+#define SEGMENT_CORNER_TL   1
+#define SEGMENT_CORNER_TR   2
+#define SEGMENT_CORNER_BL   3
+#define SEGMENT_CORNER_BR   4
+
+in int aClipRenderTaskIndex;
+in int aClipLayerIndex;
+in int aClipDataIndex;
+in int aClipSegmentIndex;
+
+struct CacheClipInstance {
+    int render_task_index;
+    int layer_index;
+    int data_index;
+    int segment_index;
+};
+
+CacheClipInstance fetch_clip_item(int index) {
+    CacheClipInstance cci;
+
+    cci.render_task_index = aClipRenderTaskIndex;
+    cci.layer_index = aClipLayerIndex;
+    cci.data_index = aClipDataIndex;
+    cci.segment_index = aClipSegmentIndex;
+
+    return cci;
+}
+
+// The transformed vertex function that always covers the whole clip area,
+// which is the intersection of all clip instances of a given primitive
+TransformVertexInfo write_clip_tile_vertex(vec4 local_clip_rect,
+                                           Layer layer,
+                                           ClipArea area,
+                                           int segment_index) {
+    vec2 lp0_base = local_clip_rect.xy;
+    vec2 lp1_base = local_clip_rect.xy + local_clip_rect.zw;
+
+    vec2 lp0 = clamp_rect(lp0_base, layer.local_clip_rect);
+    vec2 lp1 = clamp_rect(lp1_base, layer.local_clip_rect);
+    vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
+
+    vec2 outer_p0 = area.screen_origin_target_index.xy;
+    vec2 outer_p1 = outer_p0 + area.task_bounds.zw - area.task_bounds.xy;
+    vec2 inner_p0 = area.inner_rect.xy;
+    vec2 inner_p1 = area.inner_rect.zw;
+
+    vec2 p0, p1;
+    switch (segment_index) {
+        case SEGMENT_ALL:
+            p0 = outer_p0;
+            p1 = outer_p1;
+            break;
+        case SEGMENT_CORNER_TL:
+            p0 = outer_p0;
+            p1 = inner_p0;
+            break;
+        case SEGMENT_CORNER_BL:
+            p0 = vec2(outer_p0.x, outer_p1.y);
+            p1 = vec2(inner_p0.x, inner_p1.y);
+            break;
+        case SEGMENT_CORNER_TR:
+            p0 = vec2(outer_p1.x, outer_p1.y);
+            p1 = vec2(inner_p1.x, inner_p1.y);
+            break;
+        case SEGMENT_CORNER_BR:
+            p0 = vec2(outer_p1.x, outer_p0.y);
+            p1 = vec2(inner_p1.x, inner_p0.y);
+            break;
+    }
+
+    vec2 actual_pos = mix(p0, p1, aPosition.xy);
+
+    vec4 layer_pos = get_layer_pos(actual_pos / uDevicePixelRatio, layer);
+
+    // compute the point position in side the layer, in CSS space
+    vec2 vertex_pos = actual_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
+
+    gl_Position = uTransform * vec4(vertex_pos, 0.0, 1);
+
+    return TransformVertexInfo(layer_pos.xyw, actual_pos, clipped_local_rect);
+}
+
+#endif //WR_VERTEX_SHADER
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.fs.glsl
@@ -0,0 +1,40 @@
+#line 1
+/* 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/. */
+
+// TODO(gw): Write a fast path blur that handles smaller blur radii
+//           with a offset / weight uniform table and a constant
+//           loop iteration count!
+
+// TODO(gw): Make use of the bilinear sampling trick to reduce
+//           the number of texture fetches needed for a gaussian blur.
+
+float gauss(float x, float sigma) {
+    return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma));
+}
+
+void main(void) {
+    vec4 cache_sample = texture(sCache, vUv);
+    vec4 color = vec4(cache_sample.rgb, 1.0) * (cache_sample.a * gauss(0.0, vSigma));
+
+    for (int i=1 ; i < vBlurRadius ; ++i) {
+        vec2 offset = vec2(float(i)) * vOffsetScale;
+
+        vec2 st0 = clamp(vUv.xy + offset, vUvRect.xy, vUvRect.zw);
+        vec4 color0 = texture(sCache, vec3(st0, vUv.z));
+
+        vec2 st1 = clamp(vUv.xy - offset, vUvRect.xy, vUvRect.zw);
+        vec4 color1 = texture(sCache, vec3(st1, vUv.z));
+
+        // Alpha must be premultiplied in order to properly blur the alpha channel.
+        float weight = gauss(float(i), vSigma);
+        color += vec4(color0.rgb * color0.a, color0.a) * weight;
+        color += vec4(color1.rgb * color1.a, color1.a) * weight;
+    }
+
+    // Unpremultiply the alpha.
+    color.rgb /= color.a;
+
+    oFragColor = color;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.glsl
@@ -0,0 +1,10 @@
+#line 1
+/* 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/. */
+
+varying vec3 vUv;
+flat varying vec4 vUvRect;
+flat varying vec2 vOffsetScale;
+flat varying float vSigma;
+flat varying int vBlurRadius;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_blur.vs.glsl
@@ -0,0 +1,65 @@
+#line 1
+/* 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/. */
+
+// Applies a separable gaussian blur in one direction, as specified
+// by the dir field in the blur command.
+
+#define DIR_HORIZONTAL  0
+#define DIR_VERTICAL    1
+
+in int aBlurRenderTaskIndex;
+in int aBlurSourceTaskIndex;
+in int aBlurDirection;
+
+struct BlurCommand {
+    int task_id;
+    int src_task_id;
+    int dir;
+};
+
+BlurCommand fetch_blur() {
+    BlurCommand blur;
+
+    blur.task_id = aBlurRenderTaskIndex;
+    blur.src_task_id = aBlurSourceTaskIndex;
+    blur.dir = aBlurDirection;
+
+    return blur;
+}
+
+void main(void) {
+    BlurCommand cmd = fetch_blur();
+    RenderTaskData task = fetch_render_task(cmd.task_id);
+    RenderTaskData src_task = fetch_render_task(cmd.src_task_id);
+
+    vec4 local_rect = task.data0;
+
+    vec2 pos = mix(local_rect.xy,
+                   local_rect.xy + local_rect.zw,
+                   aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vUv.z = src_task.data1.x;
+    vBlurRadius = int(task.data1.y);
+    vSigma = task.data1.y * 0.5;
+
+    switch (cmd.dir) {
+        case DIR_HORIZONTAL:
+            vOffsetScale = vec2(1.0 / texture_size.x, 0.0);
+            break;
+        case DIR_VERTICAL:
+            vOffsetScale = vec2(0.0, 1.0 / texture_size.y);
+            break;
+    }
+
+    vUvRect = vec4(src_task.data0.xy, src_task.data0.xy + src_task.data0.zw);
+    vUvRect /= texture_size.xyxy;
+
+    vec2 uv0 = src_task.data0.xy / texture_size;
+    vec2 uv1 = (src_task.data0.xy + src_task.data0.zw) / texture_size;
+    vUv.xy = mix(uv0, uv1, aPosition.xy);
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.fs.glsl
@@ -0,0 +1,148 @@
+#line 1
+/* 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/. */
+
+// See http://asciimath.org to render the equations here.
+
+// The Gaussian function used for blurring:
+//
+//     G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2))
+float gauss(float x, float sigma) {
+    float sigmaPow2 = sigma * sigma;
+    return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2));
+}
+
+// An approximation of the error function, which is related to the integral of the Gaussian
+// function:
+//
+//     "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt
+//              ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4
+//
+// where:
+//
+//     a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108
+//
+// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes.
+//
+// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions
+float erf(float x) {
+    bool negative = x < 0.0;
+    if (negative)
+        x = -x;
+    float x2 = x * x;
+    float x3 = x2 * x;
+    float x4 = x2 * x2;
+    float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4;
+    float result = 1.0 - 1.0 / (denom * denom * denom * denom);
+    return negative ? -result : result;
+}
+
+// A useful helper for calculating integrals of the Gaussian function via the error function:
+//
+//      "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx
+//                     = "erf"(x/(sigma sqrt(2)))
+float erfSigma(float x, float sigma) {
+    return erf(x / (sigma * 1.4142135623730951));
+}
+
+// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is
+// the vector distance to the top left corner of the box; `p_1` is the vector distance to its
+// bottom right corner.
+//
+//      "colorFromRect"_sigma(p_0, p_1)
+//          = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy
+//          = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x}))
+//              ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y}))
+float colorFromRect(vec2 p0, vec2 p1, float sigma) {
+    return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) *
+        (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0;
+}
+
+// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate:
+//
+//      "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2)
+float ellipsePoint(float y, float y0, vec2 radii) {
+    float bStep = (y - y0) / radii.y;
+    return radii.x * sqrt(1.0 - bStep * bStep);
+}
+
+// A helper function to compute the value that needs to be subtracted to accommodate the border
+// corners.
+//
+//     "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b)
+//          = int_{y_{min}}^{y_{max}}
+//              int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx
+//              + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x)
+//                  dx dy
+//          = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y)
+//              ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) +
+//               "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a))
+//
+// with the outer integral evaluated numerically.
+float colorCutoutGeneral(float x0l,
+                         float x0r,
+                         float y0,
+                         float yMin,
+                         float yMax,
+                         vec2 radii,
+                         float sigma) {
+    float sum = 0.0;
+    for (float y = yMin; y <= yMax; y += 1.0) {
+        float xEllipsePoint = ellipsePoint(y, y0, radii);
+        sum += gauss(y, sigma) *
+            (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) +
+             erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma));
+    }
+    return sum / 2.0;
+}
+
+// The value that needs to be subtracted to accommodate the top border corners.
+float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) {
+    return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma);
+}
+
+// The value that needs to be subtracted to accommodate the bottom border corners.
+float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) {
+    return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma);
+}
+
+// The blurred color value for the point at `pos` with the top left corner of the box at
+// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`.
+float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) {
+    // Compute the vector distances `p_0` and `p_1`.
+    vec2 p0 = p0Rect - pos, p1 = p1Rect - pos;
+
+    // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if
+    // the box is unrounded.
+    float cRect = colorFromRect(p0, p1, sigma);
+    if (radii.x == 0.0 || radii.y == 0.0)
+        return cRect;
+
+    // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`,
+    // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`.
+    float x0l = p0.x + radii.x;
+    float y0t = p1.y - radii.y;
+    float x0r = p1.x - radii.x;
+    float y0b = p0.y + radii.y;
+
+    // Compute the final color:
+    //
+    //     "colorFromRect"_sigma(p_0, p_1) -
+    //          ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) +
+    //           "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b))
+    float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma);
+    float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma);
+    return cRect - (cCutoutTop + cCutoutBottom);
+}
+
+void main(void) {
+    vec2 pos = vPos.xy;
+    vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw;
+    vec2 radii = vBorderRadii.xy;
+    float sigma = vBlurRadius / 2.0;
+    float value = color(pos, p0Rect, p1Rect, radii, sigma);
+
+    value = max(value, 0.0);
+    oFragColor = vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.glsl
@@ -0,0 +1,10 @@
+#line 1
+/* 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/. */
+
+varying vec2 vPos;
+flat varying vec2 vBorderRadii;
+flat varying float vBlurRadius;
+flat varying vec4 vBoxShadowRect;
+flat varying float vInverted;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_box_shadow.vs.glsl
@@ -0,0 +1,31 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    CachePrimitiveInstance cpi = fetch_cache_instance();
+    RenderTaskData task = fetch_render_task(cpi.render_task_index);
+    BoxShadow bs = fetch_boxshadow(cpi.specific_prim_index);
+
+    vec2 p0 = task.data0.xy;
+    vec2 p1 = p0 + task.data0.zw;
+
+    vec2 pos = mix(p0, p1, aPosition.xy);
+
+    vBorderRadii = bs.border_radius_edge_size_blur_radius_inverted.xx;
+    vBlurRadius = bs.border_radius_edge_size_blur_radius_inverted.z;
+    vInverted = bs.border_radius_edge_size_blur_radius_inverted.w;
+    vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw);
+
+    // The fragment shader expects logical units, beginning at where the
+    // blur radius begins.
+    // The first path of the equation gets the virtual position in
+    // logical pixels within the patch rectangle (accounting for
+    // bilinear offset). Then we add the start position of the
+    // box shadow rect and subtract the blur radius to get the
+    // virtual coordinates that the FS expects.
+    vPos = (pos - 1.0 - p0) / uDevicePixelRatio + bs.bs_rect.xy - vec2(2.0 * vBlurRadius);
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.fs.glsl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+void main(void) {
+    float alpha = 1.f;
+    vec2 local_pos = init_transform_fs(vPos, vLocalRect, alpha);
+
+    bool repeat_mask = false; //TODO
+    vec2 clamped_mask_uv = repeat_mask ? fract(vClipMaskUv.xy) :
+        clamp(vClipMaskUv.xy, vec2(0.0, 0.0), vec2(1.0, 1.0));
+    vec2 source_uv = clamped_mask_uv * vClipMaskUvRect.zw + vClipMaskUvRect.xy;
+    float clip_alpha = texture(sMask, source_uv).r; //careful: texture has type A8
+
+    oFragColor = vec4(min(alpha, clip_alpha), 1.0, 1.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.glsl
@@ -0,0 +1,9 @@
+#line 1
+
+/* 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/. */
+
+varying vec3 vPos;
+flat varying vec4 vLocalRect;
+flat varying vec4 vClipMaskUvRect;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_image.vs.glsl
@@ -0,0 +1,39 @@
+#line 1
+/* 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/. */
+
+struct ImageMaskData {
+    vec4 uv_rect;
+    vec4 local_rect;
+};
+
+ImageMaskData fetch_mask_data(int index) {
+    ImageMaskData info;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    info.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    info.local_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return info;
+}
+
+void main(void) {
+    CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
+    ClipArea area = fetch_clip_area(cci.render_task_index);
+    Layer layer = fetch_layer(cci.layer_index);
+    ImageMaskData mask = fetch_mask_data(cci.data_index);
+    vec4 local_rect = mask.local_rect;
+
+    TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
+                                                    layer,
+                                                    area,
+                                                    cci.segment_index);
+    vLocalRect = vi.clipped_local_rect;
+    vPos = vi.local_pos;
+
+    vClipMaskUv = vec3((vPos.xy / vPos.z - local_rect.xy) / local_rect.zw, 0.0);
+    vec2 texture_size = vec2(textureSize(sMask, 0));
+    vClipMaskUvRect = mask.uv_rect / texture_size.xyxy;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.fs.glsl
@@ -0,0 +1,44 @@
+/* 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/. */
+
+float rounded_rect(vec2 pos) {
+    vec2 ref_tl = vClipRect.xy + vec2( vClipRadius.x,  vClipRadius.x);
+    vec2 ref_tr = vClipRect.zy + vec2(-vClipRadius.y,  vClipRadius.y);
+    vec2 ref_br = vClipRect.zw + vec2(-vClipRadius.z, -vClipRadius.z);
+    vec2 ref_bl = vClipRect.xw + vec2( vClipRadius.w, -vClipRadius.w);
+
+    float d_tl = distance(pos, ref_tl);
+    float d_tr = distance(pos, ref_tr);
+    float d_br = distance(pos, ref_br);
+    float d_bl = distance(pos, ref_bl);
+
+    float pixels_per_fragment = length(fwidth(pos.xy));
+    float nudge = 0.5 * pixels_per_fragment;
+    vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - vClipRadius + nudge;
+
+    bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y,
+                         pos.x > ref_tr.x && pos.y < ref_tr.y,
+                         pos.x > ref_br.x && pos.y > ref_br.y,
+                         pos.x < ref_bl.x && pos.y > ref_bl.y);
+
+    float distance_from_border = dot(vec4(is_out),
+                                     max(vec4(0.0, 0.0, 0.0, 0.0), distances));
+
+    // Move the distance back into pixels.
+    distance_from_border /= pixels_per_fragment;
+    // Apply a more gradual fade out to transparent.
+    //distance_from_border -= 0.5;
+
+    return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
+
+void main(void) {
+    float alpha = 1.f;
+    vec2 local_pos = init_transform_fs(vPos, vLocalRect, alpha);
+
+    float clip_alpha = rounded_rect(local_pos);
+
+    oFragColor = vec4(min(alpha, clip_alpha), 0.0, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.glsl
@@ -0,0 +1,10 @@
+#line 1
+
+/* 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/. */
+
+varying vec3 vPos;
+flat varying vec4 vLocalRect;
+flat varying vec4 vClipRect;
+flat varying vec4 vClipRadius;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_clip_rectangle.vs.glsl
@@ -0,0 +1,78 @@
+#line 1
+/* 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/. */
+
+struct ClipRect {
+    vec4 rect;
+    vec4 dummy;
+};
+
+ClipRect fetch_clip_rect(int index) {
+    ClipRect rect;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    //rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+    rect.dummy = vec4(0.0, 0.0, 0.0, 0.0);
+
+    return rect;
+}
+
+struct ClipCorner {
+    vec4 rect;
+    vec4 outer_inner_radius;
+};
+
+ClipCorner fetch_clip_corner(int index) {
+    ClipCorner corner;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    corner.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    corner.outer_inner_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return corner;
+}
+
+struct ClipData {
+    ClipRect rect;
+    ClipCorner top_left;
+    ClipCorner top_right;
+    ClipCorner bottom_left;
+    ClipCorner bottom_right;
+};
+
+ClipData fetch_clip(int index) {
+    ClipData clip;
+
+    clip.rect = fetch_clip_rect(index + 0);
+    clip.top_left = fetch_clip_corner(index + 1);
+    clip.top_right = fetch_clip_corner(index + 2);
+    clip.bottom_left = fetch_clip_corner(index + 3);
+    clip.bottom_right = fetch_clip_corner(index + 4);
+
+    return clip;
+}
+
+void main(void) {
+    CacheClipInstance cci = fetch_clip_item(gl_InstanceID);
+    ClipArea area = fetch_clip_area(cci.render_task_index);
+    Layer layer = fetch_layer(cci.layer_index);
+    ClipData clip = fetch_clip(cci.data_index);
+    vec4 local_rect = clip.rect.rect;
+
+    TransformVertexInfo vi = write_clip_tile_vertex(local_rect,
+                                                    layer,
+                                                    area,
+                                                    cci.segment_index);
+    vLocalRect = vi.clipped_local_rect;
+    vPos = vi.local_pos;
+
+    vClipRect = vec4(local_rect.xy, local_rect.xy + local_rect.zw);
+    vClipRadius = vec4(clip.top_left.outer_inner_radius.x,
+                       clip.top_right.outer_inner_radius.x,
+                       clip.bottom_right.outer_inner_radius.x,
+                       clip.bottom_left.outer_inner_radius.x);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.fs.glsl
@@ -0,0 +1,9 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    float a = texture(sColor0, vUv).a;
+    oFragColor = vec4(vColor.rgb, vColor.a * a);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.glsl
@@ -0,0 +1,7 @@
+#line 1
+/* 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/. */
+
+varying vec2 vUv;
+flat varying vec4 vColor;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/cs_text_run.vs.glsl
@@ -0,0 +1,36 @@
+#line 1
+/* 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/. */
+
+// Draw a text run to a cache target. These are always
+// drawn un-transformed. These are used for effects such
+// as text-shadow.
+
+void main(void) {
+    CachePrimitiveInstance cpi = fetch_cache_instance();
+    RenderTaskData task = fetch_render_task(cpi.render_task_index);
+    TextRun text = fetch_text_run(cpi.specific_prim_index);
+    Glyph glyph = fetch_glyph(cpi.sub_index);
+    PrimitiveGeometry pg = fetch_prim_geometry(cpi.global_prim_index);
+    ResourceRect res = fetch_resource_rect(cpi.user_data.x);
+
+    // Glyphs size is already in device-pixels.
+    // The render task origin is in device-pixels. Offset that by
+    // the glyph offset, relative to its primitive bounding rect.
+    vec2 size = res.uv_rect.zw - res.uv_rect.xy;
+    vec2 origin = task.data0.xy + uDevicePixelRatio * (glyph.offset.xy - pg.local_rect.xy);
+    vec4 local_rect = vec4(origin, size);
+
+    vec2 texture_size = vec2(textureSize(sColor0, 0));
+    vec2 st0 = res.uv_rect.xy / texture_size;
+    vec2 st1 = res.uv_rect.zw / texture_size;
+
+    vec2 pos = mix(local_rect.xy,
+                   local_rect.xy + local_rect.zw,
+                   aPosition.xy);
+	vUv = mix(st0, st1, aPosition.xy);
+	vColor = text.color;
+
+    gl_Position = uTransform * vec4(pos, 0.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_color.fs.glsl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+void main(void)
+{
+    oFragColor = vColor;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_color.vs.glsl
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+in vec4 aColor;
+varying vec4 vColor;
+
+void main(void)
+{
+    vColor = aColor;
+    vec4 pos = vec4(aPosition, 1.0);
+    pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio;
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_font.fs.glsl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+varying vec2 vColorTexCoord;
+varying vec4 vColor;
+
+void main(void)
+{
+#ifdef SERVO_ES2
+    float alpha = texture(sColor0, vColorTexCoord.xy).a;
+#else
+    float alpha = texture(sColor0, vColorTexCoord.xy).r;
+#endif
+    oFragColor = vec4(vColor.xyz, vColor.w * alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/debug_font.vs.glsl
@@ -0,0 +1,18 @@
+/* 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/. */
+
+in vec4 aColor;
+in vec4 aColorTexCoord;
+
+varying vec2 vColorTexCoord;
+varying vec4 vColor;
+
+void main(void)
+{
+    vColor = aColor;
+    vColorTexCoord = aColorTexCoord.xy;
+    vec4 pos = vec4(aPosition, 1.0);
+    pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio;
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -0,0 +1,665 @@
+#line 1
+/* 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/. */
+
+#if defined(GL_ES)
+    #if GL_ES == 1
+        #ifdef GL_FRAGMENT_PRECISION_HIGH
+        precision highp sampler2DArray;
+        #else
+        precision mediump sampler2DArray;
+        #endif
+    #endif
+#endif
+
+#define PST_TOP_LEFT     0
+#define PST_TOP          1
+#define PST_TOP_RIGHT    2
+#define PST_RIGHT        3
+#define PST_BOTTOM_RIGHT 4
+#define PST_BOTTOM       5
+#define PST_BOTTOM_LEFT  6
+#define PST_LEFT         7
+
+#define BORDER_LEFT      0
+#define BORDER_TOP       1
+#define BORDER_RIGHT     2
+#define BORDER_BOTTOM    3
+
+#define UV_NORMALIZED    uint(0)
+#define UV_PIXEL         uint(1)
+
+#define MAX_STOPS_PER_ANGLE_GRADIENT 8
+#define MAX_STOPS_PER_RADIAL_GRADIENT 8
+
+uniform sampler2DArray sCache;
+
+flat varying vec4 vClipMaskUvBounds;
+varying vec3 vClipMaskUv;
+
+#ifdef WR_VERTEX_SHADER
+
+#define VECS_PER_LAYER             13
+#define VECS_PER_RENDER_TASK        3
+#define VECS_PER_PRIM_GEOM          2
+
+#define GRADIENT_HORIZONTAL     0
+#define GRADIENT_VERTICAL       1
+#define GRADIENT_ROTATED        2
+
+uniform sampler2D sLayers;
+uniform sampler2D sRenderTasks;
+uniform sampler2D sPrimGeometry;
+
+uniform sampler2D sData16;
+uniform sampler2D sData32;
+uniform sampler2D sData64;
+uniform sampler2D sData128;
+uniform sampler2D sResourceRects;
+
+// Instanced attributes
+in int aGlobalPrimId;
+in int aPrimitiveAddress;
+in int aTaskIndex;
+in int aClipTaskIndex;
+in int aLayerIndex;
+in int aElementIndex;
+in ivec2 aUserData;
+in int aZIndex;
+
+// get_fetch_uv is a macro to work around a macOS Intel driver parsing bug.
+// TODO: convert back to a function once the driver issues are resolved, if ever.
+// https://github.com/servo/webrender/pull/623
+// https://github.com/servo/servo/issues/13953
+#define get_fetch_uv(i, vpi)  ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
+
+ivec2 get_fetch_uv_1(int index) {
+    return get_fetch_uv(index, 1);
+}
+
+ivec2 get_fetch_uv_2(int index) {
+    return get_fetch_uv(index, 2);
+}
+
+ivec2 get_fetch_uv_4(int index) {
+    return get_fetch_uv(index, 4);
+}
+
+ivec2 get_fetch_uv_8(int index) {
+    return get_fetch_uv(index, 8);
+}
+
+struct Layer {
+    mat4 transform;
+    mat4 inv_transform;
+    vec4 local_clip_rect;
+    vec4 screen_vertices[4];
+};
+
+Layer fetch_layer(int index) {
+    Layer layer;
+
+    // Create a UV base coord for each 8 texels.
+    // This is required because trying to use an offset
+    // of more than 8 texels doesn't work on some versions
+    // of OSX.
+    ivec2 uv = get_fetch_uv(index, VECS_PER_LAYER);
+    ivec2 uv0 = ivec2(uv.x + 0, uv.y);
+    ivec2 uv1 = ivec2(uv.x + 8, uv.y);
+
+    layer.transform[0] = texelFetchOffset(sLayers, uv0, 0, ivec2(0, 0));
+    layer.transform[1] = texelFetchOffset(sLayers, uv0, 0, ivec2(1, 0));
+    layer.transform[2] = texelFetchOffset(sLayers, uv0, 0, ivec2(2, 0));
+    layer.transform[3] = texelFetchOffset(sLayers, uv0, 0, ivec2(3, 0));
+
+    layer.inv_transform[0] = texelFetchOffset(sLayers, uv0, 0, ivec2(4, 0));
+    layer.inv_transform[1] = texelFetchOffset(sLayers, uv0, 0, ivec2(5, 0));
+    layer.inv_transform[2] = texelFetchOffset(sLayers, uv0, 0, ivec2(6, 0));
+    layer.inv_transform[3] = texelFetchOffset(sLayers, uv0, 0, ivec2(7, 0));
+
+    layer.local_clip_rect = texelFetchOffset(sLayers, uv1, 0, ivec2(0, 0));
+
+    layer.screen_vertices[0] = texelFetchOffset(sLayers, uv1, 0, ivec2(1, 0));
+    layer.screen_vertices[1] = texelFetchOffset(sLayers, uv1, 0, ivec2(2, 0));
+    layer.screen_vertices[2] = texelFetchOffset(sLayers, uv1, 0, ivec2(3, 0));
+    layer.screen_vertices[3] = texelFetchOffset(sLayers, uv1, 0, ivec2(4, 0));
+
+    return layer;
+}
+
+struct RenderTaskData {
+    vec4 data0;
+    vec4 data1;
+    vec4 data2;
+};
+
+RenderTaskData fetch_render_task(int index) {
+    RenderTaskData task;
+
+    ivec2 uv = get_fetch_uv(index, VECS_PER_RENDER_TASK);
+
+    task.data0 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(0, 0));
+    task.data1 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(1, 0));
+    task.data2 = texelFetchOffset(sRenderTasks, uv, 0, ivec2(2, 0));
+
+    return task;
+}
+
+struct Tile {
+    vec4 screen_origin_task_origin;
+    vec4 size_target_index;
+};
+
+Tile fetch_tile(int index) {
+    RenderTaskData task = fetch_render_task(index);
+
+    Tile tile;
+    tile.screen_origin_task_origin = task.data0;
+    tile.size_target_index = task.data1;
+
+    return tile;
+}
+
+struct ClipArea {
+    vec4 task_bounds;
+    vec4 screen_origin_target_index;
+    vec4 inner_rect;
+};
+
+ClipArea fetch_clip_area(int index) {
+    ClipArea area;
+
+    if (index == 0x7FFFFFFF) { //special sentinel task index
+        area.task_bounds = vec4(0.0, 0.0, 0.0, 0.0);
+        area.screen_origin_target_index = vec4(0.0, 0.0, 0.0, 0.0);
+        area.inner_rect = vec4(0.0);
+    } else {
+        RenderTaskData task = fetch_render_task(index);
+        area.task_bounds = task.data0;
+        area.screen_origin_target_index = task.data1;
+        area.inner_rect = task.data2;
+    }
+
+    return area;
+}
+
+struct Gradient {
+    vec4 start_end_point;
+    vec4 kind;
+};
+
+Gradient fetch_gradient(int index) {
+    Gradient gradient;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    gradient.start_end_point = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    gradient.kind = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return gradient;
+}
+
+struct GradientStop {
+    vec4 color;
+    vec4 offset;
+};
+
+GradientStop fetch_gradient_stop(int index) {
+    GradientStop stop;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    stop.color = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    stop.offset = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return stop;
+}
+
+struct RadialGradient {
+    vec4 start_end_center;
+    vec4 start_end_radius;
+};
+
+RadialGradient fetch_radial_gradient(int index) {
+    RadialGradient gradient;
+
+    ivec2 uv = get_fetch_uv_2(index);
+
+    gradient.start_end_center = texelFetchOffset(sData32, uv, 0, ivec2(0, 0));
+    gradient.start_end_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0));
+
+    return gradient;
+}
+
+struct Glyph {
+    vec4 offset;
+};
+
+Glyph fetch_glyph(int index) {
+    Glyph glyph;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    glyph.offset = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return glyph;
+}
+
+vec4 fetch_instance_geometry(int index) {
+    ivec2 uv = get_fetch_uv_1(index);
+
+    vec4 rect = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct PrimitiveGeometry {
+    vec4 local_rect;
+    vec4 local_clip_rect;
+};
+
+PrimitiveGeometry fetch_prim_geometry(int index) {
+    PrimitiveGeometry pg;
+
+    ivec2 uv = get_fetch_uv(index, VECS_PER_PRIM_GEOM);
+
+    pg.local_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(0, 0));
+    pg.local_clip_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(1, 0));
+
+    return pg;
+}
+
+struct PrimitiveInstance {
+    int global_prim_index;
+    int specific_prim_index;
+    int render_task_index;
+    int clip_task_index;
+    int layer_index;
+    int sub_index;
+    int z;
+    ivec2 user_data;
+};
+
+PrimitiveInstance fetch_prim_instance() {
+    PrimitiveInstance pi;
+
+    pi.global_prim_index = aGlobalPrimId;
+    pi.specific_prim_index = aPrimitiveAddress;
+    pi.render_task_index = aTaskIndex;
+    pi.clip_task_index = aClipTaskIndex;
+    pi.layer_index = aLayerIndex;
+    pi.sub_index = aElementIndex;
+    pi.user_data = aUserData;
+    pi.z = aZIndex;
+
+    return pi;
+}
+
+struct CachePrimitiveInstance {
+    int global_prim_index;
+    int specific_prim_index;
+    int render_task_index;
+    int sub_index;
+    ivec2 user_data;
+};
+
+CachePrimitiveInstance fetch_cache_instance() {
+    CachePrimitiveInstance cpi;
+
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    cpi.global_prim_index = pi.global_prim_index;
+    cpi.specific_prim_index = pi.specific_prim_index;
+    cpi.render_task_index = pi.render_task_index;
+    cpi.sub_index = pi.sub_index;
+    cpi.user_data = pi.user_data;
+
+    return cpi;
+}
+
+struct Primitive {
+    Layer layer;
+    Tile tile;
+    ClipArea clip_area;
+    vec4 local_rect;
+    vec4 local_clip_rect;
+    int prim_index;
+    // when sending multiple primitives of the same type (e.g. border segments)
+    // this index allows the vertex shader to recognize the difference
+    int sub_index;
+    ivec2 user_data;
+    float z;
+};
+
+Primitive load_primitive_custom(PrimitiveInstance pi) {
+    Primitive prim;
+
+    prim.layer = fetch_layer(pi.layer_index);
+    prim.tile = fetch_tile(pi.render_task_index);
+    prim.clip_area = fetch_clip_area(pi.clip_task_index);
+
+    PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index);
+    prim.local_rect = pg.local_rect;
+    prim.local_clip_rect = pg.local_clip_rect;
+
+    prim.prim_index = pi.specific_prim_index;
+    prim.sub_index = pi.sub_index;
+    prim.user_data = pi.user_data;
+    prim.z = float(pi.z);
+
+    return prim;
+}
+
+Primitive load_primitive() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    return load_primitive_custom(pi);
+}
+
+
+// Return the intersection of the plane (set up by "normal" and "point")
+// with the ray (set up by "ray_origin" and "ray_dir"),
+// writing the resulting scaler into "t".
+bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t)
+{
+    float denom = dot(normal, ray_dir);
+    if (denom > 1e-6) {
+        vec3 d = point - ray_origin;
+        t = dot(d, normal) / denom;
+        return t >= 0.0;
+    }
+
+    return false;
+}
+
+// Apply the inverse transform "inv_transform"
+// to the reference point "ref" in CSS space,
+// producing a local point on a layer plane,
+// set by a base point "a" and a normal "n".
+vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
+    vec3 p = vec3(ref, -10000.0);
+    vec3 d = vec3(0, 0, 1.0);
+
+    float t = 0.0;
+    // get an intersection of the layer plane with Z axis vector,
+    // originated from the "ref" point
+    ray_plane(n, a, p, d, t);
+    float z = p.z + d.z * t; // Z of the visible point on the layer
+
+    vec4 r = inv_transform * vec4(ref, z, 1.0);
+    return r;
+}
+
+// Given a CSS space position, transform it back into the layer space.
+vec4 get_layer_pos(vec2 pos, Layer layer) {
+    // get 3 of the layer corners in CSS space
+    vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w;
+    vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w;
+    vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w;
+    // get the normal to the layer plane
+    vec3 n = normalize(cross(b-a, c-a));
+    return untransform(pos, n, a, layer.inv_transform);
+}
+
+vec2 clamp_rect(vec2 point, vec4 rect) {
+    return clamp(point, rect.xy, rect.xy + rect.zw);
+}
+
+struct Rect {
+    vec2 p0;
+    vec2 p1;
+};
+
+struct VertexInfo {
+    Rect local_rect;
+    vec2 local_clamped_pos;
+    vec2 global_clamped_pos;
+};
+
+VertexInfo write_vertex(vec4 instance_rect,
+                        vec4 local_clip_rect,
+                        float z,
+                        Layer layer,
+                        Tile tile) {
+    vec2 p0 = floor(0.5 + instance_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vec2 p1 = floor(0.5 + (instance_rect.xy + instance_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
+
+    vec2 local_pos = mix(p0, p1, aPosition.xy);
+
+    vec2 cp0 = floor(0.5 + local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vec2 cp1 = floor(0.5 + (local_clip_rect.xy + local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio;
+    local_pos = clamp(local_pos, cp0, cp1);
+
+    local_pos = clamp_rect(local_pos, layer.local_clip_rect);
+
+    vec4 world_pos = layer.transform * vec4(local_pos, 0.0, 1.0);
+    world_pos.xyz /= world_pos.w;
+
+    vec2 device_pos = world_pos.xy * uDevicePixelRatio;
+
+    vec2 clamped_pos = clamp(device_pos,
+                             tile.screen_origin_task_origin.xy,
+                             tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1);
+    local_clamped_pos.xyz /= local_clamped_pos.w;
+
+    vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy;
+
+    gl_Position = uTransform * vec4(final_pos, z, 1.0);
+
+    VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy);
+    return vi;
+}
+
+#ifdef WR_FEATURE_TRANSFORM
+
+struct TransformVertexInfo {
+    vec3 local_pos;
+    vec2 global_clamped_pos;
+    vec4 clipped_local_rect;
+};
+
+TransformVertexInfo write_transform_vertex(vec4 instance_rect,
+                                           vec4 local_clip_rect,
+                                           float z,
+                                           Layer layer,
+                                           Tile tile) {
+    vec2 lp0_base = instance_rect.xy;
+    vec2 lp1_base = instance_rect.xy + instance_rect.zw;
+
+    vec2 lp0 = clamp_rect(clamp_rect(lp0_base, local_clip_rect),
+                          layer.local_clip_rect);
+    vec2 lp1 = clamp_rect(clamp_rect(lp1_base, local_clip_rect),
+                          layer.local_clip_rect);
+
+    vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
+
+    vec2 p0 = lp0;
+    vec2 p1 = vec2(lp1.x, lp0.y);
+    vec2 p2 = vec2(lp0.x, lp1.y);
+    vec2 p3 = lp1;
+
+    vec4 t0 = layer.transform * vec4(p0, 0, 1);
+    vec4 t1 = layer.transform * vec4(p1, 0, 1);
+    vec4 t2 = layer.transform * vec4(p2, 0, 1);
+    vec4 t3 = layer.transform * vec4(p3, 0, 1);
+
+    vec2 tp0 = t0.xy / t0.w;
+    vec2 tp1 = t1.xy / t1.w;
+    vec2 tp2 = t2.xy / t2.w;
+    vec2 tp3 = t3.xy / t3.w;
+
+    // compute a CSS space aligned bounding box
+    vec2 min_pos = min(min(tp0.xy, tp1.xy), min(tp2.xy, tp3.xy));
+    vec2 max_pos = max(max(tp0.xy, tp1.xy), max(tp2.xy, tp3.xy));
+
+    // clamp to the tile boundaries, in device space
+    vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio,
+                                 tile.screen_origin_task_origin.xy,
+                                 tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio,
+                                 tile.screen_origin_task_origin.xy,
+                                 tile.screen_origin_task_origin.xy + tile.size_target_index.xy);
+
+    // compute the device space position of this vertex
+    vec2 clamped_pos = mix(min_pos_clamped,
+                           max_pos_clamped,
+                           aPosition.xy);
+
+    // compute the point position in side the layer, in CSS space
+    vec4 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, layer);
+
+    // apply the task offset
+    vec2 final_pos = clamped_pos + tile.screen_origin_task_origin.zw - tile.screen_origin_task_origin.xy;
+
+    gl_Position = uTransform * vec4(final_pos, z, 1.0);
+
+    return TransformVertexInfo(layer_pos.xyw, clamped_pos, clipped_local_rect);
+}
+
+#endif //WR_FEATURE_TRANSFORM
+
+struct ResourceRect {
+    vec4 uv_rect;
+};
+
+ResourceRect fetch_resource_rect(int index) {
+    ResourceRect rect;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    rect.uv_rect = texelFetchOffset(sResourceRects, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct Rectangle {
+    vec4 color;
+};
+
+Rectangle fetch_rectangle(int index) {
+    Rectangle rect;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    rect.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return rect;
+}
+
+struct TextRun {
+    vec4 color;
+};
+
+TextRun fetch_text_run(int index) {
+    TextRun text;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    text.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return text;
+}
+
+struct Image {
+    vec4 stretch_size_and_tile_spacing;  // Size of the actual image and amount of space between
+                                         //     tiled instances of this image.
+};
+
+Image fetch_image(int index) {
+    Image image;
+
+    ivec2 uv = get_fetch_uv_1(index);
+
+    image.stretch_size_and_tile_spacing = texelFetchOffset(sData16, uv, 0, ivec2(0, 0));
+
+    return image;
+}
+
+// YUV color spaces
+#define YUV_REC601 1
+#define YUV_REC709 2
+
+struct YuvImage {
+    vec4 y_st_rect;
+    vec4 u_st_rect;
+    vec4 v_st_rect;
+    vec2 size;
+    int color_space;
+};
+
+YuvImage fetch_yuv_image(int index) {
+    YuvImage image;
+
+    ivec2 uv = get_fetch_uv_4(index);
+
+    image.y_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
+    image.u_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
+    image.v_st_rect = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
+    vec4 size_color_space = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
+    image.size = size_color_space.xy;
+    image.color_space = int(size_color_space.z);
+
+    return image;
+}
+
+struct BoxShadow {
+    vec4 src_rect;
+    vec4 bs_rect;
+    vec4 color;
+    vec4 border_radius_edge_size_blur_radius_inverted;
+};
+
+BoxShadow fetch_boxshadow(int index) {
+    BoxShadow bs;
+
+    ivec2 uv = get_fetch_uv_4(index);
+
+    bs.src_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0));
+    bs.bs_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0));
+    bs.color = texelFetchOffset(sData64, uv, 0, ivec2(2, 0));
+    bs.border_radius_edge_size_blur_radius_inverted = texelFetchOffset(sData64, uv, 0, ivec2(3, 0));
+
+    return bs;
+}
+
+void write_clip(vec2 global_pos, ClipArea area) {
+    vec2 texture_size = vec2(textureSize(sCache, 0).xy);
+    vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
+    vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
+    vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
+}
+#endif //WR_VERTEX_SHADER
+
+#ifdef WR_FRAGMENT_SHADER
+float distance_from_rect(vec2 p, vec2 origin, vec2 size) {
+    vec2 clamped = clamp(p, origin, origin + size);
+    return distance(clamped, p);
+}
+
+vec2 init_transform_fs(vec3 local_pos, vec4 local_rect, out float fragment_alpha) {
+    fragment_alpha = 1.0;
+    vec2 pos = local_pos.xy / local_pos.z;
+
+    float border_distance = distance_from_rect(pos, local_rect.xy, local_rect.zw);
+    if (border_distance != 0.0) {
+        float delta = length(fwidth(local_pos.xy));
+        fragment_alpha = 1.0 - smoothstep(0.0, 1.0, border_distance / delta * 2.0);
+    }
+
+    return pos;
+}
+
+float do_clip() {
+    // anything outside of the mask is considered transparent
+    bvec4 inside = lessThanEqual(
+        vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
+        vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
+    // check for the dummy bounds, which are given to the opaque objects
+    return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
+        all(inside) ? textureLod(sCache, vClipMaskUv, 0.0).r : 0.0;
+}
+#endif //WR_FRAGMENT_SHADER
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.fs.glsl
@@ -0,0 +1,39 @@
+/* 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/. */
+
+float offset(int index) {
+    return vOffsets[index / 4][index % 4];
+}
+
+float linearStep(float lo, float hi, float x) {
+    float d = hi - lo;
+    float v = x - lo;
+    if (d != 0.0) {
+        v /= d;
+    }
+    return clamp(v, 0.0, 1.0);
+}
+
+void main(void) {
+    float angle = atan(-vEndPoint.y + vStartPoint.y,
+                        vEndPoint.x - vStartPoint.x);
+    float sa = sin(angle);
+    float ca = cos(angle);
+
+    float sx = vStartPoint.x * ca - vStartPoint.y * sa;
+    float ex = vEndPoint.x * ca - vEndPoint.y * sa;
+    float d = ex - sx;
+
+    float x = vPos.x * ca - vPos.y * sa;
+
+    oFragColor = mix(vColors[0],
+                     vColors[1],
+                     linearStep(sx + d * offset(0), sx + d * offset(1), x));
+
+    for (int i=1 ; i < vStopCount-1 ; ++i) {
+        oFragColor = mix(oFragColor,
+                         vColors[i+1],
+                         linearStep(sx + d * offset(i), sx + d * offset(i+1), x));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.glsl
@@ -0,0 +1,11 @@
+/* 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/. */
+
+flat varying int vStopCount;
+flat varying float vAngle;
+flat varying vec2 vStartPoint;
+flat varying vec2 vEndPoint;
+varying vec2 vPos;
+flat varying vec4 vColors[MAX_STOPS_PER_ANGLE_GRADIENT];
+flat varying vec4 vOffsets[MAX_STOPS_PER_ANGLE_GRADIENT/4];
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_angle_gradient.vs.glsl
@@ -0,0 +1,33 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    Gradient gradient = fetch_gradient(prim.prim_index);
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vStopCount = int(prim.user_data.x);
+    vPos = vi.local_clamped_pos;
+
+    // Snap the start/end points to device pixel units.
+    // I'm not sure this is entirely correct, but the
+    // old render path does this, and it is needed to
+    // make the angle gradient ref tests pass. It might
+    // be better to fix this higher up in DL construction
+    // and not snap here?
+    vStartPoint = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vEndPoint = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio;
+
+    for (int i=0 ; i < vStopCount ; ++i) {
+        GradientStop stop = fetch_gradient_stop(prim.sub_index + i);
+        vColors[i] = stop.color;
+        vOffsets[i/4][i%4] = stop.offset.x;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.fs.glsl
@@ -0,0 +1,138 @@
+/* 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/. */
+
+vec3 rgbToHsv(vec3 c) {
+    float value = max(max(c.r, c.g), c.b);
+
+    float chroma = value - min(min(c.r, c.g), c.b);
+    if (chroma == 0.0) {
+        return vec3(0.0);
+    }
+    float saturation = chroma / value;
+
+    float hue;
+    if (c.r == value)
+        hue = (c.g - c.b) / chroma;
+    else if (c.g == value)
+        hue = 2.0 + (c.b - c.r) / chroma;
+    else // if (c.b == value)
+        hue = 4.0 + (c.r - c.g) / chroma;
+
+    hue *= 1.0/6.0;
+    if (hue < 0.0)
+        hue += 1.0;
+    return vec3(hue, saturation, value);
+}
+
+vec3 hsvToRgb(vec3 c) {
+    if (c.s == 0.0) {
+        return vec3(c.z);
+    }
+
+    float hue = c.x * 6.0;
+    int sector = int(hue);
+    float residualHue = hue - float(sector);
+
+    vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue));
+    switch (sector) {
+        case 0:
+            return vec3(c.z, pqt.z, pqt.x);
+        case 1:
+            return vec3(pqt.y, c.z, pqt.x);
+        case 2:
+            return vec3(pqt.x, c.z, pqt.z);
+        case 3:
+            return vec3(pqt.x, pqt.y, c.z);
+        case 4:
+            return vec3(pqt.z, pqt.x, c.z);
+        default:
+            return vec3(c.z, pqt.x, pqt.y);
+    }
+}
+
+vec4 Blur(float radius, vec2 direction) {
+    // TODO(gw): Support blur in WR2!
+    return vec4(1.0);
+}
+
+vec4 Contrast(vec4 Cs, float amount) {
+    return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0);
+}
+
+vec4 Grayscale(vec4 Cs, float amount) {
+    float ia = 1.0 - amount;
+    return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0),
+                vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0),
+                vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0),
+                vec4(0.0, 0.0, 0.0, 1.0)) * Cs;
+}
+
+vec4 HueRotate(vec4 Cs, float amount) {
+    vec3 CsHsv = rgbToHsv(Cs.rgb);
+    CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0);
+    return vec4(hsvToRgb(CsHsv), Cs.a);
+}
+
+vec4 Invert(vec4 Cs, float amount) {
+    return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount);
+}
+
+vec4 Saturate(vec4 Cs, float amount) {
+    return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a);
+}
+
+vec4 Sepia(vec4 Cs, float amount) {
+    float ia = 1.0 - amount;
+    return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0),
+                vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0),
+                vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0),
+                vec4(0.0, 0.0, 0.0, 1.0)) * Cs;
+}
+
+vec4 Brightness(vec4 Cs, float amount) {
+    return vec4(Cs.rgb * amount, Cs.a);
+}
+
+vec4 Opacity(vec4 Cs, float amount) {
+    return vec4(Cs.rgb, Cs.a * amount);
+}
+
+void main(void) {
+    vec4 Cs = texture(sCache, vUv);
+
+    if (Cs.a == 0.0) {
+        discard;
+    }
+
+    switch (vOp) {
+        case 0:
+            // Gaussian blur is specially handled:
+            oFragColor = Cs;// Blur(vAmount, vec2(0,0));
+            break;
+        case 1:
+            oFragColor = Contrast(Cs, vAmount);
+            break;
+        case 2:
+            oFragColor = Grayscale(Cs, vAmount);
+            break;
+        case 3:
+            oFragColor = HueRotate(Cs, vAmount);
+            break;
+        case 4:
+            oFragColor = Invert(Cs, vAmount);
+            break;
+        case 5:
+            oFragColor = Saturate(Cs, vAmount);
+            break;
+        case 6:
+            oFragColor = Sepia(Cs, vAmount);
+            break;
+        case 7:
+            oFragColor = Brightness(Cs, vAmount);
+            break;
+        case 8:
+            oFragColor = Opacity(Cs, vAmount);
+            break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.glsl
@@ -0,0 +1,7 @@
+/* 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/. */
+
+varying vec3 vUv;
+flat varying float vAmount;
+flat varying int vOp;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_blend.vs.glsl
@@ -0,0 +1,46 @@
+#line 1
+/* 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/. */
+
+struct Blend {
+    ivec4 src_id_target_id_op_amount;
+    int z;
+};
+
+Blend fetch_blend() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    Blend blend;
+    blend.src_id_target_id_op_amount = ivec4(pi.user_data.x,
+                                             pi.render_task_index,
+                                             pi.sub_index,
+                                             pi.user_data.y);
+    blend.z = pi.z;
+
+    return blend;
+}
+
+void main(void) {
+    Blend blend = fetch_blend();
+    Tile src = fetch_tile(blend.src_id_target_id_op_amount.x);
+    Tile dest = fetch_tile(blend.src_id_target_id_op_amount.y);
+
+    vec2 dest_origin = dest.screen_origin_task_origin.zw -
+                       dest.screen_origin_task_origin.xy +
+                       src.screen_origin_task_origin.xy;
+
+    vec2 local_pos = mix(dest_origin,
+                         dest_origin + src.size_target_index.xy,
+                         aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 st0 = src.screen_origin_task_origin.zw / texture_size;
+    vec2 st1 = (src.screen_origin_task_origin.zw + src.size_target_index.xy) / texture_size;
+    vUv = vec3(mix(st0, st1, aPosition.xy), src.size_target_index.z);
+
+    vOp = blend.src_id_target_id_op_amount.z;
+    vAmount = float(blend.src_id_target_id_op_amount.w) / 65535.0;
+
+    gl_Position = uTransform * vec4(local_pos, blend.z, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.fs.glsl
@@ -0,0 +1,408 @@
+#line 1
+
+/* 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/. */
+
+// Border styles as defined in webrender_traits/types.rs
+#define BORDER_STYLE_NONE         0
+#define BORDER_STYLE_SOLID        1
+#define BORDER_STYLE_DOUBLE       2
+#define BORDER_STYLE_DOTTED       3
+#define BORDER_STYLE_DASHED       4
+#define BORDER_STYLE_HIDDEN       5
+#define BORDER_STYLE_GROOVE       6
+#define BORDER_STYLE_RIDGE        7
+#define BORDER_STYLE_INSET        8
+#define BORDER_STYLE_OUTSET       9
+
+void discard_pixels_in_rounded_borders(vec2 local_pos) {
+  float distanceFromRef = distance(vRefPoint, local_pos);
+  if (vRadii.x > 0.0 && (distanceFromRef > vRadii.x || distanceFromRef < vRadii.z)) {
+      discard;
+  }
+}
+
+vec4 get_fragment_color(float distanceFromMixLine, float pixelsPerFragment) {
+  // Here we are mixing between the two border colors. We need to convert
+  // distanceFromMixLine it to pixel space to properly anti-alias and then push
+  // it between the limits accepted by `mix`.
+  float colorMix = min(max(distanceFromMixLine / pixelsPerFragment, -0.5), 0.5) + 0.5;
+  return mix(vHorizontalColor, vVerticalColor, colorMix);
+}
+
+float alpha_for_solid_border(float distance_from_ref,
+                             float inner_radius,
+                             float outer_radius,
+                             float pixels_per_fragment) {
+  // We want to start anti-aliasing one pixel in from the border.
+  float nudge = pixels_per_fragment;
+  inner_radius += nudge;
+  outer_radius -= nudge;
+
+  if (distance_from_ref < outer_radius && distance_from_ref > inner_radius) {
+    return 1.0;
+  }
+
+  float distance_from_border = max(distance_from_ref - outer_radius,
+                                   inner_radius - distance_from_ref);
+
+  // Move the distance back into pixels.
+  distance_from_border /= pixels_per_fragment;
+
+  // Apply a more gradual fade out to transparent.
+  // distance_from_border -= 0.5;
+
+  return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
+float alpha_for_solid_border_corner(vec2 local_pos,
+                                    float inner_radius,
+                                    float outer_radius,
+                                    float pixels_per_fragment) {
+  float distance_from_ref = distance(vRefPoint, local_pos);
+  return alpha_for_solid_border(distance_from_ref, inner_radius, outer_radius, pixels_per_fragment);
+}
+
+vec4 draw_dotted_edge(vec2 local_pos, vec4 piece_rect, float pixels_per_fragment) {
+  // We don't use pixels_per_fragment here, since it can change along the edge
+  // of a transformed border edge. We want this calculation to be consistent
+  // across the entire edge so that the positioning of the dots stays the same.
+  float two_pixels = 2.0 * length(fwidth(vLocalPos.xy));
+
+  // Circle diameter is stroke width, minus a couple pixels to account for anti-aliasing.
+  float circle_diameter = max(piece_rect.z - two_pixels, min(piece_rect.z, two_pixels));
+
+  // We want to spread the circles across the edge, but keep one circle diameter at the end
+  // reserved for two half-circles which connect to the corners.
+  float edge_available = piece_rect.w - (circle_diameter * 2.0);
+  float number_of_circles = floor(edge_available / (circle_diameter * 2.0));
+
+  // Here we are initializing the distance from the y coordinate of the center of the circle to
+  // the closest end half-circle.
+  vec2 relative_pos = local_pos - piece_rect.xy;
+  float y_distance = min(relative_pos.y, piece_rect.w - relative_pos.y);
+
+  if (number_of_circles > 0.0) {
+    // Spread the circles throughout the edge, to distribute the extra space evenly. We want
+    // to ensure that we have at last two pixels of space for each circle so that they aren't
+    // touching.
+    float space_for_each_circle = ceil(max(edge_available / number_of_circles, two_pixels));
+
+    float first_half_circle_space = circle_diameter;
+
+    float circle_index = (relative_pos.y - first_half_circle_space) / space_for_each_circle;
+    circle_index = floor(clamp(circle_index, 0.0, number_of_circles - 1.0));
+
+    float circle_y_pos =
+      circle_index * space_for_each_circle + (space_for_each_circle / 2.0) + circle_diameter;
+    y_distance = min(abs(circle_y_pos - relative_pos.y), y_distance);
+  }
+
+  float distance_from_circle_center = length(vec2(relative_pos.x - (piece_rect.z / 2.0), y_distance));
+  float distance_from_circle_edge = distance_from_circle_center - (circle_diameter / 2.0);
+
+  // Don't anti-alias if the circle diameter is small to avoid a blur of color.
+  if (circle_diameter < two_pixels && distance_from_circle_edge > 0.0)
+    return vec4(0.0);
+
+  // Move the distance back into pixels.
+  distance_from_circle_edge /= pixels_per_fragment;
+
+  float alpha = 1.0 - smoothstep(0.0, 1.0, min(1.0, max(0.0, distance_from_circle_edge)));
+  return vHorizontalColor * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_dashed_edge(float position, float border_width, float pixels_per_fragment) {
+  // TODO: Investigate exactly what FF does.
+  float size = border_width * 3.0;
+  float segment = floor(position / size);
+
+  float alpha = alpha_for_solid_border(position,
+                                       segment * size,
+                                       (segment + 1.0) * size,
+                                       pixels_per_fragment);
+
+  if (mod(segment + 2.0, 2.0) == 0.0) {
+    return vHorizontalColor * vec4(1.0, 1.0, 1.0, 1.0 - alpha);
+  } else {
+    return vHorizontalColor * vec4(1.0, 1.0, 1.0, alpha);
+  }
+}
+
+void draw_dashed_or_dotted_border(vec2 local_pos, float distance_from_mix_line) {
+  // This is the conversion factor for transformations and device pixel scaling.
+  float pixels_per_fragment = length(fwidth(local_pos.xy));
+
+  switch (vBorderPart) {
+    // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT:
+    {
+      oFragColor = get_fragment_color(distance_from_mix_line, pixels_per_fragment);
+      if (vRadii.x > 0.0) {
+        oFragColor *= vec4(1.0, 1.0, 1.0, alpha_for_solid_border_corner(local_pos,
+                                                                  vRadii.z,
+                                                                  vRadii.x,
+                                                                  pixels_per_fragment));
+      }
+
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP: {
+      if (vBorderStyle == BORDER_STYLE_DASHED) {
+        oFragColor = draw_dashed_edge(vLocalPos.x - vPieceRect.x,
+                                      vPieceRect.w,
+                                      pixels_per_fragment);
+      } else {
+        oFragColor = draw_dotted_edge(local_pos.yx, vPieceRect.yxwz, pixels_per_fragment);
+      }
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT:
+    {
+      if (vBorderStyle == BORDER_STYLE_DASHED) {
+        oFragColor = draw_dashed_edge(vLocalPos.y - vPieceRect.y,
+                                      vPieceRect.z,
+                                      pixels_per_fragment);
+      } else {
+        oFragColor = draw_dotted_edge(local_pos.xy, vPieceRect.xyzw, pixels_per_fragment);
+      }
+      break;
+    }
+  }
+}
+
+vec4 draw_double_edge(float pos,
+                      float len,
+                      float distance_from_mix_line,
+                      float pixels_per_fragment) {
+  float total_border_width = len;
+  float one_third_width = total_border_width / 3.0;
+
+  // Contribution of the outer border segment.
+  float alpha = alpha_for_solid_border(pos,
+                                       total_border_width - one_third_width,
+                                       total_border_width,
+                                       pixels_per_fragment);
+
+  // Contribution of the inner border segment.
+  alpha += alpha_for_solid_border(pos, 0.0, one_third_width, pixels_per_fragment);
+  return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_double_edge_vertical(vec2 local_pos,
+                               float distance_from_mix_line,
+                               float pixels_per_fragment) {
+  // Get our position within this specific segment
+  float position = local_pos.x - vLocalRect.x;
+  return draw_double_edge(position, vLocalRect.z, distance_from_mix_line, pixels_per_fragment);
+}
+
+vec4 draw_double_edge_horizontal(vec2 local_pos,
+                                 float distance_from_mix_line,
+                                 float pixels_per_fragment) {
+  // Get our position within this specific segment
+  float position = local_pos.y - vLocalRect.y;
+  return draw_double_edge(position, vLocalRect.w, distance_from_mix_line, pixels_per_fragment);
+}
+
+vec4 draw_double_edge_corner_with_radius(vec2 local_pos,
+                                         float distance_from_mix_line,
+                                         float pixels_per_fragment) {
+  float total_border_width = vRadii.x - vRadii.z;
+  float one_third_width = total_border_width / 3.0;
+
+  // Contribution of the outer border segment.
+  float alpha = alpha_for_solid_border_corner(local_pos,
+                                              vRadii.x - one_third_width,
+                                              vRadii.x,
+                                              pixels_per_fragment);
+
+  // Contribution of the inner border segment.
+  alpha += alpha_for_solid_border_corner(local_pos,
+                                         vRadii.z,
+                                         vRadii.z + one_third_width,
+                                         pixels_per_fragment);
+  return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
+}
+
+vec4 draw_double_edge_corner(vec2 local_pos,
+                             float distance_from_mix_line,
+                             float pixels_per_fragment) {
+  if (vRadii.x > 0.0) {
+      return draw_double_edge_corner_with_radius(local_pos,
+                                                 distance_from_mix_line,
+                                                 pixels_per_fragment);
+  }
+
+  bool is_vertical = (vBorderPart == PST_TOP_LEFT) ? distance_from_mix_line < 0.0 :
+                                                     distance_from_mix_line >= 0.0;
+  if (is_vertical) {
+    return draw_double_edge_vertical(local_pos, distance_from_mix_line, pixels_per_fragment);
+  } else {
+    return draw_double_edge_horizontal(local_pos, distance_from_mix_line, pixels_per_fragment);
+  }
+}
+
+void draw_double_border(float distance_from_mix_line, vec2 local_pos) {
+  float pixels_per_fragment = length(fwidth(local_pos.xy));
+  switch (vBorderPart) {
+    // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT:
+    {
+      oFragColor = draw_double_edge_corner(local_pos, distance_from_mix_line, pixels_per_fragment);
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP:
+    {
+      oFragColor = draw_double_edge_horizontal(local_pos,
+                                               distance_from_mix_line,
+                                               pixels_per_fragment);
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT:
+    {
+      oFragColor = draw_double_edge_vertical(local_pos,
+                                             distance_from_mix_line,
+                                             pixels_per_fragment);
+      break;
+    }
+  }
+}
+
+void draw_solid_border(float distanceFromMixLine, vec2 localPos) {
+  switch (vBorderPart) {
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT: {
+      // This is the conversion factor for transformations and device pixel scaling.
+      float pixelsPerFragment = length(fwidth(localPos.xy));
+      oFragColor = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
+
+      if (vRadii.x > 0.0) {
+        float alpha = alpha_for_solid_border_corner(localPos, vRadii.z, vRadii.x, pixelsPerFragment);
+        oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
+      }
+
+      break;
+    }
+    default:
+      oFragColor = vHorizontalColor;
+      discard_pixels_in_rounded_borders(localPos);
+  }
+}
+
+vec4 draw_mixed_edge(float distance, float border_len, vec4 color, vec2 brightness_mod) {
+  float modulator = distance / border_len > 0.5 ? brightness_mod.x : brightness_mod.y;
+  return vec4(color.xyz * modulator, color.a);
+}
+
+void draw_mixed_border(float distanceFromMixLine, float distanceFromMiddle, vec2 localPos, vec2 brightness_mod) {
+  switch (vBorderPart) {
+    case PST_TOP_LEFT:
+    case PST_TOP_RIGHT:
+    case PST_BOTTOM_LEFT:
+    case PST_BOTTOM_RIGHT: {
+      // This is the conversion factor for transformations and device pixel scaling.
+      float pixelsPerFragment = length(fwidth(localPos.xy));
+      vec4 color = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
+
+      float distance = distance(vRefPoint, localPos) - vRadii.z;
+      float length = vRadii.x - vRadii.z;
+      if (distanceFromMiddle < 0.0) {
+        distance = length - distance;
+      }
+
+      oFragColor = 0.0 <= distance && distance <= length ?
+        draw_mixed_edge(distance, length, color, brightness_mod) : vec4(0.0, 0.0, 0.0, 0.0);
+      break;
+    }
+    case PST_BOTTOM:
+    case PST_TOP: {
+      oFragColor = draw_mixed_edge(localPos.y - vPieceRect.y, vPieceRect.w, vVerticalColor, brightness_mod);
+      break;
+    }
+    case PST_LEFT:
+    case PST_RIGHT: {
+      oFragColor = draw_mixed_edge(localPos.x - vPieceRect.x, vPieceRect.z, vHorizontalColor, brightness_mod);
+      break;
+    }
+  }
+}
+
+// TODO: Investigate performance of this shader and see
+//       if it's worthwhile splitting it / removing branches etc.
+void main(void) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+#else
+    vec2 local_pos = vLocalPos;
+#endif
+
+#ifdef WR_FEATURE_TRANSFORM
+    // TODO(gw): Support other border styles for transformed elements.
+    float distance_from_mix_line = (local_pos.x - vPieceRect.x) * vPieceRect.w -
+                                   (local_pos.y - vPieceRect.y) * vPieceRect.z;
+    distance_from_mix_line /= vPieceRectHypotenuseLength;
+    float distance_from_middle = (local_pos.x - vLocalRect.x) +
+                                 (local_pos.y - vLocalRect.y) -
+                                 0.5 * (vLocalRect.z + vLocalRect.w);
+#else
+    float distance_from_mix_line = vDistanceFromMixLine;
+    float distance_from_middle = vDistanceFromMiddle;
+#endif
+
+    vec2 brightness_mod = vec2(0.7, 1.3);
+
+    // Note: we can't pass-through in the following cases,
+    // because Angle doesn't support it and fails to compile the shaders.
+    switch (vBorderStyle) {
+        case BORDER_STYLE_DASHED:
+          draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+          break;
+        case BORDER_STYLE_DOTTED:
+          draw_dashed_or_dotted_border(local_pos, distance_from_mix_line);
+          break;
+        case BORDER_STYLE_DOUBLE:
+          draw_double_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_OUTSET:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_INSET:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_SOLID:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_NONE:
+          draw_solid_border(distance_from_mix_line, local_pos);
+          break;
+        case BORDER_STYLE_GROOVE:
+          draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.yx);
+          break;
+        case BORDER_STYLE_RIDGE:
+          draw_mixed_border(distance_from_mix_line, distance_from_middle, local_pos, brightness_mod.xy);
+          break;
+        case BORDER_STYLE_HIDDEN:
+          discard;
+        default:
+          discard;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.glsl
@@ -0,0 +1,33 @@
+#line 1
+
+/* 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/. */
+
+// These are not changing.
+flat varying vec4 vVerticalColor;     // The vertical color, e.g. top/bottom
+flat varying vec4 vHorizontalColor;   // The horizontal color e.g. left/right
+flat varying vec4 vRadii;             // The border radius from CSS border-radius
+flat varying vec4 vLocalRect; // The rect of the border (x, y, w, h) in local space.
+
+// for corners, this is the beginning of the corner.
+// For the lines, this is the top left of the line.
+flat varying vec2 vRefPoint;
+flat varying int vBorderStyle;
+flat varying int vBorderPart; // Which part of the border we're drawing.
+
+flat varying vec4 vPieceRect;
+
+// These are in device space
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;     // The clamped position in local space.
+flat varying float vPieceRectHypotenuseLength;
+#else
+varying vec2 vLocalPos;     // The clamped position in local space.
+
+// These two are interpolated
+varying float vDistanceFromMixLine;  // This is the distance from the line where two colors
+                                     // meet in border corners.
+varying float vDistanceFromMiddle;   // This is the distance from the line between the top
+                                     // left corner and the bottom right.
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_border.vs.glsl
@@ -0,0 +1,226 @@
+#line 1
+/* 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/. */
+
+struct Border {
+    vec4 style;
+    vec4 widths;
+    vec4 colors[4];
+    vec4 radii[2];
+};
+
+Border fetch_border(int index) {
+    Border border;
+
+    ivec2 uv = get_fetch_uv_8(index);
+
+    border.style = texelFetchOffset(sData128, uv, 0, ivec2(0, 0));
+    border.widths = texelFetchOffset(sData128, uv, 0, ivec2(1, 0));
+    border.colors[0] = texelFetchOffset(sData128, uv, 0, ivec2(2, 0));
+    border.colors[1] = texelFetchOffset(sData128, uv, 0, ivec2(3, 0));
+    border.colors[2] = texelFetchOffset(sData128, uv, 0, ivec2(4, 0));
+    border.colors[3] = texelFetchOffset(sData128, uv, 0, ivec2(5, 0));
+    border.radii[0] = texelFetchOffset(sData128, uv, 0, ivec2(6, 0));
+    border.radii[1] = texelFetchOffset(sData128, uv, 0, ivec2(7, 0));
+
+    return border;
+}
+
+void main(void) {
+    Primitive prim = load_primitive();
+    Border border = fetch_border(prim.prim_index);
+    int sub_part = prim.sub_index;
+
+    vec2 tl_outer = prim.local_rect.xy;
+    vec2 tl_inner = tl_outer + vec2(max(border.radii[0].x, border.widths.x),
+                                    max(border.radii[0].y, border.widths.y));
+
+    vec2 tr_outer = vec2(prim.local_rect.x + prim.local_rect.z,
+                         prim.local_rect.y);
+    vec2 tr_inner = tr_outer + vec2(-max(border.radii[0].z, border.widths.z),
+                                    max(border.radii[0].w, border.widths.y));
+
+    vec2 br_outer = vec2(prim.local_rect.x + prim.local_rect.z,
+                         prim.local_rect.y + prim.local_rect.w);
+    vec2 br_inner = br_outer - vec2(max(border.radii[1].x, border.widths.z),
+                                    max(border.radii[1].y, border.widths.w));
+
+    vec2 bl_outer = vec2(prim.local_rect.x,
+                         prim.local_rect.y + prim.local_rect.w);
+    vec2 bl_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x),
+                                    -max(border.radii[1].w, border.widths.w));
+
+    vec4 segment_rect;
+    switch (sub_part) {
+        case PST_TOP_LEFT:
+            segment_rect = vec4(tl_outer, tl_inner - tl_outer);
+            vBorderStyle = int(border.style.x);
+            vHorizontalColor = border.colors[BORDER_LEFT];
+            vVerticalColor = border.colors[BORDER_TOP];
+            vRadii = vec4(border.radii[0].xy,
+                          border.radii[0].xy - border.widths.xy);
+            break;
+        case PST_TOP_RIGHT:
+            segment_rect = vec4(tr_inner.x,
+                                tr_outer.y,
+                                tr_outer.x - tr_inner.x,
+                                tr_inner.y - tr_outer.y);
+            vBorderStyle = int(border.style.y);
+            vHorizontalColor = border.colors[BORDER_TOP];
+            vVerticalColor = border.colors[BORDER_RIGHT];
+            vRadii = vec4(border.radii[0].zw,
+                          border.radii[0].zw - border.widths.zy);
+            break;
+        case PST_BOTTOM_RIGHT:
+            segment_rect = vec4(br_inner, br_outer - br_inner);
+            vBorderStyle = int(border.style.z);
+            vHorizontalColor = border.colors[BORDER_BOTTOM];
+            vVerticalColor = border.colors[BORDER_RIGHT];
+            vRadii = vec4(border.radii[1].xy,
+                          border.radii[1].xy - border.widths.zw);
+            break;
+        case PST_BOTTOM_LEFT:
+            segment_rect = vec4(bl_outer.x,
+                                bl_inner.y,
+                                bl_inner.x - bl_outer.x,
+                                bl_outer.y - bl_inner.y);
+            vBorderStyle = int(border.style.w);
+            vHorizontalColor = border.colors[BORDER_BOTTOM];
+            vVerticalColor = border.colors[BORDER_LEFT];
+            vRadii = vec4(border.radii[1].zw,
+                          border.radii[1].zw - border.widths.xw);
+            break;
+        case PST_LEFT:
+            segment_rect = vec4(tl_outer.x,
+                                tl_inner.y,
+                                border.widths.x,
+                                bl_inner.y - tl_inner.y);
+            vBorderStyle = int(border.style.x);
+            vHorizontalColor = border.colors[BORDER_LEFT];
+            vVerticalColor = border.colors[BORDER_LEFT];
+            vRadii = vec4(0.0);
+            break;
+        case PST_RIGHT:
+            segment_rect = vec4(tr_outer.x - border.widths.z,
+                                tr_inner.y,
+                                border.widths.z,
+                                br_inner.y - tr_inner.y);
+            vBorderStyle = int(border.style.z);
+            vHorizontalColor = border.colors[BORDER_RIGHT];
+            vVerticalColor = border.colors[BORDER_RIGHT];
+            vRadii = vec4(0.0);
+            break;
+        case PST_BOTTOM:
+            segment_rect = vec4(bl_inner.x,
+                                bl_outer.y - border.widths.w,
+                                br_inner.x - bl_inner.x,
+                                border.widths.w);
+            vBorderStyle = int(border.style.w);
+            vHorizontalColor = border.colors[BORDER_BOTTOM];
+            vVerticalColor = border.colors[BORDER_BOTTOM];
+            vRadii = vec4(0.0);
+            break;
+        case PST_TOP:
+            segment_rect = vec4(tl_inner.x,
+                                tl_outer.y,
+                                tr_inner.x - tl_inner.x,
+                                border.widths.y);
+            vBorderStyle = int(border.style.y);
+            vHorizontalColor = border.colors[BORDER_TOP];
+            vVerticalColor = border.colors[BORDER_TOP];
+            vRadii = vec4(0.0);
+            break;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(segment_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalPos = vi.local_pos;
+
+    // Local space
+    vLocalRect = vi.clipped_local_rect;
+#else
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos.xy;
+
+    // Local space
+    vLocalRect = prim.local_rect;
+#endif
+
+    float x0, y0, x1, y1;
+    switch (sub_part) {
+        // These are the layer tile part PrimitivePart as uploaded by the tiling.rs
+        case PST_TOP_LEFT:
+            x0 = segment_rect.x;
+            y0 = segment_rect.y;
+            // These are width / heights
+            x1 = segment_rect.x + segment_rect.z;
+            y1 = segment_rect.y + segment_rect.w;
+
+            // The radius here is the border-radius. This is 0, so vRefPoint will
+            // just be the top left (x,y) corner.
+            vRefPoint = vec2(x0, y0) + vRadii.xy;
+            break;
+        case PST_TOP_RIGHT:
+            x0 = segment_rect.x + segment_rect.z;
+            y0 = segment_rect.y;
+            x1 = segment_rect.x;
+            y1 = segment_rect.y + segment_rect.w;
+            vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y);
+            break;
+        case PST_BOTTOM_LEFT:
+            x0 = segment_rect.x;
+            y0 = segment_rect.y + segment_rect.w;
+            x1 = segment_rect.x + segment_rect.z;
+            y1 = segment_rect.y;
+            vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y);
+            break;
+        case PST_BOTTOM_RIGHT:
+            x0 = segment_rect.x;
+            y0 = segment_rect.y;
+            x1 = segment_rect.x + segment_rect.z;
+            y1 = segment_rect.y + segment_rect.w;
+            vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y);
+            break;
+        case PST_TOP:
+        case PST_LEFT:
+        case PST_BOTTOM:
+        case PST_RIGHT:
+            vRefPoint = segment_rect.xy;
+            x0 = segment_rect.x;
+            y0 = segment_rect.y;
+            x1 = segment_rect.x + segment_rect.z;
+            y1 = segment_rect.y + segment_rect.w;
+            break;
+    }
+
+    // y1 - y0 is the height of the corner / line
+    // x1 - x0 is the width of the corner / line.
+    float width = x1 - x0;
+    float height = y1 - y0;
+
+    vBorderPart = sub_part;
+    vPieceRect = vec4(x0, y0, width, height);
+
+    // The fragment shader needs to calculate the distance from the bisecting line
+    // to properly mix border colors. For transformed borders, we calculate this distance
+    // in the fragment shader itself. For non-transformed borders, we can use the
+    // interpolator.
+#ifdef WR_FEATURE_TRANSFORM
+    vPieceRectHypotenuseLength = sqrt(pow(width, 2.0) + pow(height, 2.0));
+#else
+    vDistanceFromMixLine = (vi.local_clamped_pos.x - x0) * height -
+                           (vi.local_clamped_pos.y - y0) * width;
+    vDistanceFromMiddle = (vi.local_clamped_pos.x - vLocalRect.x) +
+                          (vi.local_clamped_pos.y - vLocalRect.y) -
+                          0.5 * (vLocalRect.z + vLocalRect.w);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.fs.glsl
@@ -0,0 +1,9 @@
+/* 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/. */
+
+void main(void) {
+    vec2 uv = min(vec2(1.0), vMirrorPoint - abs(vUv.xy - vMirrorPoint));
+    uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);
+    oFragColor = vColor * texture(sCache, vec3(uv, vUv.z));
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.glsl
@@ -0,0 +1,9 @@
+/* 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/. */
+
+flat varying vec4 vColor;
+
+varying vec3 vUv;
+flat varying vec2 vMirrorPoint;
+flat varying vec4 vCacheUvRectCoords;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_box_shadow.vs.glsl
@@ -0,0 +1,32 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    BoxShadow bs = fetch_boxshadow(prim.prim_index);
+    vec4 segment_rect = fetch_instance_geometry(prim.sub_index);
+
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    RenderTaskData child_task = fetch_render_task(prim.user_data.x);
+    vUv.z = child_task.data1.x;
+
+    // Constant offsets to inset from bilinear filtering border.
+    vec2 patch_origin = child_task.data0.xy + vec2(1.0);
+    vec2 patch_size_device_pixels = child_task.data0.zw - vec2(2.0);
+    vec2 patch_size = patch_size_device_pixels / uDevicePixelRatio;
+
+    vUv.xy = (vi.local_clamped_pos - prim.local_rect.xy) / patch_size;
+    vMirrorPoint = 0.5 * prim.local_rect.zw / patch_size;
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vCacheUvRectCoords = vec4(patch_origin, patch_origin + patch_size_device_pixels) / texture_size.xyxy;
+
+    vColor = bs.color;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.fs.glsl
@@ -0,0 +1,7 @@
+/* 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/. */
+
+void main(void) {
+    oFragColor = texture(sCache, vUv);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.glsl
@@ -0,0 +1,5 @@
+/* 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/. */
+
+varying vec3 vUv;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_cache_image.vs.glsl
@@ -0,0 +1,28 @@
+#line 1
+/* 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/. */
+
+// Draw a cached primitive (e.g. a blurred text run) from the
+// target cache to the framebuffer, applying tile clip boundaries.
+
+void main(void) {
+    Primitive prim = load_primitive();
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    RenderTaskData child_task = fetch_render_task(prim.user_data.x);
+    vUv.z = child_task.data1.x;
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 uv0 = child_task.data0.xy / texture_size;
+    vec2 uv1 = (child_task.data0.xy + child_task.data0.zw) / texture_size;
+
+    vec2 f = (vi.local_clamped_pos - prim.local_rect.xy) / prim.local_rect.zw;
+
+    vUv.xy = mix(uv0, uv1, f);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.fs.glsl
@@ -0,0 +1,7 @@
+/* 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/. */
+
+void main(void) {
+    oFragColor = vec4(1.0, 1.0, 1.0, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.glsl
@@ -0,0 +1,3 @@
+/* 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/. */
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_clear.vs.glsl
@@ -0,0 +1,14 @@
+#line 1
+
+/* 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/. */
+
+in ivec4 aClearRectangle;
+
+void main() {
+    vec4 rect = vec4(aClearRectangle);
+
+    vec4 pos = vec4(mix(rect.xy, rect.xy + rect.zw, aPosition.xy), 0, 1);
+    gl_Position = uTransform * pos;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.fs.glsl
@@ -0,0 +1,219 @@
+#line 1
+
+/* 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/. */
+
+float gauss(float x, float sigma) {
+    if (sigma == 0.0)
+        return 1.0;
+    return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma));
+}
+
+vec3 Multiply(vec3 Cb, vec3 Cs) {
+    return Cb * Cs;
+}
+
+vec3 Screen(vec3 Cb, vec3 Cs) {
+    return Cb + Cs - (Cb * Cs);
+}
+
+vec3 HardLight(vec3 Cb, vec3 Cs) {
+    vec3 m = Multiply(Cb, 2.0 * Cs);
+    vec3 s = Screen(Cb, 2.0 * Cs - 1.0);
+    vec3 edge = vec3(0.5, 0.5, 0.5);
+    return mix(m, s, step(edge, Cs));
+}
+
+// TODO: Worth doing with mix/step? Check GLSL output.
+float ColorDodge(float Cb, float Cs) {
+    if (Cb == 0.0)
+        return 0.0;
+    else if (Cs == 1.0)
+        return 1.0;
+    else
+        return min(1.0, Cb / (1.0 - Cs));
+}
+
+// TODO: Worth doing with mix/step? Check GLSL output.
+float ColorBurn(float Cb, float Cs) {
+    if (Cb == 1.0)
+        return 1.0;
+    else if (Cs == 0.0)
+        return 0.0;
+    else
+        return 1.0 - min(1.0, (1.0 - Cb) / Cs);
+}
+
+float SoftLight(float Cb, float Cs) {
+    if (Cs <= 0.5) {
+        return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
+    } else {
+        float D;
+
+        if (Cb <= 0.25)
+            D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb;
+        else
+            D = sqrt(Cb);
+
+        return Cb + (2.0 * Cs - 1.0) * (D - Cb);
+    }
+}
+
+vec3 Difference(vec3 Cb, vec3 Cs) {
+    return abs(Cb - Cs);
+}
+
+vec3 Exclusion(vec3 Cb, vec3 Cs) {
+    return Cb + Cs - 2.0 * Cb * Cs;
+}
+
+// These functions below are taken from the spec.
+// There's probably a much quicker way to implement
+// them in GLSL...
+float Sat(vec3 c) {
+    return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
+}
+
+float Lum(vec3 c) {
+    vec3 f = vec3(0.3, 0.59, 0.11);
+    return dot(c, f);
+}
+
+vec3 ClipColor(vec3 C) {
+    float L = Lum(C);
+    float n = min(C.r, min(C.g, C.b));
+    float x = max(C.r, max(C.g, C.b));
+
+    if (n < 0.0)
+        C = L + (((C - L) * L) / (L - n));
+
+    if (x > 1.0)
+        C = L + (((C - L) * (1.0 - L)) / (x - L));
+
+    return C;
+}
+
+vec3 SetLum(vec3 C, float l) {
+    float d = l - Lum(C);
+    return ClipColor(C + d);
+}
+
+void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) {
+    if (Cmax > Cmin) {
+        Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin));
+        Cmax = s;
+    } else {
+        Cmid = 0.0;
+        Cmax = 0.0;
+    }
+    Cmin = 0.0;
+}
+
+vec3 SetSat(vec3 C, float s) {
+    if (C.r <= C.g) {
+        if (C.g <= C.b) {
+            SetSatInner(C.r, C.g, C.b, s);
+        } else {
+            if (C.r <= C.b) {
+                SetSatInner(C.r, C.b, C.g, s);
+            } else {
+                SetSatInner(C.b, C.r, C.g, s);
+            }
+        }
+    } else {
+        if (C.r <= C.b) {
+            SetSatInner(C.g, C.r, C.b, s);
+        } else {
+            if (C.g <= C.b) {
+                SetSatInner(C.g, C.b, C.r, s);
+            } else {
+                SetSatInner(C.b, C.g, C.r, s);
+            }
+        }
+    }
+    return C;
+}
+
+vec3 Hue(vec3 Cb, vec3 Cs) {
+    return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb));
+}
+
+vec3 Saturation(vec3 Cb, vec3 Cs) {
+    return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb));
+}
+
+vec3 Color(vec3 Cb, vec3 Cs) {
+    return SetLum(Cs, Lum(Cb));
+}
+
+vec3 Luminosity(vec3 Cb, vec3 Cs) {
+    return SetLum(Cb, Lum(Cs));
+}
+
+void main(void) {
+    vec4 Cb = texture(sCache, vUv0);
+
+    if (vUv1.x < vUv1Rect.x ||
+        vUv1.x > vUv1Rect.z ||
+        vUv1.y < vUv1Rect.y ||
+        vUv1.y > vUv1Rect.w) {
+        oFragColor = Cb;
+        return;
+    }
+
+    vec4 Cs = texture(sCache, vUv1);
+
+    // Return yellow if none of the branches match (shouldn't happen).
+    vec4 result = vec4(1.0, 1.0, 0.0, 1.0);
+
+    switch (vOp) {
+        case 1:
+            result.rgb = Multiply(Cb.rgb, Cs.rgb);
+            break;
+        case 2:
+            result.rgb = Screen(Cb.rgb, Cs.rgb);
+            break;
+        case 3:
+            result.rgb = HardLight(Cs.rgb, Cb.rgb);        // Overlay is inverse of Hardlight
+            break;
+        case 6:
+            result.r = ColorDodge(Cb.r, Cs.r);
+            result.g = ColorDodge(Cb.g, Cs.g);
+            result.b = ColorDodge(Cb.b, Cs.b);
+            break;
+        case 7:
+            result.r = ColorBurn(Cb.r, Cs.r);
+            result.g = ColorBurn(Cb.g, Cs.g);
+            result.b = ColorBurn(Cb.b, Cs.b);
+            break;
+        case 8:
+            result.rgb = HardLight(Cb.rgb, Cs.rgb);
+            break;
+        case 9:
+            result.r = SoftLight(Cb.r, Cs.r);
+            result.g = SoftLight(Cb.g, Cs.g);
+            result.b = SoftLight(Cb.b, Cs.b);
+            break;
+        case 10:
+            result.rgb = Difference(Cb.rgb, Cs.rgb);
+            break;
+        case 11:
+            result.rgb = Exclusion(Cb.rgb, Cs.rgb);
+            break;
+        case 12:
+            result.rgb = Hue(Cb.rgb, Cs.rgb);
+            break;
+        case 13:
+            result.rgb = Saturation(Cb.rgb, Cs.rgb);
+            break;
+        case 14:
+            result.rgb = Color(Cb.rgb, Cs.rgb);
+            break;
+        case 15:
+            result.rgb = Luminosity(Cb.rgb, Cs.rgb);
+            break;
+    }
+
+    oFragColor = result;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.glsl
@@ -0,0 +1,8 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+varying vec3 vUv0;
+varying vec3 vUv1;
+flat varying vec4 vUv1Rect;
+flat varying int vOp;
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_composite.vs.glsl
@@ -0,0 +1,50 @@
+#line 1
+/* 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/. */
+
+struct Composite {
+    ivec4 src0_src1_target_id_op;
+    int z;
+};
+
+Composite fetch_composite() {
+    PrimitiveInstance pi = fetch_prim_instance();
+
+    Composite composite;
+    composite.src0_src1_target_id_op = ivec4(pi.user_data.xy,
+                                             pi.render_task_index,
+                                             pi.sub_index);
+    composite.z = pi.z;
+
+    return composite;
+}
+
+void main(void) {
+    Composite composite = fetch_composite();
+    Tile src0 = fetch_tile(composite.src0_src1_target_id_op.x);
+    Tile src1 = fetch_tile(composite.src0_src1_target_id_op.y);
+    Tile dest = fetch_tile(composite.src0_src1_target_id_op.z);
+
+    vec2 local_pos = mix(dest.screen_origin_task_origin.zw,
+                         dest.screen_origin_task_origin.zw + dest.size_target_index.xy,
+                         aPosition.xy);
+
+    vec2 texture_size = vec2(textureSize(sCache, 0));
+    vec2 st0 = src0.screen_origin_task_origin.zw / texture_size;
+    vec2 st1 = (src0.screen_origin_task_origin.zw + src0.size_target_index.xy) / texture_size;
+    vUv0 = vec3(mix(st0, st1, aPosition.xy), src0.size_target_index.z);
+
+    st0 = vec2(src1.screen_origin_task_origin.zw) / texture_size;
+    st1 = vec2(src1.screen_origin_task_origin.zw + src1.size_target_index.xy) / texture_size;
+    vec2 local_virtual_pos = mix(dest.screen_origin_task_origin.xy,
+                                 dest.screen_origin_task_origin.xy + dest.size_target_index.xy,
+                                 aPosition.xy);
+    vec2 f = (local_virtual_pos - src1.screen_origin_task_origin.xy) / src1.size_target_index.xy;
+    vUv1 = vec3(mix(st0, st1, f), src1.size_target_index.z);
+    vUv1Rect = vec4(st0, st1);
+
+    vOp = composite.src0_src1_target_id_op.w;
+
+    gl_Position = uTransform * vec4(local_pos, composite.z, 1.0);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.fs.glsl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+void main(void) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 local_pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+#else
+    float alpha = 1.0;
+    vec2 local_pos = vPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+    oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.glsl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#else
+varying vec2 vPos;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_gradient.vs.glsl
@@ -0,0 +1,72 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    Gradient gradient = fetch_gradient(prim.prim_index);
+
+    GradientStop g0 = fetch_gradient_stop(prim.sub_index + 0);
+    GradientStop g1 = fetch_gradient_stop(prim.sub_index + 1);
+
+    vec4 segment_rect;
+    switch (int(gradient.kind.x)) {
+        case GRADIENT_HORIZONTAL: {
+            float x0 = mix(gradient.start_end_point.x,
+                           gradient.start_end_point.z,
+                           g0.offset.x);
+            float x1 = mix(gradient.start_end_point.x,
+                           gradient.start_end_point.z,
+                           g1.offset.x);
+            segment_rect.yw = prim.local_rect.yw;
+            segment_rect.x = x0;
+            segment_rect.z = x1 - x0;
+            } break;
+        case GRADIENT_VERTICAL: {
+            float y0 = mix(gradient.start_end_point.y,
+                           gradient.start_end_point.w,
+                           g0.offset.x);
+            float y1 = mix(gradient.start_end_point.y,
+                           gradient.start_end_point.w,
+                           g1.offset.x);
+            segment_rect.xz = prim.local_rect.xz;
+            segment_rect.y = y0;
+            segment_rect.w = y1 - y0;
+            } break;
+    }
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(segment_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+    vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw;
+#else
+    VertexInfo vi = write_vertex(segment_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw;
+    vPos = vi.local_clamped_pos;
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    switch (int(gradient.kind.x)) {
+        case GRADIENT_HORIZONTAL:
+            vColor = mix(g0.color, g1.color, f.x);
+            break;
+        case GRADIENT_VERTICAL:
+            vColor = mix(g0.color, g1.color, f.y);
+            break;
+        case GRADIENT_ROTATED:
+            vColor = vec4(1.0, 0.0, 1.0, 1.0);
+            break;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.fs.glsl
@@ -0,0 +1,31 @@
+#line 1
+
+/* 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/. */
+
+void main(void) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+
+    // We clamp the texture coordinate calculation here to the local rectangle boundaries,
+    // which makes the edge of the texture stretch instead of repeat.
+    vec2 relative_pos_in_rect =
+         clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+#else
+    float alpha = 1.0;
+    vec2 relative_pos_in_rect = vLocalPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+
+    // We calculate the particular tile this fragment belongs to, taking into
+    // account the spacing in between tiles. We only paint if our fragment does
+    // not fall into that spacing.
+    vec2 position_in_tile = mod(relative_pos_in_rect, vStretchSize + vTileSpacing);
+    vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize);
+    alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize))));
+
+    oFragColor = vec4(1.0, 1.0, 1.0, alpha) * texture(sColor0, st);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.glsl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas.
+flat varying vec2 vTextureSize;   // Size of the image in the texture atlas.
+flat varying vec2 vTileSpacing;   // Amount of space between tiled instances of this image.
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+flat varying vec2 vStretchSize;
+#else
+varying vec2 vLocalPos;
+flat varying vec2 vStretchSize;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_image.vs.glsl
@@ -0,0 +1,39 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    Image image = fetch_image(prim.prim_index);
+    ResourceRect res = fetch_resource_rect(prim.user_data.x);
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos - vi.local_rect.p0;
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    // vUv will contain how many times this image has wrapped around the image size.
+    vec2 texture_size = vec2(textureSize(sColor0, 0));
+    vec2 st0 = res.uv_rect.xy / texture_size;
+    vec2 st1 = res.uv_rect.zw / texture_size;
+
+    vTextureSize = st1 - st0;
+    vTextureOffset = st0;
+    vTileSpacing = image.stretch_size_and_tile_spacing.zw;
+    vStretchSize = image.stretch_size_and_tile_spacing.xy;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.fs.glsl
@@ -0,0 +1,67 @@
+/* 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/. */
+
+float offset(int index) {
+    return vOffsets[index / 4][index % 4];
+}
+
+float linearStep(float lo, float hi, float x) {
+    float d = hi - lo;
+    float v = x - lo;
+    if (d != 0.0) {
+        v /= d;
+    }
+    return clamp(v, 0.0, 1.0);
+}
+
+void main(void) {
+    vec2 cd = vEndCenter - vStartCenter;
+    vec2 pd = vPos - vStartCenter;
+    float rd = vEndRadius - vStartRadius;
+
+    // Solve for t in length(t * cd - pd) = vStartRadius + t * rd
+    // using a quadratic equation in form of At^2 - 2Bt + C = 0
+    float A = dot(cd, cd) - rd * rd;
+    float B = dot(pd, cd) + vStartRadius * rd;
+    float C = dot(pd, pd) - vStartRadius * vStartRadius;
+
+    float x;
+    if (A == 0.0) {
+        // Since A is 0, just solve for -2Bt + C = 0
+        if (B == 0.0) {
+            discard;
+        }
+        float t = 0.5 * C / B;
+        if (vStartRadius + rd * t >= 0.0) {
+            x = t;
+        } else {
+            discard;
+        }
+    } else {
+        float discr = B * B - A * C;
+        if (discr < 0.0) {
+            discard;
+        }
+        discr = sqrt(discr);
+        float t0 = (B + discr) / A;
+        float t1 = (B - discr) / A;
+        if (vStartRadius + rd * t0 >= 0.0) {
+            x = t0;
+        } else if (vStartRadius + rd * t1 >= 0.0) {
+            x = t1;
+        } else {
+            discard;
+        }
+    }
+
+    oFragColor = mix(vColors[0],
+                     vColors[1],
+                     linearStep(offset(0), offset(1), x));
+
+    for (int i=1 ; i < vStopCount-1 ; ++i) {
+        oFragColor = mix(oFragColor,
+                         vColors[i+1],
+                         linearStep(offset(i), offset(i+1), x));
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.glsl
@@ -0,0 +1,12 @@
+/* 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/. */
+
+flat varying int vStopCount;
+flat varying vec2 vStartCenter;
+flat varying vec2 vEndCenter;
+flat varying float vStartRadius;
+flat varying float vEndRadius;
+varying vec2 vPos;
+flat varying vec4 vColors[MAX_STOPS_PER_RADIAL_GRADIENT];
+flat varying vec4 vOffsets[MAX_STOPS_PER_RADIAL_GRADIENT/4];
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_radial_gradient.vs.glsl
@@ -0,0 +1,35 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    RadialGradient gradient = fetch_radial_gradient(prim.prim_index);
+
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+
+    vStopCount = int(prim.user_data.x);
+    vPos = vi.local_clamped_pos;
+
+    // Snap the start/end points to device pixel units.
+    // I'm not sure this is entirely correct, but the
+    // old render path does this, and it is needed to
+    // make the angle gradient ref tests pass. It might
+    // be better to fix this higher up in DL construction
+    // and not snap here?
+    vStartCenter = floor(0.5 + gradient.start_end_center.xy * uDevicePixelRatio) / uDevicePixelRatio;
+    vEndCenter = floor(0.5 + gradient.start_end_center.zw * uDevicePixelRatio) / uDevicePixelRatio;
+    vStartRadius = gradient.start_end_radius.x;
+    vEndRadius = gradient.start_end_radius.y;
+
+    for (int i=0 ; i < vStopCount ; ++i) {
+        GradientStop stop = fetch_gradient_stop(prim.sub_index + i);
+        vColors[i] = stop.color;
+        vOffsets[i/4][i%4] = stop.offset.x;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.fs.glsl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+void main(void) {
+    float alpha = 1.0;
+#ifdef WR_FEATURE_TRANSFORM
+    alpha = 0.0;
+    init_transform_fs(vLocalPos, vLocalRect, alpha);
+#endif
+
+#ifdef WR_FEATURE_CLIP
+    alpha = min(alpha, do_clip());
+#endif
+    oFragColor = vColor * vec4(1.0, 1.0, 1.0, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.glsl
@@ -0,0 +1,10 @@
+/* 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/. */
+
+varying vec4 vColor;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_rectangle.vs.glsl
@@ -0,0 +1,29 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    Rectangle rect = fetch_rectangle(prim.prim_index);
+    vColor = rect.color;
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+#endif
+
+#ifdef WR_FEATURE_CLIP
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.fs.glsl
@@ -0,0 +1,20 @@
+/* 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/. */
+
+void main(void) {
+#ifdef WR_FEATURE_SUBPIXEL_AA
+    //note: the blend mode is not compatible with clipping
+    oFragColor = texture(sColor0, vUv);
+#else
+    float alpha = texture(sColor0, vUv).a;
+#ifdef WR_FEATURE_TRANSFORM
+    float a = 0.0;
+    init_transform_fs(vLocalPos, vLocalRect, a);
+    alpha *= a;
+#endif
+    vec4 color = vColor;
+    alpha = min(alpha, do_clip());
+    oFragColor = vec4(vColor.rgb, vColor.a * alpha);
+#endif
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.glsl
@@ -0,0 +1,11 @@
+/* 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/. */
+
+flat varying vec4 vColor;
+varying vec2 vUv;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_text_run.vs.glsl
@@ -0,0 +1,40 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+    TextRun text = fetch_text_run(prim.prim_index);
+    Glyph glyph = fetch_glyph(prim.sub_index);
+    ResourceRect res = fetch_resource_rect(prim.user_data.x);
+
+    vec4 local_rect = vec4(glyph.offset.xy, (res.uv_rect.zw - res.uv_rect.xy) / uDevicePixelRatio);
+
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+    vec2 f = (vi.local_pos.xy / vi.local_pos.z - local_rect.xy) / local_rect.zw;
+#else
+    VertexInfo vi = write_vertex(local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0);
+#endif
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+    vec2 texture_size = vec2(textureSize(sColor0, 0));
+    vec2 st0 = res.uv_rect.xy / texture_size;
+    vec2 st1 = res.uv_rect.zw / texture_size;
+
+    vColor = text.color;
+    vUv = mix(st0, st1, f);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.fs.glsl
@@ -0,0 +1,33 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+#ifdef WR_FEATURE_TRANSFORM
+    float alpha = 0.0;
+    vec2 pos = init_transform_fs(vLocalPos, vLocalRect, alpha);
+
+    // We clamp the texture coordinate calculation here to the local rectangle boundaries,
+    // which makes the edge of the texture stretch instead of repeat.
+    vec2 relative_pos_in_rect =
+         clamp(pos, vLocalRect.xy, vLocalRect.xy + vLocalRect.zw) - vLocalRect.xy;
+#else
+    float alpha = 1.0;;
+    vec2 relative_pos_in_rect = vLocalPos;
+#endif
+
+    alpha = min(alpha, do_clip());
+
+    vec2 st_y = vTextureOffsetY + relative_pos_in_rect / vStretchSize * vTextureSizeY;
+    vec2 st_u = vTextureOffsetU + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
+    vec2 st_v = vTextureOffsetV + relative_pos_in_rect / vStretchSize * vTextureSizeUv;
+
+    float y = texture(sColor0, st_y).r;
+    float u = texture(sColor1, st_u).r;
+    float v = texture(sColor2, st_v).r;
+
+    // See the vertex shader for an explanation of where the constants come from.
+    vec3 rgb = vYuvColorMatrix * vec3(y - 0.06275, u - 0.50196, v - 0.50196);
+    oFragColor = vec4(rgb, alpha);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.glsl
@@ -0,0 +1,19 @@
+/* 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/. */
+
+flat varying vec2 vTextureOffsetY; // Offset of the y plane into the texture atlas.
+flat varying vec2 vTextureOffsetU; // Offset of the u plane into the texture atlas.
+flat varying vec2 vTextureOffsetV; // Offset of the v plane into the texture atlas.
+flat varying vec2 vTextureSizeY;   // Size of the y plane in the texture atlas.
+flat varying vec2 vTextureSizeUv;  // Size of the u and v planes in the texture atlas.
+flat varying vec2 vStretchSize;
+
+flat varying mat3 vYuvColorMatrix;
+
+#ifdef WR_FEATURE_TRANSFORM
+varying vec3 vLocalPos;
+flat varying vec4 vLocalRect;
+#else
+varying vec2 vLocalPos;
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/ps_yuv_image.vs.glsl
@@ -0,0 +1,77 @@
+#line 1
+/* 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/. */
+
+void main(void) {
+    Primitive prim = load_primitive();
+#ifdef WR_FEATURE_TRANSFORM
+    TransformVertexInfo vi = write_transform_vertex(prim.local_rect,
+                                                    prim.local_clip_rect,
+                                                    prim.z,
+                                                    prim.layer,
+                                                    prim.tile);
+    vLocalRect = vi.clipped_local_rect;
+    vLocalPos = vi.local_pos;
+#else
+    VertexInfo vi = write_vertex(prim.local_rect,
+                                 prim.local_clip_rect,
+                                 prim.z,
+                                 prim.layer,
+                                 prim.tile);
+    vLocalPos = vi.local_clamped_pos - vi.local_rect.p0;
+#endif
+
+    YuvImage image = fetch_yuv_image(prim.prim_index);
+
+    vec2 y_texture_size = vec2(textureSize(sColor0, 0));
+    vec2 y_st0 = image.y_st_rect.xy / y_texture_size;
+    vec2 y_st1 = image.y_st_rect.zw / y_texture_size;
+
+    vTextureSizeY = y_st1 - y_st0;
+    vTextureOffsetY = y_st0;
+
+    vec2 uv_texture_size = vec2(textureSize(sColor1, 0));
+    vec2 u_st0 = image.u_st_rect.xy / uv_texture_size;
+    vec2 u_st1 = image.u_st_rect.zw / uv_texture_size;
+
+    vec2 v_st0 = image.v_st_rect.xy / uv_texture_size;
+    vec2 v_st1 = image.v_st_rect.zw / uv_texture_size;
+
+    // This assumes the U and V surfaces have the same size.
+    vTextureSizeUv = u_st1 - u_st0;
+    vTextureOffsetU = u_st0;
+    vTextureOffsetV = v_st0;
+
+    vStretchSize = image.size;
+
+    // The constants added to the Y, U and V components are applied in the fragment shader.
+    if (image.color_space == YUV_REC601) {
+        // From Rec601:
+        // [R]   [1.1643835616438356,  0.0,                 1.5960267857142858   ]   [Y -  16]
+        // [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708   ] x [U - 128]
+        // [B]   [1.1643835616438356,  2.017232142857143,   8.862867620416422e-17]   [V - 128]
+        //
+        // For the range [0,1] instead of [0,255].
+        vYuvColorMatrix = mat3(
+            1.16438,  0.0,      1.59603,
+            1.16438, -0.39176, -0.81297,
+            1.16438,  2.01723,  0.0
+        );
+    } else { // if (image.color_space == YUV_REC709)
+        // From Rec709:
+        // [R]   [1.1643835616438356,  4.2781193979771426e-17, 1.7927410714285714]   [Y -  16]
+        // [G] = [1.1643835616438358, -0.21324861427372963,   -0.532909328559444 ] x [U - 128]
+        // [B]   [1.1643835616438356,  2.1124017857142854,     0.0               ]   [V - 128]
+        //
+        // For the range [0,1] instead of [0,255]:
+        vYuvColorMatrix = mat3(
+            1.16438,  0.0,      1.79274,
+            1.16438, -0.21325, -0.53291,
+            1.16438,  2.11240,  0.0
+        );
+    }
+
+    write_clip(vi.global_clamped_pos, prim.clip_area);
+
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/shared.glsl
@@ -0,0 +1,51 @@
+/* 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/. */
+
+//======================================================================================
+// Vertex shader attributes and uniforms
+//======================================================================================
+#ifdef WR_VERTEX_SHADER
+    #define varying out
+
+    // Uniform inputs
+    uniform mat4 uTransform;       // Orthographic projection
+    uniform float uDevicePixelRatio;
+
+    // Attribute inputs
+    in vec3 aPosition;
+#endif
+
+//======================================================================================
+// Fragment shader attributes and uniforms
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+    precision highp float;
+
+    #define varying in
+
+    // Uniform inputs
+
+    // Fragment shader outputs
+    out vec4 oFragColor;
+#endif
+
+//======================================================================================
+// Shared shader uniforms
+//======================================================================================
+uniform sampler2D sColor0;
+uniform sampler2D sColor1;
+uniform sampler2D sColor2;
+uniform sampler2D sMask;
+
+//======================================================================================
+// Interpolator definitions
+//======================================================================================
+
+//======================================================================================
+// VS only types and UBOs
+//======================================================================================
+
+//======================================================================================
+// VS only functions
+//======================================================================================
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/res/shared_other.glsl
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//======================================================================================
+// Vertex shader attributes and uniforms
+//======================================================================================
+#ifdef WR_VERTEX_SHADER
+#endif
+
+//======================================================================================
+// Fragment shader attributes and uniforms
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+#endif
+
+//======================================================================================
+// Interpolator definitions
+//======================================================================================
+
+//======================================================================================
+// VS only types and UBOs
+//======================================================================================
+
+//======================================================================================
+// VS only functions
+//======================================================================================
+
+//======================================================================================
+// FS only functions
+//======================================================================================
+#ifdef WR_FRAGMENT_SHADER
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/batch_builder.rs
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::f32;
+use webrender_traits::{ColorF, BorderStyle};
+use webrender_traits::{BorderSide};
+
+//const BORDER_DASH_SIZE: f32 = 3.0;
+
+pub trait BorderSideHelpers {
+    fn border_color(&self,
+                    scale_factor_0: f32,
+                    scale_factor_1: f32,
+                    black_color_0: f32,
+                    black_color_1: f32) -> ColorF;
+}
+
+impl BorderSideHelpers for BorderSide {
+    fn border_color(&self,
+                    scale_factor_0: f32,
+                    scale_factor_1: f32,
+                    black_color_0: f32,
+                    black_color_1: f32) -> ColorF {
+        match self.style {
+            BorderStyle::Inset => {
+                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+                    self.color.scale_rgb(scale_factor_1)
+                } else {
+                    ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a)
+                }
+            }
+            BorderStyle::Outset => {
+                if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 {
+                    self.color.scale_rgb(scale_factor_0)
+                } else {
+                    ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a)
+                }
+            }
+            _ => self.color,
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_colors.rs
@@ -0,0 +1,158 @@
+/* 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/. */
+
+#![allow(dead_code)]
+
+use webrender_traits::ColorF;
+
+// A subset of the standard CSS colors, useful for defining GPU tag colors etc.
+
+pub const INDIGO: ColorF = ColorF { r: 0.294117647059, g: 0.0, b: 0.509803921569, a: 1.0 };
+pub const GOLD: ColorF = ColorF { r: 1.0, g: 0.843137254902, b: 0.0, a: 1.0 };
+pub const FIREBRICK: ColorF = ColorF { r: 0.698039215686, g: 0.133333333333, b: 0.133333333333, a: 1.0 };
+pub const INDIANRED: ColorF = ColorF { r: 0.803921568627, g: 0.360784313725, b: 0.360784313725, a: 1.0 };
+pub const YELLOW: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.0, a: 1.0 };
+pub const DARKOLIVEGREEN: ColorF = ColorF { r: 0.333333333333, g: 0.419607843137, b: 0.18431372549, a: 1.0 };
+pub const DARKSEAGREEN: ColorF = ColorF { r: 0.560784313725, g: 0.737254901961, b: 0.560784313725, a: 1.0 };
+pub const SLATEGREY: ColorF = ColorF { r: 0.439215686275, g: 0.501960784314, b: 0.564705882353, a: 1.0 };
+pub const DARKSLATEGREY: ColorF = ColorF { r: 0.18431372549, g: 0.309803921569, b: 0.309803921569, a: 1.0 };
+pub const MEDIUMVIOLETRED: ColorF = ColorF { r: 0.780392156863, g: 0.0823529411765, b: 0.521568627451, a: 1.0 };
+pub const MEDIUMORCHID: ColorF = ColorF { r: 0.729411764706, g: 0.333333333333, b: 0.827450980392, a: 1.0 };
+pub const CHARTREUSE: ColorF = ColorF { r: 0.498039215686, g: 1.0, b: 0.0, a: 1.0 };
+pub const MEDIUMSLATEBLUE: ColorF = ColorF { r: 0.482352941176, g: 0.407843137255, b: 0.933333333333, a: 1.0 };
+pub const BLACK: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.0, a: 1.0 };
+pub const SPRINGGREEN: ColorF = ColorF { r: 0.0, g: 1.0, b: 0.498039215686, a: 1.0 };
+pub const CRIMSON: ColorF = ColorF { r: 0.862745098039, g: 0.078431372549, b: 0.235294117647, a: 1.0 };
+pub const LIGHTSALMON: ColorF = ColorF { r: 1.0, g: 0.627450980392, b: 0.478431372549, a: 1.0 };
+pub const BROWN: ColorF = ColorF { r: 0.647058823529, g: 0.164705882353, b: 0.164705882353, a: 1.0 };
+pub const TURQUOISE: ColorF = ColorF { r: 0.250980392157, g: 0.878431372549, b: 0.81568627451, a: 1.0 };
+pub const OLIVEDRAB: ColorF = ColorF { r: 0.419607843137, g: 0.556862745098, b: 0.137254901961, a: 1.0 };
+pub const CYAN: ColorF = ColorF { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const SILVER: ColorF = ColorF { r: 0.752941176471, g: 0.752941176471, b: 0.752941176471, a: 1.0 };
+pub const SKYBLUE: ColorF = ColorF { r: 0.529411764706, g: 0.807843137255, b: 0.921568627451, a: 1.0 };
+pub const GRAY: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKTURQUOISE: ColorF = ColorF { r: 0.0, g: 0.807843137255, b: 0.819607843137, a: 1.0 };
+pub const GOLDENROD: ColorF = ColorF { r: 0.854901960784, g: 0.647058823529, b: 0.125490196078, a: 1.0 };
+pub const DARKGREEN: ColorF = ColorF { r: 0.0, g: 0.392156862745, b: 0.0, a: 1.0 };
+pub const DARKVIOLET: ColorF = ColorF { r: 0.580392156863, g: 0.0, b: 0.827450980392, a: 1.0 };
+pub const DARKGRAY: ColorF = ColorF { r: 0.662745098039, g: 0.662745098039, b: 0.662745098039, a: 1.0 };
+pub const LIGHTPINK: ColorF = ColorF { r: 1.0, g: 0.713725490196, b: 0.756862745098, a: 1.0 };
+pub const TEAL: ColorF = ColorF { r: 0.0, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKMAGENTA: ColorF = ColorF { r: 0.545098039216, g: 0.0, b: 0.545098039216, a: 1.0 };
+pub const LIGHTGOLDENRODYELLOW: ColorF = ColorF { r: 0.980392156863, g: 0.980392156863, b: 0.823529411765, a: 1.0 };
+pub const LAVENDER: ColorF = ColorF { r: 0.901960784314, g: 0.901960784314, b: 0.980392156863, a: 1.0 };
+pub const YELLOWGREEN: ColorF = ColorF { r: 0.603921568627, g: 0.803921568627, b: 0.196078431373, a: 1.0 };
+pub const THISTLE: ColorF = ColorF { r: 0.847058823529, g: 0.749019607843, b: 0.847058823529, a: 1.0 };
+pub const VIOLET: ColorF = ColorF { r: 0.933333333333, g: 0.509803921569, b: 0.933333333333, a: 1.0 };
+pub const NAVY: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.501960784314, a: 1.0 };
+pub const DIMGREY: ColorF = ColorF { r: 0.411764705882, g: 0.411764705882, b: 0.411764705882, a: 1.0 };
+pub const ORCHID: ColorF = ColorF { r: 0.854901960784, g: 0.439215686275, b: 0.839215686275, a: 1.0 };
+pub const BLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const GHOSTWHITE: ColorF = ColorF { r: 0.972549019608, g: 0.972549019608, b: 1.0, a: 1.0 };
+pub const HONEYDEW: ColorF = ColorF { r: 0.941176470588, g: 1.0, b: 0.941176470588, a: 1.0 };
+pub const CORNFLOWERBLUE: ColorF = ColorF { r: 0.392156862745, g: 0.58431372549, b: 0.929411764706, a: 1.0 };
+pub const DARKBLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.545098039216, a: 1.0 };
+pub const DARKKHAKI: ColorF = ColorF { r: 0.741176470588, g: 0.717647058824, b: 0.419607843137, a: 1.0 };
+pub const MEDIUMPURPLE: ColorF = ColorF { r: 0.576470588235, g: 0.439215686275, b: 0.858823529412, a: 1.0 };
+pub const CORNSILK: ColorF = ColorF { r: 1.0, g: 0.972549019608, b: 0.862745098039, a: 1.0 };
+pub const RED: ColorF = ColorF { r: 1.0, g: 0.0, b: 0.0, a: 1.0 };
+pub const BISQUE: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.76862745098, a: 1.0 };
+pub const SLATEGRAY: ColorF = ColorF { r: 0.439215686275, g: 0.501960784314, b: 0.564705882353, a: 1.0 };
+pub const DARKCYAN: ColorF = ColorF { r: 0.0, g: 0.545098039216, b: 0.545098039216, a: 1.0 };
+pub const KHAKI: ColorF = ColorF { r: 0.941176470588, g: 0.901960784314, b: 0.549019607843, a: 1.0 };
+pub const WHEAT: ColorF = ColorF { r: 0.960784313725, g: 0.870588235294, b: 0.701960784314, a: 1.0 };
+pub const DEEPSKYBLUE: ColorF = ColorF { r: 0.0, g: 0.749019607843, b: 1.0, a: 1.0 };
+pub const REBECCAPURPLE: ColorF = ColorF { r: 0.4, g: 0.2, b: 0.6, a: 1.0 };
+pub const DARKRED: ColorF = ColorF { r: 0.545098039216, g: 0.0, b: 0.0, a: 1.0 };
+pub const STEELBLUE: ColorF = ColorF { r: 0.274509803922, g: 0.509803921569, b: 0.705882352941, a: 1.0 };
+pub const ALICEBLUE: ColorF = ColorF { r: 0.941176470588, g: 0.972549019608, b: 1.0, a: 1.0 };
+pub const LIGHTSLATEGREY: ColorF = ColorF { r: 0.466666666667, g: 0.533333333333, b: 0.6, a: 1.0 };
+pub const GAINSBORO: ColorF = ColorF { r: 0.862745098039, g: 0.862745098039, b: 0.862745098039, a: 1.0 };
+pub const MEDIUMTURQUOISE: ColorF = ColorF { r: 0.282352941176, g: 0.819607843137, b: 0.8, a: 1.0 };
+pub const FLORALWHITE: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.941176470588, a: 1.0 };
+pub const CORAL: ColorF = ColorF { r: 1.0, g: 0.498039215686, b: 0.313725490196, a: 1.0 };
+pub const PURPLE: ColorF = ColorF { r: 0.501960784314, g: 0.0, b: 0.501960784314, a: 1.0 };
+pub const LIGHTGREY: ColorF = ColorF { r: 0.827450980392, g: 0.827450980392, b: 0.827450980392, a: 1.0 };
+pub const LIGHTCYAN: ColorF = ColorF { r: 0.878431372549, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKSALMON: ColorF = ColorF { r: 0.913725490196, g: 0.588235294118, b: 0.478431372549, a: 1.0 };
+pub const BEIGE: ColorF = ColorF { r: 0.960784313725, g: 0.960784313725, b: 0.862745098039, a: 1.0 };
+pub const AZURE: ColorF = ColorF { r: 0.941176470588, g: 1.0, b: 1.0, a: 1.0 };
+pub const LIGHTSTEELBLUE: ColorF = ColorF { r: 0.690196078431, g: 0.76862745098, b: 0.870588235294, a: 1.0 };
+pub const OLDLACE: ColorF = ColorF { r: 0.992156862745, g: 0.960784313725, b: 0.901960784314, a: 1.0 };
+pub const GREENYELLOW: ColorF = ColorF { r: 0.678431372549, g: 1.0, b: 0.18431372549, a: 1.0 };
+pub const ROYALBLUE: ColorF = ColorF { r: 0.254901960784, g: 0.411764705882, b: 0.882352941176, a: 1.0 };
+pub const LIGHTSEAGREEN: ColorF = ColorF { r: 0.125490196078, g: 0.698039215686, b: 0.666666666667, a: 1.0 };
+pub const MISTYROSE: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.882352941176, a: 1.0 };
+pub const SIENNA: ColorF = ColorF { r: 0.627450980392, g: 0.321568627451, b: 0.176470588235, a: 1.0 };
+pub const LIGHTCORAL: ColorF = ColorF { r: 0.941176470588, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const ORANGERED: ColorF = ColorF { r: 1.0, g: 0.270588235294, b: 0.0, a: 1.0 };
+pub const NAVAJOWHITE: ColorF = ColorF { r: 1.0, g: 0.870588235294, b: 0.678431372549, a: 1.0 };
+pub const LIME: ColorF = ColorF { r: 0.0, g: 1.0, b: 0.0, a: 1.0 };
+pub const PALEGREEN: ColorF = ColorF { r: 0.596078431373, g: 0.98431372549, b: 0.596078431373, a: 1.0 };
+pub const BURLYWOOD: ColorF = ColorF { r: 0.870588235294, g: 0.721568627451, b: 0.529411764706, a: 1.0 };
+pub const SEASHELL: ColorF = ColorF { r: 1.0, g: 0.960784313725, b: 0.933333333333, a: 1.0 };
+pub const MEDIUMSPRINGGREEN: ColorF = ColorF { r: 0.0, g: 0.980392156863, b: 0.603921568627, a: 1.0 };
+pub const FUCHSIA: ColorF = ColorF { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const PAPAYAWHIP: ColorF = ColorF { r: 1.0, g: 0.937254901961, b: 0.835294117647, a: 1.0 };
+pub const BLANCHEDALMOND: ColorF = ColorF { r: 1.0, g: 0.921568627451, b: 0.803921568627, a: 1.0 };
+pub const PERU: ColorF = ColorF { r: 0.803921568627, g: 0.521568627451, b: 0.247058823529, a: 1.0 };
+pub const AQUAMARINE: ColorF = ColorF { r: 0.498039215686, g: 1.0, b: 0.83137254902, a: 1.0 };
+pub const WHITE: ColorF = ColorF { r: 1.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKSLATEGRAY: ColorF = ColorF { r: 0.18431372549, g: 0.309803921569, b: 0.309803921569, a: 1.0 };
+pub const TOMATO: ColorF = ColorF { r: 1.0, g: 0.388235294118, b: 0.278431372549, a: 1.0 };
+pub const IVORY: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.941176470588, a: 1.0 };
+pub const DODGERBLUE: ColorF = ColorF { r: 0.117647058824, g: 0.564705882353, b: 1.0, a: 1.0 };
+pub const LEMONCHIFFON: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.803921568627, a: 1.0 };
+pub const CHOCOLATE: ColorF = ColorF { r: 0.823529411765, g: 0.411764705882, b: 0.117647058824, a: 1.0 };
+pub const ORANGE: ColorF = ColorF { r: 1.0, g: 0.647058823529, b: 0.0, a: 1.0 };
+pub const FORESTGREEN: ColorF = ColorF { r: 0.133333333333, g: 0.545098039216, b: 0.133333333333, a: 1.0 };
+pub const DARKGREY: ColorF = ColorF { r: 0.662745098039, g: 0.662745098039, b: 0.662745098039, a: 1.0 };
+pub const OLIVE: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.0, a: 1.0 };
+pub const MINTCREAM: ColorF = ColorF { r: 0.960784313725, g: 1.0, b: 0.980392156863, a: 1.0 };
+pub const ANTIQUEWHITE: ColorF = ColorF { r: 0.980392156863, g: 0.921568627451, b: 0.843137254902, a: 1.0 };
+pub const DARKORANGE: ColorF = ColorF { r: 1.0, g: 0.549019607843, b: 0.0, a: 1.0 };
+pub const CADETBLUE: ColorF = ColorF { r: 0.372549019608, g: 0.619607843137, b: 0.627450980392, a: 1.0 };
+pub const MOCCASIN: ColorF = ColorF { r: 1.0, g: 0.894117647059, b: 0.709803921569, a: 1.0 };
+pub const LIMEGREEN: ColorF = ColorF { r: 0.196078431373, g: 0.803921568627, b: 0.196078431373, a: 1.0 };
+pub const SADDLEBROWN: ColorF = ColorF { r: 0.545098039216, g: 0.270588235294, b: 0.0745098039216, a: 1.0 };
+pub const GREY: ColorF = ColorF { r: 0.501960784314, g: 0.501960784314, b: 0.501960784314, a: 1.0 };
+pub const DARKSLATEBLUE: ColorF = ColorF { r: 0.282352941176, g: 0.239215686275, b: 0.545098039216, a: 1.0 };
+pub const LIGHTSKYBLUE: ColorF = ColorF { r: 0.529411764706, g: 0.807843137255, b: 0.980392156863, a: 1.0 };
+pub const DEEPPINK: ColorF = ColorF { r: 1.0, g: 0.078431372549, b: 0.576470588235, a: 1.0 };
+pub const PLUM: ColorF = ColorF { r: 0.866666666667, g: 0.627450980392, b: 0.866666666667, a: 1.0 };
+pub const AQUA: ColorF = ColorF { r: 0.0, g: 1.0, b: 1.0, a: 1.0 };
+pub const DARKGOLDENROD: ColorF = ColorF { r: 0.721568627451, g: 0.525490196078, b: 0.043137254902, a: 1.0 };
+pub const MAROON: ColorF = ColorF { r: 0.501960784314, g: 0.0, b: 0.0, a: 1.0 };
+pub const SANDYBROWN: ColorF = ColorF { r: 0.956862745098, g: 0.643137254902, b: 0.376470588235, a: 1.0 };
+pub const MAGENTA: ColorF = ColorF { r: 1.0, g: 0.0, b: 1.0, a: 1.0 };
+pub const TAN: ColorF = ColorF { r: 0.823529411765, g: 0.705882352941, b: 0.549019607843, a: 1.0 };
+pub const ROSYBROWN: ColorF = ColorF { r: 0.737254901961, g: 0.560784313725, b: 0.560784313725, a: 1.0 };
+pub const PINK: ColorF = ColorF { r: 1.0, g: 0.752941176471, b: 0.796078431373, a: 1.0 };
+pub const LIGHTBLUE: ColorF = ColorF { r: 0.678431372549, g: 0.847058823529, b: 0.901960784314, a: 1.0 };
+pub const PALEVIOLETRED: ColorF = ColorF { r: 0.858823529412, g: 0.439215686275, b: 0.576470588235, a: 1.0 };
+pub const MEDIUMSEAGREEN: ColorF = ColorF { r: 0.235294117647, g: 0.701960784314, b: 0.443137254902, a: 1.0 };
+pub const SLATEBLUE: ColorF = ColorF { r: 0.41568627451, g: 0.352941176471, b: 0.803921568627, a: 1.0 };
+pub const DIMGRAY: ColorF = ColorF { r: 0.411764705882, g: 0.411764705882, b: 0.411764705882, a: 1.0 };
+pub const POWDERBLUE: ColorF = ColorF { r: 0.690196078431, g: 0.878431372549, b: 0.901960784314, a: 1.0 };
+pub const SEAGREEN: ColorF = ColorF { r: 0.180392156863, g: 0.545098039216, b: 0.341176470588, a: 1.0 };
+pub const SNOW: ColorF = ColorF { r: 1.0, g: 0.980392156863, b: 0.980392156863, a: 1.0 };
+pub const MEDIUMBLUE: ColorF = ColorF { r: 0.0, g: 0.0, b: 0.803921568627, a: 1.0 };
+pub const MIDNIGHTBLUE: ColorF = ColorF { r: 0.0980392156863, g: 0.0980392156863, b: 0.439215686275, a: 1.0 };
+pub const PALETURQUOISE: ColorF = ColorF { r: 0.686274509804, g: 0.933333333333, b: 0.933333333333, a: 1.0 };
+pub const PALEGOLDENROD: ColorF = ColorF { r: 0.933333333333, g: 0.909803921569, b: 0.666666666667, a: 1.0 };
+pub const WHITESMOKE: ColorF = ColorF { r: 0.960784313725, g: 0.960784313725, b: 0.960784313725, a: 1.0 };
+pub const DARKORCHID: ColorF = ColorF { r: 0.6, g: 0.196078431373, b: 0.8, a: 1.0 };
+pub const SALMON: ColorF = ColorF { r: 0.980392156863, g: 0.501960784314, b: 0.447058823529, a: 1.0 };
+pub const LIGHTSLATEGRAY: ColorF = ColorF { r: 0.466666666667, g: 0.533333333333, b: 0.6, a: 1.0 };
+pub const LAWNGREEN: ColorF = ColorF { r: 0.486274509804, g: 0.988235294118, b: 0.0, a: 1.0 };
+pub const LIGHTGREEN: ColorF = ColorF { r: 0.564705882353, g: 0.933333333333, b: 0.564705882353, a: 1.0 };
+pub const LIGHTGRAY: ColorF = ColorF { r: 0.827450980392, g: 0.827450980392, b: 0.827450980392, a: 1.0 };
+pub const HOTPINK: ColorF = ColorF { r: 1.0, g: 0.411764705882, b: 0.705882352941, a: 1.0 };
+pub const LIGHTYELLOW: ColorF = ColorF { r: 1.0, g: 1.0, b: 0.878431372549, a: 1.0 };
+pub const LAVENDERBLUSH: ColorF = ColorF { r: 1.0, g: 0.941176470588, b: 0.960784313725, a: 1.0 };
+pub const LINEN: ColorF = ColorF { r: 0.980392156863, g: 0.941176470588, b: 0.901960784314, a: 1.0 };
+pub const MEDIUMAQUAMARINE: ColorF = ColorF { r: 0.4, g: 0.803921568627, b: 0.666666666667, a: 1.0 };
+pub const GREEN: ColorF = ColorF { r: 0.0, g: 0.501960784314, b: 0.0, a: 1.0 };
+pub const BLUEVIOLET: ColorF = ColorF { r: 0.541176470588, g: 0.16862745098, b: 0.886274509804, a: 1.0 };
+pub const PEACHPUFF: ColorF = ColorF { r: 1.0, g: 0.854901960784, b: 0.725490196078, a: 1.0 };
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_font_data.rs
@@ -0,0 +1,1914 @@
+/* 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/. */
+
+#[derive(Debug)]
+pub struct BakedGlyph {
+    pub x0: u32,
+    pub y0: u32,
+    pub x1: u32,
+    pub y1: u32,
+    pub xo: f32,
+    pub yo: f32,
+    pub xa: f32,
+}
+
+pub const FIRST_GLYPH_INDEX: u32 = 32;
+pub const BMP_WIDTH: u32 = 128;
+pub const BMP_HEIGHT: u32 = 128;
+pub const FONT_SIZE: u32 = 19;
+
+pub const GLYPHS: [BakedGlyph; 96] = [
+    BakedGlyph {
+        x0: 1,
+        y0: 1,
+        x1: 1,
+        y1: 1,
+        xo: 0.000000,
+        yo: 0.000000,
+        xa: 3.864407,
+    },
+    BakedGlyph {
+        x0: 2,
+        y0: 1,
+        x1: 5,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 4.644068,
+    },
+    BakedGlyph {
+        x0: 6,
+        y0: 1,
+        x1: 11,
+        y1: 6,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 6.644068,
+    },
+    BakedGlyph {
+        x0: 12,
+        y0: 1,
+        x1: 23,
+        y1: 13,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 11.067797,
+    },
+    BakedGlyph {
+        x0: 24,
+        y0: 1,
+        x1: 32,
+        y1: 17,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 33,
+        y0: 1,
+        x1: 46,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 14.084745,
+    },
+    BakedGlyph {
+        x0: 47,
+        y0: 1,
+        x1: 58,
+        y1: 14,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.983051,
+    },
+    BakedGlyph {
+        x0: 59,
+        y0: 1,
+        x1: 61,
+        y1: 6,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 4.067797,
+    },
+    BakedGlyph {
+        x0: 62,
+        y0: 1,
+        x1: 67,
+        y1: 19,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 68,
+        y0: 1,
+        x1: 72,
+        y1: 19,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 73,
+        y0: 1,
+        x1: 81,
+        y1: 8,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.000000,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 1,
+        x1: 91,
+        y1: 11,
+        xo: 0.000000,
+        yo: -10.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 1,
+        x1: 95,
+        y1: 6,
+        xo: 0.000000,
+        yo: -2.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 96,
+        y0: 1,
+        x1: 101,
+        y1: 3,
+        xo: 0.000000,
+        yo: -6.000000,
+        xa: 4.779661,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 1,
+        x1: 105,
+        y1: 4,
+        xo: 1.000000,
+        yo: -2.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 106,
+        y0: 1,
+        x1: 114,
+        y1: 19,
+        xo: -1.000000,
+        yo: -14.000000,
+        xa: 6.084746,
+    },
+    BakedGlyph {
+        x0: 115,
+        y0: 1,
+        x1: 123,
+        y1: 14,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 20,
+        x1: 6,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 7,
+        y0: 20,
+        x1: 15,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 20,
+        x1: 24,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 25,
+        y0: 20,
+        x1: 34,
+        y1: 32,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 35,
+        y0: 20,
+        x1: 43,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 44,
+        y0: 20,
+        x1: 52,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 53,
+        y0: 20,
+        x1: 61,
+        y1: 32,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 62,
+        y0: 20,
+        x1: 70,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 71,
+        y0: 20,
+        x1: 79,
+        y1: 33,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 80,
+        y0: 20,
+        x1: 83,
+        y1: 30,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 84,
+        y0: 20,
+        x1: 88,
+        y1: 32,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 4.169492,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 20,
+        x1: 98,
+        y1: 28,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 99,
+        y0: 20,
+        x1: 108,
+        y1: 26,
+        xo: 0.000000,
+        yo: -8.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 109,
+        y0: 20,
+        x1: 118,
+        y1: 28,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 119,
+        y0: 20,
+        x1: 125,
+        y1: 33,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 6.440678,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 34,
+        x1: 15,
+        y1: 49,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 15.932203,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 34,
+        x1: 27,
+        y1: 46,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.864407,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 34,
+        x1: 37,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.677966,
+    },
+    BakedGlyph {
+        x0: 38,
+        y0: 34,
+        x1: 47,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.322034,
+    },
+    BakedGlyph {
+        x0: 48,
+        y0: 34,
+        x1: 58,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.898305,
+    },
+    BakedGlyph {
+        x0: 59,
+        y0: 34,
+        x1: 67,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.406779,
+    },
+    BakedGlyph {
+        x0: 68,
+        y0: 34,
+        x1: 76,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 8.813560,
+    },
+    BakedGlyph {
+        x0: 77,
+        y0: 34,
+        x1: 86,
+        y1: 47,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.152542,
+    },
+    BakedGlyph {
+        x0: 87,
+        y0: 34,
+        x1: 97,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.728813,
+    },
+    BakedGlyph {
+        x0: 98,
+        y0: 34,
+        x1: 100,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 4.203390,
+    },
+    BakedGlyph {
+        x0: 101,
+        y0: 34,
+        x1: 108,
+        y1: 47,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.254237,
+    },
+    BakedGlyph {
+        x0: 109,
+        y0: 34,
+        x1: 118,
+        y1: 46,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.152542,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 50,
+        x1: 9,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 8.508474,
+    },
+    BakedGlyph {
+        x0: 10,
+        y0: 50,
+        x1: 23,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 14.661017,
+    },
+    BakedGlyph {
+        x0: 24,
+        y0: 50,
+        x1: 34,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 12.016949,
+    },
+    BakedGlyph {
+        x0: 35,
+        y0: 50,
+        x1: 47,
+        y1: 63,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 13.118644,
+    },
+    BakedGlyph {
+        x0: 48,
+        y0: 50,
+        x1: 57,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.033898,
+    },
+    BakedGlyph {
+        x0: 58,
+        y0: 50,
+        x1: 70,
+        y1: 66,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 13.118644,
+    },
+    BakedGlyph {
+        x0: 71,
+        y0: 50,
+        x1: 81,
+        y1: 62,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 10.474576,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 50,
+        x1: 91,
+        y1: 63,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 8.762712,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 50,
+        x1: 101,
+        y1: 62,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.288136,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 50,
+        x1: 112,
+        y1: 63,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 11.525424,
+    },
+    BakedGlyph {
+        x0: 113,
+        y0: 50,
+        x1: 124,
+        y1: 62,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.576271,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 67,
+        x1: 16,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 15.610169,
+    },
+    BakedGlyph {
+        x0: 17,
+        y0: 67,
+        x1: 27,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 10.305085,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 67,
+        x1: 38,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 39,
+        y0: 67,
+        x1: 48,
+        y1: 79,
+        xo: 0.000000,
+        yo: -12.000000,
+        xa: 9.491526,
+    },
+    BakedGlyph {
+        x0: 49,
+        y0: 67,
+        x1: 54,
+        y1: 85,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 55,
+        y0: 67,
+        x1: 63,
+        y1: 85,
+        xo: -1.000000,
+        yo: -14.000000,
+        xa: 6.084746,
+    },
+    BakedGlyph {
+        x0: 64,
+        y0: 67,
+        x1: 68,
+        y1: 85,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.254237,
+    },
+    BakedGlyph {
+        x0: 69,
+        y0: 67,
+        x1: 77,
+        y1: 74,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 78,
+        y0: 67,
+        x1: 88,
+        y1: 69,
+        xo: -1.000000,
+        yo: 2.000000,
+        xa: 8.305085,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 67,
+        x1: 93,
+        y1: 72,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 6.372881,
+    },
+    BakedGlyph {
+        x0: 94,
+        y0: 67,
+        x1: 102,
+        y1: 77,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.627119,
+    },
+    BakedGlyph {
+        x0: 103,
+        y0: 67,
+        x1: 111,
+        y1: 82,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 112,
+        y0: 67,
+        x1: 120,
+        y1: 77,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.796610,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 86,
+        x1: 10,
+        y1: 101,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 11,
+        y0: 86,
+        x1: 20,
+        y1: 96,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.288136,
+    },
+    BakedGlyph {
+        x0: 21,
+        y0: 86,
+        x1: 27,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 6.372881,
+    },
+    BakedGlyph {
+        x0: 28,
+        y0: 86,
+        x1: 37,
+        y1: 99,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.711864,
+    },
+    BakedGlyph {
+        x0: 38,
+        y0: 86,
+        x1: 46,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 47,
+        y0: 86,
+        x1: 49,
+        y1: 99,
+        xo: 1.000000,
+        yo: -13.000000,
+        xa: 4.016949,
+    },
+    BakedGlyph {
+        x0: 50,
+        y0: 86,
+        x1: 55,
+        y1: 103,
+        xo: -2.000000,
+        yo: -13.000000,
+        xa: 4.016949,
+    },
+    BakedGlyph {
+        x0: 56,
+        y0: 86,
+        x1: 64,
+        y1: 100,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 8.389831,
+    },
+    BakedGlyph {
+        x0: 65,
+        y0: 86,
+        x1: 68,
+        y1: 101,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 4.322034,
+    },
+    BakedGlyph {
+        x0: 69,
+        y0: 86,
+        x1: 82,
+        y1: 95,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 14.627119,
+    },
+    BakedGlyph {
+        x0: 83,
+        y0: 86,
+        x1: 91,
+        y1: 95,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 86,
+        x1: 101,
+        y1: 96,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.864407,
+    },
+    BakedGlyph {
+        x0: 102,
+        y0: 86,
+        x1: 110,
+        y1: 99,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 111,
+        y0: 86,
+        x1: 120,
+        y1: 99,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 9.881356,
+    },
+    BakedGlyph {
+        x0: 1,
+        y0: 104,
+        x1: 7,
+        y1: 113,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 6.338983,
+    },
+    BakedGlyph {
+        x0: 8,
+        y0: 104,
+        x1: 15,
+        y1: 114,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.254237,
+    },
+    BakedGlyph {
+        x0: 16,
+        y0: 104,
+        x1: 22,
+        y1: 117,
+        xo: 1.000000,
+        yo: -12.000000,
+        xa: 6.559322,
+    },
+    BakedGlyph {
+        x0: 23,
+        y0: 104,
+        x1: 31,
+        y1: 114,
+        xo: 1.000000,
+        yo: -9.000000,
+        xa: 9.644068,
+    },
+    BakedGlyph {
+        x0: 32,
+        y0: 104,
+        x1: 40,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.135593,
+    },
+    BakedGlyph {
+        x0: 41,
+        y0: 104,
+        x1: 54,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 13.135593,
+    },
+    BakedGlyph {
+        x0: 55,
+        y0: 104,
+        x1: 63,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.457627,
+    },
+    BakedGlyph {
+        x0: 64,
+        y0: 104,
+        x1: 72,
+        y1: 117,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 8.033898,
+    },
+    BakedGlyph {
+        x0: 73,
+        y0: 104,
+        x1: 81,
+        y1: 113,
+        xo: 0.000000,
+        yo: -9.000000,
+        xa: 7.711864,
+    },
+    BakedGlyph {
+        x0: 82,
+        y0: 104,
+        x1: 88,
+        y1: 122,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.406780,
+    },
+    BakedGlyph {
+        x0: 89,
+        y0: 104,
+        x1: 91,
+        y1: 122,
+        xo: 1.000000,
+        yo: -14.000000,
+        xa: 4.440678,
+    },
+    BakedGlyph {
+        x0: 92,
+        y0: 104,
+        x1: 97,
+        y1: 122,
+        xo: 0.000000,
+        yo: -14.000000,
+        xa: 5.406780,
+    },
+    BakedGlyph {
+        x0: 98,
+        y0: 104,
+        x1: 107,
+        y1: 108,
+        xo: 0.000000,
+        yo: -7.000000,
+        xa: 9.559322,
+    },
+    BakedGlyph {
+        x0: 108,
+        y0: 104,
+        x1: 116,
+        y1: 117,
+        xo: 0.000000,
+        yo: -13.000000,
+        xa: 8.474576,
+    },
+];
+
+pub const FONT_BITMAP: [u8; 16384] = [
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x34,0xae,0x00,0x00,0x81,0x90,0x00,0xe0,0x31,0x00,0x00,0x00,0x00,0x06,
+    0xba,0x05,0x00,0x00,0xa2,0x23,0x00,0x00,0x00,0x00,0x00,0x1a,0x0d,0x00,0x00,0x00,
+    0x00,0x16,0xb2,0xec,0xbc,0x1f,0x00,0x00,0x00,0x49,0x8c,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0d,0x9d,0xeb,0xe5,0x89,0x03,0x00,0x00,0x00,0x00,0x81,0x90,0x00,0x00,0x00,
+    0x00,0x13,0x00,0x00,0x11,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x6b,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,0x00,0x00,0x4a,0x76,0x00,
+    0x3b,0x70,0x70,0x70,0x22,0x00,0x56,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x2d,0x1e,0x00,0x00,0x18,0xac,0xea,0xd2,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x45,0xe9,0x00,0x00,0x8a,0x99,0x00,0xf6,0x2d,0x00,0x00,0x00,0x00,0x2f,
+    0xd8,0x00,0x00,0x08,0xf7,0x09,0x00,0x00,0x00,0x00,0x00,0xad,0x52,0x00,0x00,0x00,
+    0x00,0xa5,0x8f,0x0c,0x7d,0xba,0x00,0x00,0x06,0xda,0x3d,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x92,0xb9,0x20,0x28,0xd7,0x64,0x00,0x00,0x00,0x00,0x8a,0x99,0x00,0x00,0x00,
+    0x28,0xdd,0x03,0x00,0xa5,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x7f,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x80,0xaa,0x00,
+    0x54,0xa0,0xa0,0xa0,0x31,0x00,0xbb,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+    0xe0,0x34,0x00,0x0b,0xd7,0x95,0x1d,0x40,0xe1,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x45,0xe9,0x00,0x00,0x7a,0x88,0x00,0xe6,0x1c,0x00,0x00,0x00,0x00,0x60,
+    0xa8,0x00,0x00,0x34,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0xb2,0x6b,0x0b,0x00,0x00,
+    0x00,0xea,0x22,0x00,0x10,0xf7,0x05,0x00,0x73,0xab,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xd6,0x50,0x00,0x00,0x81,0x98,0x00,0x00,0x00,0x00,0x7a,0x88,0x00,0x00,0x00,
+    0xb4,0x6a,0x00,0x00,0x2e,0xe4,0x0d,0x00,0x00,0x24,0xcd,0x61,0x65,0x62,0x61,0xcd,
+    0x24,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x9b,0x83,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,
+    0xda,0x00,0x00,0x5e,0xd0,0x03,0x00,0x00,0x49,0xe6,0x04,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x44,0xe9,0x00,0x00,0x5a,0x67,0x00,0xbf,0x02,0x00,0x1b,0x86,0x86,0xc4,
+    0xc5,0x86,0x86,0xb0,0xd9,0x86,0x24,0x00,0x00,0x57,0xc9,0xea,0xd3,0xef,0x85,0x00,
+    0x00,0xed,0x1e,0x00,0x0d,0xf7,0x07,0x15,0xe8,0x21,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xbf,0x65,0x00,0x00,0xc6,0x6a,0x00,0x00,0x00,0x00,0x5a,0x67,0x00,0x00,0x47,
+    0xd7,0x04,0x00,0x00,0x00,0x9d,0x85,0x00,0x00,0x0d,0x55,0x8d,0xcc,0xcc,0x8c,0x54,
+    0x0d,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x01,0xe0,0x2e,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x96,
+    0x81,0x00,0x00,0xb7,0x80,0x00,0x00,0x00,0x04,0xf1,0x45,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x3d,0xe3,0x00,0x00,0x0f,0x12,0x00,0x21,0x00,0x00,0x13,0x5f,0x5f,0xe0,
+    0x86,0x5f,0x5f,0xc2,0x9f,0x5f,0x1a,0x00,0x16,0xf9,0x3d,0x01,0x00,0x03,0x13,0x00,
+    0x00,0xae,0x80,0x04,0x6c,0xc4,0x00,0x96,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x56,0xe2,0x1f,0x8e,0xc2,0x06,0x00,0x00,0x00,0x00,0x0f,0x12,0x00,0x00,0xc7,
+    0x4f,0x00,0x00,0x00,0x00,0x1a,0xee,0x0d,0x00,0x00,0x00,0x3b,0xb4,0xb5,0x37,0x00,
+    0x00,0x00,0x05,0x5f,0x5f,0x5f,0xd1,0x8a,0x5f,0x5f,0x3a,0x00,0x0b,0x76,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xea,
+    0x27,0x00,0x00,0xd8,0x4f,0x00,0x00,0x00,0x00,0xc2,0x67,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x35,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xf2,
+    0x16,0x00,0x00,0xc6,0x3f,0x00,0x00,0x00,0x65,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x1f,0xc7,0xef,0xd1,0x29,0x2c,0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0d,0xd1,0xfa,0x8f,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xf6,
+    0x0a,0x00,0x00,0x00,0x00,0x00,0xca,0x3b,0x00,0x00,0x23,0xec,0x3c,0x3d,0xea,0x21,
+    0x00,0x00,0x07,0x93,0x93,0x93,0xe0,0xb0,0x93,0x93,0x5a,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xcd,
+    0x00,0x00,0x00,0xf0,0x3e,0x00,0x00,0x00,0x00,0xb0,0x7f,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x25,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0xe4,
+    0x00,0x00,0x03,0xf4,0x0f,0x00,0x00,0x00,0x4d,0xec,0x20,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x06,0x00,0x00,0xba,0x63,0x07,0x82,0xc2,0x8d,0x0c,0x00,0x00,0x00,
+    0x24,0xda,0x7b,0x97,0xc2,0x0b,0x00,0x01,0xa2,0x03,0x00,0x00,0x00,0x00,0x2a,0xe1,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xa3,0x69,0x00,0x00,0x0a,0x5b,0x00,0x00,0x5d,0x0a,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0x74,
+    0x00,0x00,0x00,0xf6,0x3a,0x00,0x00,0x00,0x00,0xab,0x85,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x09,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1e,0x67,0xbe,
+    0x1e,0x1e,0x40,0xe4,0x1e,0x1e,0x08,0x00,0x01,0x96,0xf2,0x91,0x2b,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x4c,0xce,0x02,0x8c,0xb1,0x37,0xa3,0xa2,0x00,0x00,0x00,
+    0xc6,0x75,0x00,0x01,0x9c,0xbe,0x0a,0x28,0xd1,0x00,0x00,0x00,0x00,0x00,0x57,0xbc,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x7d,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xf1,0x1c,
+    0x00,0x00,0x00,0xde,0x49,0x00,0x00,0x00,0x00,0xbc,0x6d,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0xcb,0xea,0xe2,
+    0xcb,0xcb,0xe1,0xeb,0xcb,0xcb,0x37,0x00,0x00,0x00,0x2d,0x93,0xee,0xb4,0x1f,0x00,
+    0x00,0x00,0x00,0x00,0x05,0xd8,0x40,0x00,0xe2,0x2e,0x00,0x19,0xf5,0x02,0x00,0x13,
+    0xff,0x1d,0x00,0x00,0x02,0xa1,0xbb,0x94,0x7b,0x00,0x00,0x00,0x00,0x00,0x84,0x96,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x56,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xc0,0x00,
+    0x00,0x00,0x00,0xc4,0x6e,0x00,0x00,0x00,0x00,0xe2,0x53,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,0x52,
+    0x00,0x00,0x8b,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xa7,0xd7,0x04,
+    0x00,0x00,0x00,0x00,0x70,0xad,0x00,0x00,0xf2,0x15,0x00,0x06,0xf7,0x0a,0x00,0x10,
+    0xff,0x23,0x00,0x00,0x00,0x03,0xb2,0xfb,0x13,0x00,0x00,0x00,0x00,0x00,0x7e,0x9b,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb3,0x67,0x00,
+    0x00,0x00,0x00,0x77,0xb5,0x00,0x00,0x00,0x2b,0xf5,0x0f,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x33,0x8c,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe8,0x20,
+    0x00,0x00,0xbd,0x4b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xfc,0x2c,
+    0x00,0x00,0x00,0x13,0xe7,0x23,0x00,0x00,0xc1,0x5c,0x00,0x47,0xd7,0x00,0x00,0x00,
+    0xb5,0xaf,0x0d,0x00,0x0a,0x60,0xe1,0xbd,0xa5,0x01,0x00,0x00,0x00,0x00,0x51,0xc1,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x82,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xf4,0x13,0x00,
+    0x00,0x00,0x00,0x19,0xf3,0x57,0x00,0x0b,0xc0,0x98,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7f,0xfe,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1b,0xec,0x00,
+    0x00,0x01,0xee,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xef,0x0c,
+    0x00,0x00,0x00,0x94,0x8a,0x00,0x00,0x00,0x35,0xe8,0xc4,0xed,0x44,0x00,0x00,0x00,
+    0x15,0xa9,0xf1,0xdc,0xea,0xaf,0x1e,0x07,0xc7,0x73,0x00,0x00,0x00,0x00,0x24,0xe6,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xa8,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0xb3,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x3c,0xea,0xdb,0xf2,0xae,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x02,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x85,0x9b,0x61,0x52,0x6c,0xd1,0x89,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x34,0x10,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0x1b,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xf4,
+    0x0d,0x00,0x00,0x00,0x00,0x00,0xcf,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0x5a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x02,0x2c,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x69,0x8f,0xe2,0xa5,0x28,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xba,
+    0x5e,0x00,0x00,0x00,0x00,0x26,0xe9,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0xf2,0x0b,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x52,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,
+    0xe1,0x0a,0x00,0x00,0x00,0xaf,0x71,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xa6,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x46,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xa1,0x7d,0x00,0x00,0x3e,0xd9,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x4d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x1a,0xd2,0x03,0x00,0xa0,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xed,0x06,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x05,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x1a,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x28,0xb6,0x00,0x14,0x93,0xe1,0xe8,0x99,0x42,0x00,0x00,0x00,
+    0x2b,0xaa,0xea,0xf3,0xca,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2c,0xbd,
+    0x30,0x00,0x00,0x00,0x63,0xbe,0xbe,0xbe,0xbe,0x94,0x00,0x00,0x00,0x00,0x00,0x0d,
+    0x5a,0x8c,0x92,0x00,0x00,0x9e,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x3a,0x00,0x00,0x39,
+    0xbe,0xed,0xde,0x94,0x0f,0x00,0x00,0x00,0x47,0xc5,0xf0,0xce,0x62,0x00,0x00,0x00,
+    0x6a,0x88,0x00,0x00,0x00,0x6a,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x2a,0x29,0x00,0x02,0x27,0x27,0x27,0x27,0x27,0x27,0x27,0x18,0x00,0x00,0x4a,0x0a,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xd0,0xf3,0xe5,0xa3,0x17,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x36,0xe8,0xfb,0x00,0x98,0x8a,0x21,0x16,0x68,0xfb,0x1d,0x00,0x00,
+    0x3a,0x6a,0x22,0x11,0x62,0xf8,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0xd7,0xed,
+    0x41,0x00,0x00,0x00,0x8e,0x8e,0x38,0x38,0x38,0x2c,0x00,0x00,0x00,0x00,0x42,0xdd,
+    0xa9,0x5c,0x2b,0x00,0x00,0x39,0x45,0x45,0x45,0x45,0x5a,0xf1,0x24,0x00,0x25,0xef,
+    0x54,0x05,0x17,0xad,0xb3,0x00,0x00,0x3e,0xe9,0x46,0x08,0x39,0xe1,0x65,0x00,0x00,
+    0xaf,0xd8,0x00,0x00,0x00,0xaf,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x50,0xbc,
+    0xe2,0x4f,0x00,0x0a,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0xcb,0x7c,0x00,0x02,0xaa,0xe9,
+    0x8b,0x21,0x00,0x00,0x00,0x00,0x00,0x32,0x49,0x0e,0x16,0xae,0xb1,0x00,0x00,0x00,
+    0x00,0x0d,0xad,0xdf,0x61,0xfb,0x00,0x02,0x00,0x00,0x00,0x00,0xba,0x7a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xac,0x86,0x00,0x00,0x00,0x00,0x00,0x05,0xc6,0x50,0xd4,
+    0x41,0x00,0x00,0x00,0x9b,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xf1,0x36,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xae,0x71,0x00,0x00,0x7d,0xa3,
+    0x00,0x00,0x00,0x18,0xff,0x13,0x00,0xb6,0x78,0x00,0x00,0x00,0x4b,0xe0,0x04,0x00,
+    0x02,0x05,0x00,0x00,0x00,0x02,0x05,0x00,0x00,0x00,0x00,0x13,0x76,0xdf,0xbe,0x53,
+    0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,
+    0x84,0xe6,0xb1,0x45,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x46,0xeb,0x00,0x00,0x00,
+    0x00,0x01,0x58,0x08,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0xa8,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xaa,0x70,0x00,0x00,0x00,0x00,0x00,0x87,0x8a,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xad,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd0,0x54,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0xd4,0x02,0x00,0x00,0x8b,0x93,
+    0x00,0x00,0x00,0x1e,0xff,0x18,0x00,0xe2,0x4c,0x00,0x00,0x00,0x06,0xfb,0x24,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x9d,0xe9,0x94,0x2a,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x06,0x5b,0xc5,0xd6,0x4e,0x00,0x00,0x00,0x00,0x00,0x75,0xbd,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x69,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x3e,0xe4,0x1c,0x00,0x00,0x00,0x00,0x39,0xd0,0x07,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xc5,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xeb,0x04,0x01,
+    0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xcc,0x58,0x00,0x00,0x00,0x45,0xe5,
+    0x1a,0x00,0x00,0x74,0xc5,0x00,0x00,0xd2,0x80,0x00,0x00,0x00,0x00,0xe9,0x41,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xd8,0xcb,0x58,0x06,0x00,0x00,
+    0x00,0x00,0x00,0x08,0x97,0x97,0x97,0x97,0x97,0x97,0x97,0x5c,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x21,0x89,0xef,0x73,0x00,0x00,0x00,0x00,0x2b,0xe6,0x32,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x00,0x70,0xd1,0x06,0x00,0x00,
+    0x00,0x00,0x82,0xd2,0xed,0x2e,0x00,0x00,0x00,0x00,0x03,0xcd,0x3d,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0xc5,0xf6,0xe8,0xb5,0x3e,0x00,0x00,0x00,0x71,0xdc,0xc6,0xef,
+    0xf3,0xc1,0x30,0x00,0x00,0x00,0x00,0x00,0x48,0xd8,0x02,0x00,0x00,0x00,0x00,0x5c,
+    0xe9,0x8e,0x7d,0xd8,0x20,0x00,0x00,0x82,0xd4,0x1c,0x00,0x00,0x16,0xed,0x39,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x46,0xb3,0xe4,0x81,0x1b,
+    0x00,0x00,0x00,0x05,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x37,0x00,0x00,0x00,0x01,
+    0x47,0xb2,0xe5,0x81,0x1a,0x00,0x00,0x00,0x00,0x1d,0xdf,0x49,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x00,0x67,0xe2,0x1f,0x00,0x00,0x00,
+    0x00,0x00,0x25,0x4b,0x95,0xea,0x3f,0x00,0x00,0x00,0x63,0xac,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x17,0x6c,0xee,0x5c,0x00,0x00,0x94,0xb6,0x29,0x02,
+    0x1d,0x8a,0xef,0x11,0x00,0x00,0x00,0x00,0xaf,0x78,0x00,0x00,0x00,0x00,0x03,0x9e,
+    0xc5,0x6f,0xc8,0xc2,0x19,0x00,0x00,0x0c,0xab,0xfd,0xc6,0xcd,0xdb,0xff,0x17,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x8d,0xea,
+    0xab,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x71,0xda,
+    0xc7,0x5b,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x76,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x00,0x6f,0xe1,0x24,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x6a,0xe0,0x01,0x00,0x02,0xd9,0x45,0x16,0x16,0x16,0xd7,
+    0x51,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xed,0x01,0x00,0xa1,0x81,0x00,0x00,
+    0x00,0x06,0xf1,0x65,0x00,0x00,0x00,0x0d,0xf6,0x20,0x00,0x00,0x00,0x00,0x76,0xc8,
+    0x07,0x00,0x00,0x63,0xe6,0x0a,0x00,0x00,0x00,0x16,0x3b,0x26,0x3e,0xf2,0x00,0x00,
+    0x56,0x70,0x00,0x00,0x00,0x4a,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,
+    0x66,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x35,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xea,0x11,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x00,0x59,0xe6,0x23,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x18,0xff,0x1c,0x00,0x1f,0xcf,0xcf,0xcf,0xcf,0xcf,0xf7,
+    0xdc,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xff,0x20,0x00,0x64,0x92,0x00,0x00,
+    0x00,0x00,0xb4,0x81,0x00,0x00,0x00,0x5a,0xc7,0x00,0x00,0x00,0x00,0x00,0xca,0x72,
+    0x00,0x00,0x00,0x00,0xdc,0x4d,0x00,0x00,0x00,0x00,0x00,0x00,0x8d,0x9b,0x00,0x00,
+    0xbb,0xe4,0x00,0x00,0x00,0x80,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x13,0xec,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x4c,0xfc,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xfe,0x0d,0x00,0x21,0xcc,0x00,0x00,
+    0x00,0x00,0xca,0x63,0x00,0x00,0x00,0x9b,0x8e,0x00,0x00,0x00,0x00,0x00,0xca,0x5e,
+    0x00,0x00,0x00,0x00,0xce,0x54,0x00,0x00,0x00,0x00,0x00,0x41,0xed,0x18,0x00,0x00,
+    0x09,0x11,0x00,0x00,0x00,0x9b,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x6d,0xb6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x25,0x04,0x00,0x01,0x32,0xc1,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x22,0x06,0x00,0x00,0x10,0xb0,0xac,0x00,0x00,0x00,0xdd,0x5b,0x00,
+    0x00,0x4b,0xec,0x10,0x00,0x00,0x00,0xc6,0x63,0x00,0x00,0x00,0x00,0x00,0x7a,0xcb,
+    0x11,0x00,0x00,0x52,0xeb,0x14,0x00,0x00,0x03,0x22,0x88,0xda,0x4b,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x01,0xe0,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x8e,0x2b,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xfb,0x00,0x9b,0xfb,0xf6,0xf6,0xf6,0xf6,0xf6,0x21,0x00,
+    0xa4,0xf0,0xcc,0xe7,0xfd,0x9d,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,
+    0x41,0x00,0x00,0x8f,0xf2,0xce,0xd2,0xf4,0xa2,0x13,0x00,0x00,0x00,0x33,0xe0,0xd8,
+    0xcd,0xe0,0x3a,0x00,0x00,0x00,0x01,0xf1,0x38,0x00,0x00,0x00,0x00,0x00,0x04,0x91,
+    0xea,0xbe,0xcf,0xdc,0x3f,0x00,0x00,0x52,0xe1,0xbf,0x89,0x10,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x0b,0x76,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0xfe,0x70,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x17,0x39,0x2e,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x12,0x37,0x30,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x24,
+    0x28,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x0e,0x34,0x24,0x03,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1a,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x0e,0x7d,0xb2,0xdc,0xe5,0xb8,0x84,0x14,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x30,0xbd,0x15,0x00,0x00,0x00,0x00,0x00,0x45,0xb2,0xce,0xd4,
+    0xc2,0x9a,0x42,0x00,0x00,0x00,0x00,0x00,0x12,0x90,0xce,0xf7,0xea,0xb6,0x4c,0x00,
+    0x45,0xb1,0xcb,0xd0,0xb0,0x8b,0x34,0x00,0x00,0x00,0x00,0x5a,0xbe,0xbe,0xbe,0xbe,
+    0xbe,0xbe,0x3a,0x00,0x5a,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x2a,0x00,0x00,0x00,0x11,
+    0x8e,0xcb,0xf4,0xdf,0xbb,0x5f,0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0xb4,
+    0x27,0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x94,0x00,0x5a,0x81,0x00,
+    0x00,0x00,0x00,0x21,0xb7,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x54,0xe4,0x9c,0x4a,0x1d,0x13,0x45,0x8c,0xe7,0x5c,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa6,0xec,0x7f,0x00,0x00,0x00,0x00,0x00,0x79,0xc0,0x2c,0x27,
+    0x39,0x74,0xeb,0x79,0x00,0x00,0x00,0x37,0xe5,0x9f,0x43,0x16,0x29,0x63,0x62,0x00,
+    0x79,0xc1,0x31,0x2d,0x4f,0x7b,0xe7,0xa6,0x0f,0x00,0x00,0x79,0xc2,0x41,0x41,0x41,
+    0x41,0x41,0x14,0x00,0x79,0xc2,0x41,0x41,0x41,0x41,0x41,0x0e,0x00,0x00,0x37,0xe4,
+    0x9e,0x3b,0x13,0x28,0x5b,0x83,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x1b,0xda,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x39,0xeb,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0xe5,0x44,0x00,0x00,
+    0x00,0x00,0x00,0x1f,0xed,0x45,0xea,0x09,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x42,0xf4,0x06,0x00,0x08,0xd9,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x10,0xb6,0xa5,0x00,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xda,0x73,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x00,0x1b,0xd9,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x07,0xd6,0x67,0x00,0x00,0x19,0x63,0x86,0x70,0x36,0x00,0x53,0xe2,0x0e,0x00,
+    0x00,0x00,0x00,0x89,0x93,0x00,0xcb,0x61,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x1b,0xfd,0x13,0x00,0x72,0xd4,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x19,0xf0,0x4d,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x72,0xd1,0x03,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x00,
+    0x1d,0xd9,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4f,0xd4,0x02,0x00,0x3f,0xe7,0x94,0x64,0x8d,0xe1,0x00,0x00,0xc8,0x50,0x00,
+    0x00,0x00,0x08,0xea,0x29,0x00,0x60,0xc9,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x80,0xc2,0x00,0x00,0xac,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0x8d,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x81,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x22,
+    0xda,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x7b,0x99,0x00,0x05,0xdc,0x5a,0x00,0x00,0x34,0xe1,0x00,0x00,0x91,0x82,0x00,
+    0x00,0x00,0x5d,0xc5,0x00,0x00,0x0b,0xf1,0x32,0x00,0x00,0x00,0x79,0xdf,0x9c,0x9c,
+    0xa6,0xd5,0xcc,0x12,0x00,0x00,0xd7,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xbb,0x00,0x79,0xe3,0xa9,0xa9,0xa9,
+    0xa9,0x75,0x00,0x00,0x79,0xdf,0x9c,0x9c,0x9c,0x9c,0x5c,0x00,0x00,0xd7,0x5c,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0xe2,0xa4,0xa4,0xa4,0xa4,0xa4,0xa4,0xfa,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xcf,0xe6,
+    0x5b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xa7,0x70,0x00,0x2b,0xf3,0x01,0x00,0x00,0x34,0xe1,0x00,0x00,0x6c,0xab,0x00,
+    0x00,0x00,0xc1,0x64,0x00,0x00,0x00,0x99,0x97,0x00,0x00,0x00,0x79,0xcc,0x5f,0x5f,
+    0x66,0x80,0xd4,0xc1,0x0f,0x00,0xe2,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x6f,0xc6,0x00,0x79,0xc7,0x52,0x52,0x52,
+    0x52,0x39,0x00,0x00,0x79,0xcd,0x63,0x63,0x63,0x63,0x3b,0x00,0x00,0xe2,0x52,0x00,
+    0x00,0x00,0x00,0x00,0x16,0x8f,0x00,0x79,0xca,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0xf7,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xc5,0xba,
+    0xd2,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xb9,0x60,0x00,0x3d,0xe4,0x00,0x00,0x00,0x34,0xe1,0x00,0x00,0x79,0x98,0x00,
+    0x00,0x24,0xfb,0x41,0x34,0x34,0x34,0x68,0xf0,0x0a,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x08,0xce,0x80,0x00,0xbb,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x95,0x98,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x72,0x00,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x5f,0xc7,0x00,0x79,0xad,0x01,
+    0x74,0xea,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x87,0x00,0x16,0xfd,0x15,0x00,0x00,0x34,0xe1,0x00,0x00,0xb4,0x6d,0x00,
+    0x00,0x85,0xe3,0xc7,0xc7,0xc7,0xc7,0xc7,0xee,0x5e,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x00,0x89,0xb2,0x00,0x90,0xae,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x07,0xdb,0x66,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0xaf,0x00,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0xc0,0x00,0x79,0xad,0x00,
+    0x00,0x50,0xec,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x64,0xb2,0x00,0x00,0xa8,0xae,0x0e,0x00,0x3d,0xfb,0x16,0x4b,0xec,0x0f,0x00,
+    0x02,0xe2,0x46,0x00,0x00,0x00,0x00,0x00,0x7c,0xbf,0x00,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x00,0x00,0xb4,0x90,0x00,0x21,0xf5,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x86,0xce,0x06,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0xf6,0x32,
+    0x00,0x00,0x00,0x00,0x27,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xb8,0xa5,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x52,0xee,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x2a,0xf3,0x24,0x00,0x0f,0x96,0xe4,0xe3,0xc4,0xa4,0xf0,0xcd,0x33,0x00,0x00,
+    0x45,0xe5,0x03,0x00,0x00,0x00,0x00,0x00,0x21,0xfd,0x22,0x00,0x79,0xad,0x00,0x00,
+    0x00,0x21,0x8d,0xed,0x2a,0x00,0x00,0x74,0xec,0x50,0x04,0x00,0x00,0x11,0x33,0x00,
+    0x79,0xad,0x00,0x00,0x0d,0x37,0xb5,0xdf,0x27,0x00,0x00,0x79,0xad,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xec,
+    0x53,0x05,0x00,0x00,0x28,0xff,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x4f,0x28,0x00,0x04,0x48,0xf5,0x51,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x00,0x6e,0xe1,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x8a,0xbf,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xa4,0x8d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc2,0x81,0x00,0x65,0xf3,0xeb,0xe4,
+    0xef,0xe5,0x97,0x29,0x00,0x00,0x00,0x00,0x4c,0xdd,0xf5,0xd1,0xe2,0xf7,0x95,0x00,
+    0x65,0xf3,0xef,0xeb,0xf0,0xcc,0x74,0x07,0x00,0x00,0x00,0x79,0xff,0xff,0xff,0xff,
+    0xff,0xff,0xbe,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,
+    0xd9,0xf7,0xd1,0xd4,0xf2,0xd1,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0xf2,
+    0x34,0x00,0x79,0xad,0x00,0x75,0xf0,0xd8,0xe9,0xfd,0x86,0x02,0x00,0x79,0xad,0x00,
+    0x00,0x00,0x00,0x00,0xad,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x08,0xcf,0xbd,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x11,0x15,
+    0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x3a,0x30,0x0a,0x00,0x00,
+    0x00,0x02,0x10,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x10,0x34,0x24,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x30,0x33,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x07,0x78,0xeb,0xba,0x91,0x72,0x7c,0x72,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x12,0x41,0x68,0x84,0x76,0x44,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x5a,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x37,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x6e,0x77,0x00,0x00,0x5a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x7a,0x5d,0x00,0x00,0x00,0x13,0x93,0xcd,0xf3,0xd3,0x9e,0x1e,0x00,0x00,0x00,0x00,
+    0x44,0xaf,0xca,0xd3,0xbc,0x9b,0x39,0x00,0x00,0x00,0x00,0x00,0x13,0x93,0xcd,0xf3,
+    0xd3,0x9e,0x1e,0x00,0x00,0x00,0x00,0x44,0xaf,0xca,0xd3,0xbc,0x99,0x36,0x00,0x00,
+    0x00,0x00,0x00,0x09,0x63,0xab,0xee,0xed,0xb8,0x4b,0x00,0x00,0x84,0xbe,0xbe,0xbe,
+    0xbe,0xbe,0xbe,0xbe,0xbb,0x00,0x64,0x77,0x00,0x00,0x00,0x00,0x00,0x13,0xbe,0x0a,
+    0x00,0x85,0x6f,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xb1,0x34,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0xff,0xc4,0x01,0x00,0x00,
+    0x00,0x00,0x00,0x1a,0xf4,0xb2,0x00,0x00,0x79,0xff,0x78,0x00,0x00,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x00,0x3c,0xe8,0x9c,0x3f,0x16,0x39,0x8c,0xee,0x4f,0x00,0x00,0x00,
+    0x79,0xc2,0x34,0x2b,0x3d,0x7d,0xed,0x83,0x00,0x00,0x00,0x3c,0xe8,0x9c,0x3f,0x16,
+    0x39,0x8c,0xee,0x4f,0x00,0x00,0x00,0x79,0xc2,0x35,0x2b,0x3c,0x7b,0xed,0x78,0x00,
+    0x00,0x00,0x00,0x6a,0xc2,0x30,0x08,0x1e,0x5e,0x58,0x00,0x00,0x2d,0x41,0x41,0x41,
+    0xf2,0x6b,0x41,0x41,0x40,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x63,0xe1,0x01,0x00,0x00,0x00,0x00,0x00,0x3d,0xed,0x07,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0xef,0xdd,0x4e,0x00,0x00,
+    0x00,0x00,0x00,0x98,0xcd,0xc8,0x00,0x00,0x79,0xc4,0xe6,0x4b,0x00,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x09,0xdd,0x71,0x00,0x00,0x00,0x00,0x00,0x53,0xed,0x16,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x32,0xfe,0x27,0x00,0x09,0xdd,0x71,0x00,0x00,0x00,
+    0x00,0x00,0x53,0xed,0x16,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x3b,0xfd,0x1a,
+    0x00,0x00,0x02,0xd8,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x0f,0xf7,0x3a,0x00,0x00,0x00,0x00,0x00,0x95,0x98,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xd8,0x61,0xcb,0x01,0x00,
+    0x00,0x00,0x1f,0xea,0x4a,0xdd,0x00,0x00,0x79,0xa9,0x3d,0xe9,0x1f,0x00,0x00,0x00,
+    0xa4,0x7d,0x00,0x76,0xd4,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xb9,0x94,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0xdc,0x5b,0x00,0x76,0xd4,0x03,0x00,0x00,0x00,
+    0x00,0x00,0x00,0xb9,0x94,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0xeb,0x49,
+    0x00,0x00,0x09,0xfc,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0xac,0x93,0x00,0x00,0x00,0x00,0x04,0xe9,0x3c,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4e,0xc4,0x05,0xdf,0x4a,0x00,
+    0x00,0x00,0x97,0x84,0x27,0xf3,0x00,0x00,0x79,0xa9,0x00,0x79,0xc8,0x06,0x00,0x00,
+    0xa4,0x7d,0x00,0xad,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x62,0xcb,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x01,0xed,0x47,0x00,0xad,0x81,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x62,0xcb,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x09,0xf9,0x1f,
+    0x00,0x00,0x00,0xaf,0xc5,0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x4f,0xea,0x05,0x00,0x00,0x00,0x49,0xdc,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xb1,0x00,0x6a,0xc2,0x00,
+    0x00,0x18,0xed,0x15,0x14,0xff,0x09,0x00,0x79,0xa9,0x00,0x02,0xbc,0x88,0x00,0x00,
+    0xa4,0x7d,0x00,0xd8,0x5c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0xf4,0x02,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x75,0xeb,0x10,0x00,0xd8,0x5c,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x3e,0xf4,0x02,0x00,0x79,0xad,0x00,0x00,0x00,0x08,0x95,0xc4,0x00,
+    0x00,0x00,0x00,0x0e,0x9f,0xf5,0x9e,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x05,0xe8,0x4a,0x00,0x00,0x00,0xa4,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x75,0x9d,0x00,0x09,0xe8,0x3a,
+    0x00,0x88,0x92,0x00,0x03,0xfd,0x1b,0x00,0x79,0xa9,0x00,0x00,0x1b,0xea,0x3c,0x00,
+    0xa4,0x7d,0x00,0xe1,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0xfa,0x05,0x00,
+    0x79,0xd9,0x8a,0x90,0xa1,0xdb,0xda,0x38,0x00,0x00,0xe2,0x54,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x35,0xfc,0x06,0x00,0x79,0xe9,0xba,0xbd,0xc9,0xf2,0x90,0x0f,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x25,0x92,0xf2,0xa9,0x12,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x86,0xa0,0x00,0x00,0x00,0x00,0x00,0x1a,0xff,0x0d,
+    0x00,0x00,0x00,0x8c,0xa9,0x00,0x00,0x0f,0xf3,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x90,0x00,0x00,0x79,0xb0,
+    0x0d,0xea,0x1f,0x00,0x00,0xf2,0x29,0x00,0x79,0xa9,0x00,0x00,0x00,0x57,0xdc,0x0b,
+    0xa4,0x7d,0x00,0xb8,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0xd6,0x00,0x00,
+    0x79,0xd2,0x75,0x6f,0x5a,0x37,0x01,0x00,0x00,0x00,0xb9,0x77,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x59,0xdc,0x00,0x00,0x79,0xc2,0x41,0x40,0x4a,0xf0,0x40,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xc5,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x84,0xa4,0x00,0x00,0x00,0x00,0x00,0x1f,0xff,0x0b,
+    0x00,0x00,0x00,0x29,0xf7,0x12,0x00,0x66,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x85,0x00,0x00,0x10,0xf0,
+    0x96,0xa0,0x00,0x00,0x00,0xe7,0x38,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0xab,0x8a,
+    0xa4,0x7d,0x00,0x8b,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9a,0xa9,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0xb8,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x9a,0xab,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x62,0xe3,0x12,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0xfd,0x0c,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x6b,0xc2,0x00,0x00,0x00,0x00,0x00,0x3e,0xef,0x00,
+    0x00,0x00,0x00,0x00,0xbe,0x6e,0x00,0xca,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9f,0x7a,0x00,0x00,0x00,0x8e,
+    0xff,0x2d,0x00,0x00,0x00,0xdb,0x47,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x16,0xe8,
+    0xcf,0x7d,0x00,0x1d,0xf3,0x43,0x00,0x00,0x00,0x00,0x00,0x29,0xf7,0x31,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1d,0xf4,0x43,0x00,0x00,0x00,
+    0x00,0x00,0x29,0xf9,0x32,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0xb1,0xa4,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3a,0xe9,0x09,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x3e,0xf3,0x16,0x00,0x00,0x00,0x00,0x86,0xc0,0x00,
+    0x00,0x00,0x00,0x00,0x55,0xd7,0x35,0xe4,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6f,0x00,0x00,0x00,0x15,
+    0x46,0x00,0x00,0x00,0x00,0xd0,0x56,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x00,0x61,
+    0xff,0x7d,0x00,0x00,0x6b,0xf1,0x5c,0x05,0x00,0x03,0x4c,0xe9,0x84,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6d,0xf1,0x5c,0x05,0x00,
+    0x03,0x4c,0xe9,0x84,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x1b,0xf0,0x44,
+    0x00,0x00,0x15,0x47,0x02,0x00,0x00,0x15,0xb7,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x00,0xc4,0xb7,0x14,0x00,0x00,0x4f,0xf5,0x4a,0x00,
+    0x00,0x00,0x00,0x00,0x04,0xe1,0xd3,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x79,0xff,0xff,0xff,0xff,0xff,0xff,0x34,0x00,0xbb,0x64,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xc4,0x65,0x00,0x79,0xa9,0x00,0x00,0x00,0x00,0x00,0x01,
+    0xc4,0x7d,0x00,0x00,0x00,0x41,0xd4,0xf7,0xd4,0xf4,0xde,0x52,0x00,0x00,0x00,0x00,
+    0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43,0xd4,0xf7,0xd4,
+    0xf4,0xd5,0x5f,0x00,0x00,0x00,0x00,0x79,0xad,0x00,0x00,0x00,0x00,0x00,0x75,0xcc,
+    0x01,0x00,0x33,0xda,0xee,0xc9,0xd9,0xdc,0x99,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xee,0x38,0x00,0x00,0x00,0x00,0x00,0x13,0xaf,0xf6,0xd5,0xe7,0xeb,0x58,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x75,0xf7,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x35,0x15,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x94,
+    0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1b,0x38,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x32,0x1f,0x01,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,
+    0xd6,0xa9,0x37,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x0a,0x75,0xce,0xf0,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x3e,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0xb1,
+    0x00,0x18,0xba,0x29,0x00,0x00,0x00,0x00,0x07,0xac,0x40,0x00,0x77,0x85,0x00,0x00,
+    0x00,0x00,0x00,0x07,0xb2,0x32,0x00,0x06,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0xbe,0x7a,
+    0x00,0x15,0x45,0x45,0x45,0x08,0x00,0x18,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x3c,0x45,0x45,0x27,0x00,0x00,0x00,0x07,0xb1,0x65,0x00,0x00,0x00,0x00,0x12,0xcf,
+    0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0xcf,0x51,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x1c,
+    0xc9,0xea,0xe5,0xad,0x20,0x00,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x1e,0xa5,0xde,0xea,0xc5,0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x2c,0xfc,0x09,0x00,0x00,0x00,0x00,0x39,0x1d,0x00,0x00,0x00,0x00,0x62,0xc5,
+    0x00,0x00,0x81,0xc9,0x04,0x00,0x00,0x00,0x87,0xbb,0x01,0x00,0x28,0xf8,0x29,0x00,
+    0x00,0x00,0x00,0x6f,0xc4,0x01,0x00,0x02,0x41,0x41,0x41,0x41,0x41,0x49,0xe8,0x72,
+    0x00,0x4e,0xe4,0x93,0x93,0x11,0x00,0x20,0xee,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x7f,0x93,0xc8,0x8f,0x00,0x00,0x00,0x75,0xae,0xe3,0x14,0x00,0x00,0x00,0x03,0x23,
+    0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x0d,0x00,0xae,0x6d,0x00,0x00,0x00,0x00,0x09,
+    0x35,0x12,0x1b,0x8f,0xd4,0x03,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x1f,0xeb,0xb4,0x47,0x13,0x3e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x05,0xf9,0x33,0x00,0x00,0x00,0x05,0xec,0x96,0x00,0x00,0x00,0x00,0x94,0x96,
+    0x00,0x00,0x05,0xcd,0x78,0x00,0x00,0x37,0xec,0x1d,0x00,0x00,0x00,0x95,0xa9,0x00,
+    0x00,0x00,0x0c,0xe7,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa4,0xaa,0x01,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0xc4,0x51,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x14,0xe3,0x19,0x7d,0x93,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0xe0,0x76,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x05,0xef,0x2b,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xa3,0xb3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xd2,0x62,0x00,0x00,0x00,0x47,0xee,0xe7,0x02,0x00,0x00,0x00,0xc7,0x66,
+    0x00,0x00,0x00,0x2c,0xf1,0x2b,0x08,0xd6,0x5d,0x00,0x00,0x00,0x00,0x15,0xee,0x35,
+    0x00,0x00,0x81,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0xd9,0x0d,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x6b,0xab,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x92,0x7e,0x00,0x0a,0xdf,0x27,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0xc2,0x3d,0x00,0x00,0x00,
+    0x03,0x27,0x3b,0x24,0xd7,0x44,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0xe6,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x9f,0x96,0x00,0x00,0x00,0x9c,0x7a,0xe1,0x3e,0x00,0x00,0x04,0xf5,0x31,
+    0x00,0x00,0x00,0x00,0x75,0xcb,0x8e,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0xcd,
+    0x03,0x23,0xe7,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0xee,0x2f,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x16,0xf2,0x0e,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x26,0xe0,0x0b,0x00,0x00,0x61,0xb0,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x45,
+    0xde,0xd0,0xb7,0xce,0xfc,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x08,0xfe,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x6a,0xca,0x00,0x00,0x05,0xec,0x22,0x8d,0x92,0x00,0x00,0x2d,0xf5,0x05,
+    0x00,0x00,0x00,0x00,0x03,0xcb,0xf2,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc7,
+    0x6e,0xb5,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xd0,0x6d,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0xb7,0x60,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0xaf,0x62,0x00,0x00,0x00,0x02,0xd0,0x3f,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xf0,
+    0x54,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0xb6,0xa9,0xdd,0xd7,0x9c,0x15,0x00,0x00,
+    0x00,0xf0,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x34,0xf9,0x09,0x00,0x48,0xc6,0x00,0x33,0xe4,0x03,0x00,0x66,0xc3,0x00,
+    0x00,0x00,0x00,0x00,0x1e,0xeb,0xe9,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,
+    0xf4,0xc9,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x87,0xb9,0x01,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x5e,0xba,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x31,0x03,0x00,0x00,0x00,0x00,0x26,0x0d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xfc,
+    0x04,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0xdb,0x56,0x19,0x2e,0x95,0xe3,0x11,0x00,
+    0x00,0xbf,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x04,0xf0,0x41,0x00,0xa7,0x6a,0x00,0x00,0xd6,0x4a,0x00,0xa5,0x84,0x00,
+    0x00,0x00,0x00,0x02,0xbd,0x79,0x49,0xe9,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xc0,0x69,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x35,0xec,0x1c,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0xf3,0x18,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xf1,
+    0x58,0x00,0x00,0x00,0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xb4,0x83,0x00,
+    0x00,0x42,0xef,0x4c,0x01,0x00,0x0b,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0xb2,0x7f,0x12,0xef,0x12,0x00,0x00,0x76,0xaf,0x00,0xe4,0x41,0x00,
+    0x00,0x00,0x00,0x6f,0xc7,0x03,0x00,0x9b,0xb0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xcf,0x66,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x6e,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4b,
+    0xe4,0xdf,0xce,0xdb,0xf0,0x39,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x5b,0xc7,0x00,
+    0x00,0x00,0x50,0xe1,0xf1,0xda,0xee,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x6d,0xc7,0x6c,0xa2,0x00,0x00,0x00,0x17,0xf6,0x3e,0xf4,0x08,0x00,
+    0x00,0x00,0x1c,0xed,0x29,0x00,0x00,0x0f,0xe4,0x52,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xc3,0x01,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xc8,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x03,0x1f,0x2c,0x1a,0x01,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x44,0xe8,0x00,
+    0x00,0x00,0x00,0x00,0x15,0x23,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1c,0xfb,0xd9,0x3a,0x00,0x00,0x00,0x00,0xaa,0xd7,0xad,0x00,0x00,
+    0x00,0x00,0xa8,0x82,0x00,0x00,0x00,0x00,0x53,0xdf,0x09,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x12,0xec,0x32,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xef,0x23,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x80,0xcd,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xc6,0xd0,0x00,0x00,0x00,0x00,0x00,0x3e,0xff,0x5c,0x00,0x00,
+    0x00,0x40,0xe4,0x0a,0x00,0x00,0x00,0x00,0x00,0xbd,0x80,0x00,0x00,0x00,0x00,0x00,
+    0xbe,0x68,0x00,0x00,0x00,0x00,0x00,0x59,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9e,0x7d,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd3,0x96,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x44,0xd6,0x00,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x26,0x8e,0xf0,0x19,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe7,0x31,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0xf4,0xdc,0xd5,0xfd,0xc8,0x2d,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91,0x8b,0x00,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x1d,0x2d,0x0f,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xbe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x37,0xe3,0x02,0x00,
+    0x00,0x00,0x7d,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x4e,0xec,0xb6,0xb6,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xdc,0x40,0x00,
+    0x9d,0xb6,0xda,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x0b,0x23,0x23,0x23,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x10,0x00,
+    0x1e,0x23,0x23,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0c,0x00,0x00,0x00,0x24,0xae,0xe4,
+    0xa9,0x40,0x01,0x00,0x00,0x00,0x00,0x00,0x14,0x11,0x00,0x00,0x00,0x00,0x17,0x98,
+    0xd1,0xe4,0xce,0xa5,0x20,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,
+    0x14,0x00,0x00,0x00,0x00,0x14,0x14,0x00,0x02,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x02,0x0e,0x00,0x00,0x48,0xb3,0xd3,0xe5,0xa4,0x3e,0x2f,0xa4,0xdd,0xdb,0xa5,
+    0x17,0x00,0x00,0x48,0xb1,0xd2,0xe6,0xcf,0x8e,0x09,0x00,0x00,0x00,0x00,0x1b,0xa3,
+    0xdf,0xd8,0x94,0x0e,0x00,0x00,0x49,0xb7,0xd7,0xe7,0xc5,0x80,0x08,0x00,0x00,0x00,
+    0x00,0x11,0x8f,0xcb,0xe7,0xd4,0xb1,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xab,0x6c,0x00,0x00,0x1f,0xed,0x72,0x18,
+    0x55,0xd2,0x8a,0x00,0x00,0x00,0x56,0xbc,0xe7,0xec,0x4e,0x00,0x00,0x1d,0xe9,0x93,
+    0x30,0x18,0x2f,0xe3,0x41,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb6,
+    0xb6,0x00,0x00,0x00,0x00,0xb6,0xb6,0x00,0x89,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8d,0x8a,0x00,0x00,0x8a,0xab,0x24,0x18,0x43,0xe0,0xe3,0x5f,0x20,0x29,0xa4,
+    0xc8,0x00,0x00,0x8a,0xac,0x25,0x17,0x35,0xbd,0xab,0x00,0x00,0x00,0x1b,0xea,0xb6,
+    0x3e,0x4d,0xc7,0xd6,0x09,0x00,0x8a,0xac,0x25,0x1c,0x6c,0xd3,0xcf,0x07,0x00,0x00,
+    0x15,0xe3,0xc8,0x60,0x19,0x29,0xc3,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0xa5,0x8c,0x00,0x00,
+    0x00,0x46,0xf7,0x0d,0x00,0x0a,0xf1,0x45,0x03,0x01,0x04,0x00,0x00,0xa4,0xa1,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,
+    0x33,0x00,0x00,0x00,0x00,0x33,0x33,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x68,0xbf,0x00,0x00,0x00,0x11,
+    0xfb,0x1f,0x00,0x8a,0x8f,0x00,0x00,0x00,0x1d,0xfa,0x18,0x00,0x00,0x9f,0xb8,0x00,
+    0x00,0x00,0x00,0xdb,0x78,0x00,0x8a,0x8f,0x00,0x00,0x00,0x03,0xe8,0x78,0x00,0x00,
+    0x9b,0xcd,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0xe3,0x4b,0x16,0x16,
+    0x16,0x1c,0xf5,0x2f,0x00,0x4d,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xe9,0x3e,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x3d,0xe0,0x00,0x00,0x00,0x00,
+    0xe2,0x3a,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xe4,0x3a,0x00,0x00,0xe4,0x6e,0x00,
+    0x00,0x00,0x00,0x90,0xbf,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x98,0xc1,0x00,0x00,
+    0xe2,0x79,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x08,0xfe,0xdd,0xd8,0xd8,
+    0xd8,0xd8,0xd8,0x3a,0x00,0x87,0x92,0x00,0x00,0x00,0x00,0x00,0x07,0xfe,0x24,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,
+    0x6d,0x00,0x00,0x00,0x00,0x69,0x6d,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x31,0xe9,0x00,0x00,0x00,0x00,
+    0xd5,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd2,0x49,0x00,0x08,0xfe,0x2e,0x00,
+    0x00,0x00,0x00,0x50,0xe3,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x4b,0xe7,0x00,0x08,
+    0xfe,0x2d,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x22,0xa8,0xdd,0xd8,0x9d,0xc7,0x6c,0x00,0x00,0xf3,0x4f,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0xe4,0xc2,0xc2,0xc2,0x10,0x00,0x00,0xe3,0x45,0x00,
+    0x00,0x00,0x00,0xd8,0x41,0x00,0x8a,0xcf,0xc2,0xe4,0xce,0x8e,0x0a,0x00,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x00,0x0d,0xad,0x43,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0xee,0x5b,0x00,
+    0x00,0x00,0x00,0x7e,0xca,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x50,0xd2,0x00,0x00,
+    0xf2,0x32,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x24,0xed,0x7f,0x28,0x1d,0x62,0xe8,0x6c,0x00,0x00,0xc3,0xa2,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0xa2,0x2b,0x2b,0x2b,0x04,0x00,0x00,0xa3,0xaf,0x00,
+    0x00,0x00,0x00,0xd9,0x41,0x00,0x8a,0xba,0x37,0x18,0x35,0xbd,0xae,0x00,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x09,0xbd,0x7e,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0xba,0xa5,0x00,
+    0x00,0x00,0x00,0xc8,0x94,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x93,0xa0,0x00,0x00,
+    0xc2,0x74,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xa5,0x95,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x46,0xf1,0x75,0x1b,
+    0x00,0x03,0x18,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0xe1,0xb6,
+    0x62,0x6e,0xb6,0xff,0x41,0x00,0x8a,0x8f,0x00,0x00,0x00,0x1d,0xfb,0x18,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x08,0xb8,0x85,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0x36,0xf2,0x77,
+    0x0f,0x18,0x87,0xf1,0x1a,0x00,0x8a,0xbf,0x18,0x00,0x00,0x4f,0xf2,0x28,0x00,0x00,
+    0x44,0xeb,0x39,0x00,0x00,0x22,0xd4,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xe8,0x3d,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x4d,0xdd,0xfc,
+    0xdb,0xf2,0x7a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x6f,
+    0x9e,0x9c,0x55,0xde,0x3d,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xe4,0x3a,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x97,0xb6,0x88,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x30,0xe9,0x00,0x00,0x00,0x00,
+    0xd4,0x45,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,0x00,0x48,0xe3,
+    0xf0,0xf7,0xd4,0x32,0x00,0x00,0x8a,0xd3,0xe7,0xd5,0xea,0xdd,0x40,0x00,0x00,0x00,
+    0x00,0x56,0xe8,0xe4,0xd9,0xdf,0xdc,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x08,0xff,0x25,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x10,
+    0x25,0x09,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x27,0xff,0x1c,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xd2,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0xdf,0xf4,0x38,0x00,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x1e,0x17,0x00,0x00,0x00,0x00,0x8a,0x8f,0x02,0x20,0x19,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1f,0x1b,0x01,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xed,0x62,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x09,0x00,
+    0x00,0x1f,0x9e,0xcc,0x01,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x4f,0xed,0x48,0x00,0x00,0x00,
+    0x00,0x8f,0x8a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0xb8,0xb5,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x63,0xf2,0xd8,
+    0xdc,0xd3,0x8e,0x22,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x8a,0x8f,0x00,0x3e,0xed,0x3b,0x00,0x00,
+    0x00,0x8e,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0xad,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x31,0xf6,0x7f,0x1c,0x00,0x00,0xae,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x22,
+    0x18,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x8a,
+    0x8f,0x00,0x00,0x00,0x00,0x8a,0x8e,0x00,0x8a,0x8f,0x00,0x00,0x52,0xe7,0x1d,0x00,
+    0x00,0x7b,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x3f,0xd8,0xfc,0xd2,0xe0,0xf1,0x55,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0xcf,0x49,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0xa6,0x69,0x00,0x8a,0x8f,0x00,0x00,0x00,0x92,0xbc,0x01,
+    0x00,0x1f,0xdf,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x13,0x2d,0x1a,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x1c,0xe0,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x03,0xd1,0xe1,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x1e,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x3d,0xac,0xd3,0xe8,0xd1,0x0b,0x00,0x00,0x2a,0x91,0xdc,0xe5,0xbd,0x0a,0x00,
+    0x3e,0x3e,0x00,0x00,0x00,0x00,0x00,0x7d,0x59,0x00,0x00,0x00,0x00,0xb2,0x24,0x00,
+    0x6b,0x76,0x00,0x00,0x00,0x00,0x4f,0x86,0x00,0x62,0x7e,0x00,0x00,0x00,0x01,0xb6,
+    0x24,0x00,0x00,0x00,0x54,0x7c,0x00,0x17,0xbc,0x26,0x00,0x00,0x00,0x92,0x57,0x00,
+    0x6b,0x77,0x00,0x00,0x00,0x00,0x6a,0x6a,0x00,0x14,0xc2,0xc2,0xc2,0xc2,0xc2,0xaf,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x07,0x00,0x15,0x34,0x00,0x0d,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x15,0x1a,0x00,0x00,0x00,0x01,0x00,0x00,0x1c,0xb6,0xb6,0xb6,
+    0xb6,0xb6,0xb6,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0xab,0x1f,0x13,0x2a,0x00,0x00,0x00,0xc2,0x66,0x0a,0x16,0x44,0x00,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x4d,0xd4,0x00,0x00,0x00,0x00,0xa3,0x6f,0x00,0x41,0xda,0x00,0x00,0x00,0x27,0xff,
+    0x5f,0x00,0x00,0x00,0xa5,0x63,0x00,0x00,0x7b,0xc6,0x03,0x00,0x5c,0xd0,0x06,0x00,
+    0x4d,0xd8,0x00,0x00,0x00,0x00,0xc1,0x51,0x00,0x04,0x2b,0x2b,0x2b,0x2d,0xcd,0x96,
+    0x00,0x00,0x00,0x00,0x11,0xba,0xd8,0x35,0x00,0x4e,0xbe,0x00,0xb0,0xdc,0x48,0x00,
+    0x00,0x00,0x00,0x71,0xdc,0xde,0xb6,0x21,0x00,0x60,0x8a,0x00,0x27,0xbc,0x23,0x23,
+    0x23,0x23,0x53,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x1c,0xfa,0x04,0x00,0x00,0x00,0x00,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x0b,0xf6,0x1c,0x00,0x00,0x02,0xe8,0x25,0x00,0x06,0xf2,0x1d,0x00,0x00,0x6a,0xe9,
+    0x9d,0x00,0x00,0x01,0xe5,0x1b,0x00,0x00,0x03,0xc6,0x76,0x1c,0xe7,0x2d,0x00,0x00,
+    0x0b,0xf5,0x26,0x00,0x00,0x07,0xf4,0x11,0x00,0x00,0x00,0x00,0x00,0x7e,0xc1,0x05,
+    0x00,0x00,0x00,0x00,0x78,0xaa,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x46,0xdb,0x00,
+    0x00,0x00,0x0a,0xdb,0x0c,0x02,0x69,0xe5,0xc0,0xdb,0x21,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x02,0xd4,0xa4,0x1b,0x00,0x00,0x00,0x00,
+    0x9c,0xe0,0xc2,0xc2,0xbf,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0xad,0x6b,0x00,0x00,0x3c,0xce,0x00,0x00,0x00,0xb1,0x67,0x00,0x00,0xb1,0x67,
+    0xe4,0x01,0x00,0x31,0xd1,0x00,0x00,0x00,0x00,0x25,0xec,0xc9,0x75,0x00,0x00,0x00,
+    0x00,0xa8,0x7b,0x00,0x00,0x3e,0xcc,0x00,0x00,0x00,0x00,0x00,0x41,0xe4,0x19,0x00,
+    0x00,0x00,0x00,0x00,0x9e,0x70,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x08,0xfe,0x06,
+    0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x08,0x2e,0x0a,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x99,0xf2,0xa7,0x26,0x00,0x00,
+    0x9c,0x93,0x2b,0x2b,0x2a,0x00,0x00,0xa4,0x75,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x56,0xc1,0x00,0x00,0x91,0x75,0x00,0x00,0x00,0x6a,0xb5,0x00,0x0a,0xe7,0x08,
+    0xd7,0x32,0x00,0x7d,0x88,0x00,0x00,0x00,0x00,0x00,0xb2,0xfc,0x24,0x00,0x00,0x00,
+    0x00,0x4d,0xd9,0x01,0x00,0x81,0x8a,0x00,0x00,0x00,0x00,0x13,0xe4,0x44,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x69,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x01,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x84,0xf1,0x2b,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x9b,0x84,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x08,0xec,0x22,0x05,0xe4,0x19,0x00,0x00,0x00,0x17,0xf4,0x11,0x51,0xa7,0x00,
+    0x84,0x84,0x00,0xd1,0x31,0x00,0x00,0x00,0x00,0x50,0xd4,0x80,0xc8,0x04,0x00,0x00,
+    0x00,0x04,0xe1,0x40,0x00,0xc9,0x3c,0x00,0x00,0x00,0x00,0xab,0x8e,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa6,0x7f,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x7f,0xab,0x00,0x00,0x00,0x00,0xe9,0x30,0x00,
+    0x00,0x00,0x8f,0x86,0x52,0xad,0x00,0x00,0x00,0x00,0x00,0xad,0x66,0xa8,0x50,0x00,
+    0x2d,0xdc,0x2c,0xcd,0x00,0x00,0x00,0x00,0x16,0xe4,0x2f,0x02,0xc3,0x7d,0x00,0x00,
+    0x00,0x00,0x77,0xad,0x1a,0xdd,0x01,0x00,0x00,0x00,0x57,0xda,0x08,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x64,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xfc,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x05,0x14,0x00,0x00,0x10,0xe4,0x39,0x00,
+    0x9c,0x7d,0x00,0x00,0x00,0x00,0x00,0x27,0xf7,0x3f,0x00,0x00,0x02,0xeb,0x30,0x00,
+    0x00,0x00,0x25,0xea,0xc8,0x42,0x00,0x00,0x00,0x00,0x00,0x49,0xd3,0xe2,0x06,0x00,
+    0x00,0xce,0xc6,0x6a,0x00,0x00,0x00,0x00,0x9f,0x81,0x00,0x00,0x24,0xef,0x27,0x00,
+    0x00,0x00,0x10,0xed,0x92,0x86,0x00,0x00,0x00,0x0c,0xe3,0x45,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xc0,0x49,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xe3,0x26,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x8a,0x8f,0x00,0x00,0x00,0x00,0x00,0x2d,0xf2,0xd7,0xd5,0xdf,0x8c,0x00,0x00,
+    0x9b,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0xeb,0xe6,0xdc,0xf1,0xda,0x22,0x00,
+    0x00,0x00,0x00,0xae,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xe1,0x8d,0x00,0x00,
+    0x00,0x68,0xf6,0x10,0x00,0x00,0x00,0x3b,0xdc,0x08,0x00,0x00,0x00,0x7e,0xb3,0x00,
+    0x00,0x00,0x00,0x7f,0xff,0x2c,0x00,0x00,0x00,0x58,0xfe,0xee,0xee,0xee,0xee,0xee,
+    0x0c,0x00,0x17,0x8c,0xd4,0x09,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0x76,0xc9,
+    0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x20,0x21,0x00,0x00,0x00,0x00,
+    0x8a,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x1d,0x08,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x53,0xc7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x26,0xc3,0xaf,0x02,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0x4e,0xe4,
+    0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x5c,0xd5,0x0b,0x00,0x0f,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x17,0xd9,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x02,0xd3,0x3d,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xd7,0x3b,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x08,0xb5,0xef,0xd9,0xec,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0xc2,0xc7,0xe5,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa5,0x60,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xf9,0x0e,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xb1,0x00,0x00,
+    0x00,0x00,0x38,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x14,0x24,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x14,0x25,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x27,0xf3,0xd8,0xd8,
+    0xd8,0xd8,0xe1,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa4,0x68,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x00,0xff,0x0d,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0xa1,0x6d,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x05,0xff,0x09,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x87,0x8f,0x00,0x00,0x00,0x4e,0xbe,0x00,0x00,0x2a,0xeb,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x24,0xe1,0xa3,0x26,0x00,0x4e,0xbe,0x00,0x80,0xd9,0x71,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x0c,0x3c,0x16,0x00,0x0b,0x1a,0x00,0x3e,0x20,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+];
+
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/debug_render.rs
@@ -0,0 +1,219 @@
+/* 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 debug_font_data;
+use device::{Device, GpuMarker, ProgramId, VAOId, TextureId, VertexFormat};
+use device::{TextureFilter, VertexUsageHint, TextureTarget};
+use euclid::{Matrix4D, Point2D, Size2D, Rect};
+use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
+use internal_types::{DebugFontVertex, DebugColorVertex, RenderTargetMode, PackedColor};
+use std::f32;
+use webrender_traits::{ColorF, ImageFormat, DeviceUintSize};
+
+pub struct DebugRenderer {
+    font_vertices: Vec<DebugFontVertex>,
+    font_indices: Vec<u32>,
+    font_program_id: ProgramId,
+    font_vao: VAOId,
+    font_texture_id: TextureId,
+
+    tri_vertices: Vec<DebugColorVertex>,
+    tri_indices: Vec<u32>,
+    tri_vao: VAOId,
+    line_vertices: Vec<DebugColorVertex>,
+    line_vao: VAOId,
+    color_program_id: ProgramId,
+}
+
+impl DebugRenderer {
+    pub fn new(device: &mut Device) -> DebugRenderer {
+        let font_program_id = device.create_program("debug_font", "shared_other");
+        let color_program_id = device.create_program("debug_color", "shared_other");
+
+        let font_vao = device.create_vao(VertexFormat::DebugFont, 32);
+        let line_vao = device.create_vao(VertexFormat::DebugColor, 32);
+        let tri_vao = device.create_vao(VertexFormat::DebugColor, 32);
+
+        let font_texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
+        device.init_texture(font_texture_id,
+                            debug_font_data::BMP_WIDTH,
+                            debug_font_data::BMP_HEIGHT,
+                            ImageFormat::A8,
+                            TextureFilter::Linear,
+                            RenderTargetMode::None,
+                            Some(&debug_font_data::FONT_BITMAP));
+
+        DebugRenderer {
+            font_vertices: Vec::new(),
+            font_indices: Vec::new(),
+            line_vertices: Vec::new(),
+            tri_vao: tri_vao,
+            tri_vertices: Vec::new(),
+            tri_indices: Vec::new(),
+            font_program_id: font_program_id,
+            color_program_id: color_program_id,
+            font_vao: font_vao,
+            line_vao: line_vao,
+            font_texture_id: font_texture_id,
+        }
+    }
+
+    pub fn line_height(&self) -> f32 {
+        debug_font_data::FONT_SIZE as f32 * 1.1
+    }
+
+    pub fn add_text(&mut self,
+                    x: f32,
+                    y: f32,
+                    text: &str,
+                    color: &ColorF) -> Rect<f32> {
+        let mut x_start = x;
+        let ipw = 1.0 / debug_font_data::BMP_WIDTH as f32;
+        let iph = 1.0 / debug_font_data::BMP_HEIGHT as f32;
+        let color = PackedColor::from_color(color);
+
+        let mut min_x = f32::MAX;
+        let mut max_x = -f32::MAX;
+        let mut min_y = f32::MAX;
+        let mut max_y = -f32::MAX;
+
+        for c in text.chars() {
+            let c = c as usize - debug_font_data::FIRST_GLYPH_INDEX as usize;
+            if c < debug_font_data::GLYPHS.len() {
+                let glyph = &debug_font_data::GLYPHS[c];
+
+                let x0 = (x_start + glyph.xo + 0.5).floor();
+                let y0 = (y + glyph.yo + 0.5).floor();
+
+                let x1 = x0 + glyph.x1 as f32 - glyph.x0 as f32;
+                let y1 = y0 + glyph.y1 as f32 - glyph.y0 as f32;
+
+                let s0 = glyph.x0 as f32 * ipw;
+                let t0 = glyph.y0 as f32 * iph;
+                let s1 = glyph.x1 as f32 * ipw;
+                let t1 = glyph.y1 as f32 * iph;
+
+                x_start += glyph.xa;
+
+                let vertex_count = self.font_vertices.len() as u32;
+
+                self.font_vertices.push(DebugFontVertex::new(x0, y0, s0, t0, color));
+                self.font_vertices.push(DebugFontVertex::new(x1, y0, s1, t0, color));
+                self.font_vertices.push(DebugFontVertex::new(x0, y1, s0, t1, color));
+                self.font_vertices.push(DebugFontVertex::new(x1, y1, s1, t1, color));
+
+                self.font_indices.push(vertex_count + 0);
+                self.font_indices.push(vertex_count + 1);
+                self.font_indices.push(vertex_count + 2);
+                self.font_indices.push(vertex_count + 2);
+                self.font_indices.push(vertex_count + 1);
+                self.font_indices.push(vertex_count + 3);
+
+                min_x = min_x.min(x0);
+                max_x = max_x.max(x1);
+                min_y = min_y.min(y0);
+                max_y = max_y.max(y1);
+            }
+        }
+
+        Rect::new(Point2D::new(min_x, min_y), Size2D::new(max_x-min_x, max_y-min_y))
+    }
+
+    pub fn add_quad(&mut self,
+                    x0: f32,
+                    y0: f32,
+                    x1: f32,
+                    y1: f32,
+                    color_top: &ColorF,
+                    color_bottom: &ColorF) {
+        let color_top = PackedColor::from_color(color_top);
+        let color_bottom = PackedColor::from_color(color_bottom);
+        let vertex_count = self.tri_vertices.len() as u32;
+
+        self.tri_vertices.push(DebugColorVertex::new(x0, y0, color_top));
+        self.tri_vertices.push(DebugColorVertex::new(x1, y0, color_top));
+        self.tri_vertices.push(DebugColorVertex::new(x0, y1, color_bottom));
+        self.tri_vertices.push(DebugColorVertex::new(x1, y1, color_bottom));
+
+        self.tri_indices.push(vertex_count + 0);
+        self.tri_indices.push(vertex_count + 1);
+        self.tri_indices.push(vertex_count + 2);
+        self.tri_indices.push(vertex_count + 2);
+        self.tri_indices.push(vertex_count + 1);
+        self.tri_indices.push(vertex_count + 3);
+    }
+
+    #[allow(dead_code)]
+    pub fn add_line(&mut self,
+                    x0: i32,
+                    y0: i32,
+                    color0: &ColorF,
+                    x1: i32,
+                    y1: i32,
+                    color1: &ColorF) {
+        let color0 = PackedColor::from_color(color0);
+        let color1 = PackedColor::from_color(color1);
+        self.line_vertices.push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
+        self.line_vertices.push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
+    }
+
+    pub fn render(&mut self,
+                  device: &mut Device,
+                  viewport_size: &DeviceUintSize) {
+        let _gm = GpuMarker::new("debug");
+        device.disable_depth();
+        device.set_blend(true);
+        device.set_blend_mode_alpha();
+
+        let projection = Matrix4D::ortho(0.0,
+                                         viewport_size.width as f32,
+                                         viewport_size.height as f32,
+                                         0.0,
+                                         ORTHO_NEAR_PLANE,
+                                         ORTHO_FAR_PLANE);
+
+        // Triangles
+        if !self.tri_vertices.is_empty() {
+            device.bind_program(self.color_program_id, &projection);
+            device.bind_vao(self.tri_vao);
+            device.update_vao_indices(self.tri_vao,
+                                      &self.tri_indices,
+                                      VertexUsageHint::Dynamic);
+            device.update_vao_main_vertices(self.tri_vao,
+                                            &self.tri_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_triangles_u32(0, self.tri_indices.len() as i32);
+        }
+
+        // Lines
+        if !self.line_vertices.is_empty() {
+            device.bind_program(self.color_program_id, &projection);
+            device.bind_vao(self.line_vao);
+            device.update_vao_main_vertices(self.line_vao,
+                                            &self.line_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_nonindexed_lines(0, self.line_vertices.len() as i32);
+        }
+
+        // Glyph
+        if !self.font_indices.is_empty() {
+            device.bind_program(self.font_program_id, &projection);
+            device.bind_texture(TextureSampler::Color0, self.font_texture_id);
+            device.bind_vao(self.font_vao);
+            device.update_vao_indices(self.font_vao,
+                                      &self.font_indices,
+                                      VertexUsageHint::Dynamic);
+            device.update_vao_main_vertices(self.font_vao,
+                                            &self.font_vertices,
+                                            VertexUsageHint::Dynamic);
+            device.draw_triangles_u32(0, self.font_indices.len() as i32);
+        }
+
+        self.font_indices.clear();
+        self.font_vertices.clear();
+        self.line_vertices.clear();
+        self.tri_vertices.clear();
+        self.tri_indices.clear();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/gfx/webrender/src/device.rs
@@ -0,0 +1,1965 @@
+/* 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 euclid::Matrix4D;
+use fnv::FnvHasher;
+use gleam::gl;
+use internal_types::{PackedVertex, RenderTargetMode, TextureSampler, DEFAULT_TEXTURE};
+use internal_types::{BlurAttribute, ClearAttribute, ClipAttribute, VertexAttribute};
+use internal_types::{DebugFontVertex, DebugColorVertex};
+//use notify::{self, Watcher};
+use super::shader_source;
+use std::collections::HashMap;
+use std::fs::File;
+use std::hash::BuildHasherDefault;
+use std::io::Read;
+use std::mem;
+use std::path::PathBuf;
+//use std::sync::mpsc::{channel, Sender};
+//use std::thread;
+use webrender_traits::{ColorF, ImageFormat};
+use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
+
+#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+const GL_FORMAT_A: gl::GLuint = gl::RED;
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const GL_FORMAT_A: gl::GLuint = gl::ALPHA;
+
+#[cfg(any(target_os = "windows", all(unix, not(target_os = "android"))))]
+const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA;
+
+#[cfg(target_os = "android")]
+const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA_EXT;
+
+#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
+const SHADER_VERSION: &'static str = "#version 150\n";
+
+#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
+const SHADER_VERSION: &'static str = "#version 300 es\n";
+
+static SHADER_PREAMBLE: &'static str = "shared";
+
+pub type ViewportDimensions = [u32; 2];
+
+lazy_static! {
+    pub static ref MAX_TEXTURE_SIZE: gl::GLint = {
+        gl::get_integer_v(gl::MAX_TEXTURE_SIZE)
+    };
+}
+
+#[repr(u32)]
+pub enum DepthFunction {
+    Less = gl::LESS,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum TextureTarget {
+    Default,
+    Array,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum TextureFilter {
+    Nearest,
+    Linear,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum VertexFormat {
+    Triangles,
+    Rectangles,
+    DebugFont,
+    DebugColor,
+    Clear,
+    Blur,
+    Clip,
+}
+
+enum FBOTarget {
+    Read,
+    Draw,
+}
+
+fn get_optional_shader_source(shader_name: &str, base_path: &Option<PathBuf>) -> Option<String> {
+    if let Some(ref base) = *base_path {
+        let shader_path = base.join(&format!("{}.glsl", shader_name));
+        if shader_path.exists() {
+            let mut source = String::new();
+            File::open(&shader_path).unwrap().read_to_string(&mut source).unwrap();
+            return Some(source);
+        }
+    }
+
+    shader_source::SHADERS.get(shader_name).and_then(|s| Some((*s).to_owned()))
+}
+
+fn get_shader_source(shader_name: &str, base_path: &Option<PathBuf>) -> String {
+    get_optional_shader_source(shader_name, base_path)
+        .expect(&format!("Couldn't get required shader: {}", shader_name))
+}
+
+pub trait FileWatcherHandler : Send {
+    fn file_changed(&self, path: PathBuf);
+}
+
+impl VertexFormat {
+    fn bind(&self, main: VBOId, instance: VBOId, offset: gl::GLuint, instance_stride: gl::GLint) {
+        main.bind();
+
+        match *self {
+            VertexFormat::DebugFont => {
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint);
+
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::ColorTexCoord as gl::GLuint, 0);
+
+                let vertex_stride = mem::size_of::<DebugFontVertex>() as gl::GLuint;
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                                          4,
+                                          gl::UNSIGNED_BYTE,
+                                          true,
+                                          vertex_stride as gl::GLint,
+                                          8 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          12 + vertex_stride * offset);
+            }
+            VertexFormat::DebugColor => {
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+
+                let vertex_stride = mem::size_of::<DebugColorVertex>() as gl::GLuint;
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0 + vertex_stride * offset);
+                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                                          4,
+                                          gl::UNSIGNED_BYTE,
+                                          true,
+                                          vertex_stride as gl::GLint,
+                                          8 + vertex_stride * offset);
+            }
+            VertexFormat::Rectangles |
+            VertexFormat::Triangles => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+                let mut offset = 0;
+
+                for &attrib in [VertexAttribute::GlobalPrimId,
+                                VertexAttribute::PrimitiveAddress,
+                                VertexAttribute::TaskIndex,
+                                VertexAttribute::ClipTaskIndex,
+                                VertexAttribute::LayerIndex,
+                                VertexAttribute::ElementIndex,
+                                VertexAttribute::ZIndex,
+                               ].into_iter() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                offset);
+                    offset += 4;
+                }
+
+                gl::enable_vertex_attrib_array(VertexAttribute::UserData as gl::GLuint);
+                gl::vertex_attrib_divisor(VertexAttribute::UserData as gl::GLuint, 1);
+                gl::vertex_attrib_i_pointer(VertexAttribute::UserData as gl::GLuint,
+                                            2,
+                                            gl::INT,
+                                            instance_stride,
+                                            offset);
+            }
+            VertexFormat::Clear => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(ClearAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(ClearAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(ClearAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                gl::enable_vertex_attrib_array(ClearAttribute::Rectangle as gl::GLuint);
+                gl::vertex_attrib_divisor(ClearAttribute::Rectangle as gl::GLuint, 1);
+                gl::vertex_attrib_i_pointer(ClearAttribute::Rectangle as gl::GLuint,
+                                            4,
+                                            gl::INT,
+                                            instance_stride,
+                                            0);
+            }
+            VertexFormat::Blur => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(BlurAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(BlurAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(BlurAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                for (i, &attrib) in [BlurAttribute::RenderTaskIndex,
+                                     BlurAttribute::SourceTaskIndex,
+                                     BlurAttribute::Direction,
+                                    ].into_iter().enumerate() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                (i * 4) as gl::GLuint);
+                }
+            }
+            VertexFormat::Clip => {
+                let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
+                gl::enable_vertex_attrib_array(ClipAttribute::Position as gl::GLuint);
+                gl::vertex_attrib_divisor(ClipAttribute::Position as gl::GLuint, 0);
+
+                gl::vertex_attrib_pointer(ClipAttribute::Position as gl::GLuint,
+                                          2,
+                                          gl::FLOAT,
+                                          false,
+                                          vertex_stride as gl::GLint,
+                                          0);
+
+                instance.bind();
+
+                for (i, &attrib) in [ClipAttribute::RenderTaskIndex,
+                                     ClipAttribute::LayerIndex,
+                                     ClipAttribute::DataIndex,
+                                     ClipAttribute::SegmentIndex,
+                                    ].into_iter().enumerate() {
+                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                                                1,
+                                                gl::INT,
+                                                instance_stride,
+                                                (i * 4) as gl::GLuint);
+                }
+            }
+        }
+    }
+}
+
+impl TextureId {
+    pub fn bind(&self) {
+        gl::bind_texture(self.target, self.name);
+    }
+
+    pub fn new(name: gl::GLuint) -> TextureId {
+        TextureId {
+            name: name,
+            target: gl::TEXTURE_2D,
+        }
+    }
+
+    pub fn invalid() -> TextureId {
+        TextureId {
+            name: 0,
+            target: gl::TEXTURE_2D,
+        }
+    }
+
+    pub fn is_valid(&self) -> bool { *self != TextureId::invalid() }
+}
+
+impl ProgramId {
+    fn bind(&self) {
+        gl::use_program(self.0);
+    }
+}
+
+impl VBOId {
+    fn bind(&self) {
+        gl::bind_buffer(gl::ARRAY_BUFFER, self.0);
+    }
+}
+
+impl IBOId {
+    fn bind(&self) {
+        gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0);
+    }
+}
+
+impl UBOId {
+    fn _bind(&self) {
+        gl::bind_buffer(gl::UNIFORM_BUFFER, self.0);
+    }
+}
+
+impl FBOId {
+    fn bind(&self, target: FBOTarget) {
+        let target = match target {
+            FBOTarget::Read => gl::READ_FRAMEBUFFER,
+            FBOTarget::Draw => gl::DRAW_FRAMEBUFFER,
+        };
+        gl::bind_framebuffer(target, self.0);
+    }
+}
+
+struct Texture {
+    id: gl::GLuint,
+    format: ImageFormat,
+    width: u32,
+    height: u32,
+    filter: TextureFilter,
+    mode: RenderTargetMode,
+    fbo_ids: Vec<FBOId>,
+}
+
+impl Drop for Texture {
+    fn drop(&mut self) {
+        if !self.fbo_ids.is_empty() {
+            let fbo_ids: Vec<_> = self.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect();
+            gl::delete_framebuffers(&fbo_ids[..]);
+        }
+        gl::delete_textures(&[self.id]);
+    }
+}
+
+struct Program {
+    id: gl::GLuint,
+    u_transform: gl::GLint,
+    u_device_pixel_ratio: gl::GLint,
+    name: String,
+    vs_source: String,
+    fs_source: String,
+    prefix: Option<String>,
+    vs_id: Option<gl::GLuint>,
+    fs_id: Option<gl::GLuint>,