Merge m-c to autoland, a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 06 Feb 2017 17:52:26 -0800
changeset 341102 330ab4695793c499110152a6582afca8e87ae46c
parent 341101 f3da0505833f946d1b1767986ebb8e3d7a63f5c1 (current diff)
parent 341044 af8a2573d0f1e9cc6f2ba0ab67d7a702a197f177 (diff)
child 341103 270900fec93245a4c8e93df3e74be837735766d7
push id86634
push usercbook@mozilla.com
push dateTue, 07 Feb 2017 13:14:58 +0000
treeherdermozilla-inbound@9dbd2d9b334e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge 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,
+        }