Import Cobalt 23.lts.4.311259
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 12bbd12..860c540 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -45,7 +45,8 @@
             (?x)^(
                 starboard/[^/]+/i18n/|
                 cobalt/content/licenses/|
-                cobalt/fetch/embedded_scripts
+                cobalt/fetch/embedded_scripts|
+                cobalt/loader/cors_preflight.cc
             )
 
 -   repo: local
@@ -58,10 +59,11 @@
         always_run: true
     -   id: clang-format
         name: clang-format
-        entry: python ./precommit_hooks/clang_format_wrapper.py
+        entry: clang-format
         language: python
         types: [c++]
         args: [-i, -style=file]
+        additional_dependencies: ['clang-format']
     -   id: cpplint
         name: cpplint
         entry: cpplint
diff --git a/base/message_loop/message_pump_ui_starboard.h b/base/message_loop/message_pump_ui_starboard.h
index 12e6e38..214e18c 100644
--- a/base/message_loop/message_pump_ui_starboard.h
+++ b/base/message_loop/message_pump_ui_starboard.h
@@ -40,7 +40,11 @@
 class BASE_EXPORT MessagePumpUIStarboard : public MessagePump {
  public:
   MessagePumpUIStarboard();
-  virtual ~MessagePumpUIStarboard() {}
+  virtual ~MessagePumpUIStarboard() {
+    // There is probability that MessagePump may send event to MessageLoop that
+    // was already destroyed. To avoid this delete all tasks in pump_
+    Quit();
+  }
 
   // Runs one iteration of the run loop, and reschedules another call, if
   // necessary.
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 6260b81..157c841 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1292,7 +1292,7 @@
   # android:runtime_library.  This is to ensure libc++ appears before
   # libandroid_support in the -isystem include order.  Otherwise, there will be
   # build errors related to symbols declared in math.h.
-  if (use_custom_libcxx) {
+  if (!is_starboard && use_custom_libcxx) {
     configs += [ "//build/config/c++:runtime_library" ]
   }
 
diff --git a/buildtools/.gitignore b/buildtools/.gitignore
deleted file mode 100644
index afaa3ca..0000000
--- a/buildtools/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-*.pyc
-linux64/clang-format
-mac/clang-format
-win/clang-format.exe
diff --git a/buildtools/LICENSE b/buildtools/LICENSE
deleted file mode 100644
index 972bb2e..0000000
--- a/buildtools/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//    * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//    * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//    * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/buildtools/METADATA b/buildtools/METADATA
deleted file mode 100644
index 33b683b..0000000
--- a/buildtools/METADATA
+++ /dev/null
@@ -1,20 +0,0 @@
-name: "buildtools"
-description:
-  "Subtree at buildtools."
-
-third_party {
-  url {
-    type: LOCAL_SOURCE
-    value: "/buildtools_mirror"
-  }
-  url {
-    type: GIT
-    value: "https://chromium.googlesource.com/chromium/buildtools"
-  }
-  version: "5af0a3a8b89827a8634132080a39ab4b63dee489"
-  last_upgrade_date {
-    year: 2017
-    month: 8
-    day: 18
-  }
-}
diff --git a/buildtools/README.txt b/buildtools/README.txt
deleted file mode 100644
index 1db97b4..0000000
--- a/buildtools/README.txt
+++ /dev/null
@@ -1,56 +0,0 @@
-This repository contains hashes of build tools used by Chromium and related
-projects. The actual binaries are pulled from Google Storage, normally as part
-of a gclient hook.
-
-The repository is separate so that the shared build tools can be shared between
-the various Chromium-related projects without each one needing to maintain
-their own versionining of each binary.
-
-To update the GN binary, run (from the Chromium repo) tools/gn/bin/roll_gn.py
-which will automatically upload the binaries and roll build tools.
-
-________________________________________
-UPDATING AND ROLLING BUILDTOOLS MANUALLY
-
-When you update buildtools, you should roll the new version into the Chromium
-repository right away. Otherwise, the next person who makes a change will end
-up rolling (and testing) your change. If there are any unresolved problems with
-your change, the next person will be blocked.
-
-  - From the buildtools directory, make a branch, edit and upload normally.
-
-  - Get your change reviewed and landed. There are no trybots so landing will
-    be very fast.
-
-  - Get the hash for the commit that commit-bot made. Make a new branch in
-    the Chromium repository and paste the hash into the line in //DEPS
-    labeled "buildtools_revision".
-
-  - You can TBR changes to the DEPS file since the git hashes can't be reviewed
-    in any practical way. Submit that patch to the commit queue.
-
-  - If this roll identifies a problem with your patch, fix it promptly. If you
-    are unable to fix it promptly, it's best to revert your buildtools patch
-    to avoid blocking other people that want to make changes.
-
-________________________
-ADDING BINARIES MANUALLY
-
-One uploads new versions of the tools using the 'gsutil' binary from the
-Google Storage SDK:
-
-  https://developers.google.com/storage/docs/gsutil
-
-There is a checked-in version of gsutil as part of depot_tools.
-
-To initialize gsutil's credentials:
-
-  python ~/depot_tools/third_party/gsutil/gsutil config
-
-  That will give a URL which you should log into with your web browser. For
-  rolling GN, the username should be the one that is on the ACL for the
-  "chromium-gn" bucket (probably your @google.com address). Contact the build
-  team for help getting access if necessary.
-
-  Copy the code back to the command line util. Ignore the project ID (it's OK
-  to just leave blank when prompted).
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni
deleted file mode 100644
index d66c2a9..0000000
--- a/buildtools/deps_revisions.gni
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-declare_args() {
-  # Used to cause full rebuilds on libc++ rolls. This should be kept in sync
-  # with the libcxx_revision vars in //DEPS.
-  libcxx_revision = "8fa87946779682841e21e2da977eccfb6cb3bded"
-}
diff --git a/buildtools/linux64/clang-format.sha1 b/buildtools/linux64/clang-format.sha1
deleted file mode 100644
index dcf7df3..0000000
--- a/buildtools/linux64/clang-format.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5349d1954e17f6ccafb6e6663b0f13cdb2bb33c8
\ No newline at end of file
diff --git a/buildtools/mac/clang-format.sha1 b/buildtools/mac/clang-format.sha1
deleted file mode 100644
index 8a00b61..0000000
--- a/buildtools/mac/clang-format.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0679b295e2ce2fce7919d1e8d003e497475f24a3
diff --git a/buildtools/win/clang-format.exe.sha1 b/buildtools/win/clang-format.exe.sha1
deleted file mode 100644
index fbb0ae5..0000000
--- a/buildtools/win/clang-format.exe.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c8455d43d052eb79f65d046c6b02c169857b963b
diff --git a/cobalt/BUILD.gn b/cobalt/BUILD.gn
index e9c9fcb..1b39161 100644
--- a/cobalt/BUILD.gn
+++ b/cobalt/BUILD.gn
@@ -28,6 +28,7 @@
     "//cobalt/layout_tests:web_platform_tests",
     "//cobalt/loader:loader_test",
     "//cobalt/loader/image/sandbox:image_decoder_sandbox",
+    "//cobalt/media:media_test",
     "//cobalt/media/sandbox:media_sandbox",
     "//cobalt/media/sandbox:web_media_player_sandbox",
     "//cobalt/media_capture:media_capture_test",
diff --git a/cobalt/audio/audio_node_input_output_test.cc b/cobalt/audio/audio_node_input_output_test.cc
index 12cb069..2723382 100644
--- a/cobalt/audio/audio_node_input_output_test.cc
+++ b/cobalt/audio/audio_node_input_output_test.cc
@@ -94,9 +94,10 @@
  public:
   AudioNodeInputOutputTest() {
     web_context_.reset(web::Agent::CreateContext("AudioNodeInputOutputTest"));
-    web_context_->setup_environment_settings(
+    web_context_->SetupEnvironmentSettings(
         new dom::testing::StubEnvironmentSettings);
     web_context_->global_environment()->CreateGlobalObject();
+    web_context_->SetupFinished();
   }
 
   ~AudioNodeInputOutputTest() {}
diff --git a/cobalt/base/deep_link_event.h b/cobalt/base/deep_link_event.h
index c2d3aaf..e878511 100644
--- a/cobalt/base/deep_link_event.h
+++ b/cobalt/base/deep_link_event.h
@@ -16,20 +16,28 @@
 #define COBALT_BASE_DEEP_LINK_EVENT_H_
 
 #include <string>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/strings/string_util.h"
 #include "cobalt/base/event.h"
+#include "cobalt/base/polymorphic_downcast.h"
 
 namespace base {
 
 class DeepLinkEvent : public Event {
  public:
   DeepLinkEvent(const std::string& link, const base::Closure& consumed_callback)
-      : link_(link), consumed_callback_(consumed_callback) {}
+      : link_(link), consumed_callback_(std::move(consumed_callback)) {}
+  explicit DeepLinkEvent(const Event* event) {
+    const base::DeepLinkEvent* deep_link_event =
+        base::polymorphic_downcast<const base::DeepLinkEvent*>(event);
+    link_ = deep_link_event->link();
+    consumed_callback_ = deep_link_event->callback();
+  }
   const std::string& link() const { return link_; }
-  const base::Closure& callback() const { return consumed_callback_; }
+  base::Closure callback() const { return consumed_callback_; }
 
   BASE_EVENT_SUBCLASS(DeepLinkEvent);
 
diff --git a/cobalt/black_box_tests/black_box_cobalt_runner.py b/cobalt/black_box_tests/black_box_cobalt_runner.py
index f9ec2df..1f333e3 100644
--- a/cobalt/black_box_tests/black_box_cobalt_runner.py
+++ b/cobalt/black_box_tests/black_box_cobalt_runner.py
@@ -17,19 +17,32 @@
 from __future__ import division
 from __future__ import print_function
 
+import logging
+import time
+
 from cobalt.tools.automated_testing import cobalt_runner
+from cobalt.tools.automated_testing import webdriver_utils
+
+selenium_exceptions = webdriver_utils.import_selenium_module(
+    'common.exceptions')
 
 # The following constants and logics are shared between this module and
 # the JavaScript test environment. Anyone making changes here should also
 # ensure necessary changes are made to testdata/black_box_js_test_utils.js
 _TEST_STATUS_ELEMENT_NAME = 'black_box_test_status'
 _JS_TEST_SUCCESS_MESSAGE = 'JavaScript_test_succeeded'
+_JS_TEST_FAILURE_MESSAGE = 'JavaScript_test_failed'
 _JS_TEST_SETUP_DONE_MESSAGE = 'JavaScript_setup_done'
 
+POLL_UNTIL_WAIT_SECONDS = 30
+
 
 class BlackBoxCobaltRunner(cobalt_runner.CobaltRunner):
   """Custom CobaltRunner made for BlackBoxTests' need."""
 
+  class AssertException(Exception):
+    """Raised when assert condition fails."""
+
   def __init__(self,
                launcher_params,
                url,
@@ -43,11 +56,37 @@
       target_params = []
     target_params.append('--silence_inline_script_warnings')
 
-    super(BlackBoxCobaltRunner, self).__init__(launcher_params, url, log_file,
-                                               target_params, success_message)
+    super().__init__(launcher_params, url, log_file, target_params,
+                     success_message)
+
+  def PollUntilFoundOrTestsFailedWithReconnects(self, css_selector):
+    """Polls until an element is found.
+
+    Args:
+      css_selector: A CSS selector
+    """
+    start_time = time.time()
+    while time.time() - start_time < POLL_UNTIL_WAIT_SECONDS:
+      is_failed = False
+      try:
+        if self.FindElements(css_selector):
+          break
+        is_failed = self.JSTestsFailed()
+      except (cobalt_runner.CobaltRunner.AssertException,
+              selenium_exceptions.NoSuchElementException,
+              selenium_exceptions.NoSuchWindowException,
+              selenium_exceptions.WebDriverException) as e:
+        # If the page
+        logging.warning(e)
+        self.ReconnectWebDriver()
+        continue
+      if is_failed:
+        raise BlackBoxCobaltRunner.AssertException(
+            'JS Test failed while waiting for ' + css_selector)
+      time.sleep(0.25)
 
   def JSTestsSucceeded(self):
-    """Check test assertions in HTML page."""
+    """Check succeeded test assertion in HTML page."""
 
     # Call onTestEnd() in black_box_js_test_utils.js to unblock the waiting for
     # JavaScript test logic completion.
@@ -56,9 +95,18 @@
     return body_element.get_attribute(
         _TEST_STATUS_ELEMENT_NAME) == _JS_TEST_SUCCESS_MESSAGE
 
+  def JSTestsFailed(self):
+    """Check failed test assertion in HTML page."""
+
+    # Call onTestEnd() in black_box_js_test_utils.js to unblock the waiting for
+    # JavaScript test logic completion.
+    body_element = self.UniqueFind('body')
+    return body_element and body_element.get_attribute(
+        _TEST_STATUS_ELEMENT_NAME) == _JS_TEST_FAILURE_MESSAGE
+
   def WaitForJSTestsSetup(self):
     """Poll setup status until JavaScript gives green light."""
 
     # Calling setupFinished() in black_box_js_test_utils.js to unblock the
     # waiting logic here.
-    self.PollUntilFound('#{}'.format(_JS_TEST_SETUP_DONE_MESSAGE))
+    self.PollUntilFound(f'#{_JS_TEST_SETUP_DONE_MESSAGE}')
diff --git a/cobalt/black_box_tests/black_box_tests.py b/cobalt/black_box_tests/black_box_tests.py
index 510e893..e816953 100644
--- a/cobalt/black_box_tests/black_box_tests.py
+++ b/cobalt/black_box_tests/black_box_tests.py
@@ -36,6 +36,8 @@
     'android-arm/devel',
     'android-arm64/devel',
     'android-x86/devel',
+    'evergreen-arm/devel',
+    'evergreen-x64/devel',
     'raspi-0/devel',
 ]
 
@@ -53,7 +55,8 @@
     'preload_font',
     'preload_visibility',
     'preload_launch_parameter',
-    'signal_handler_doesnt_crash',
+    # TODO(b/254502632): Investigate the cause of the flakiness from this test.
+    # 'signal_handler_doesnt_crash',
     'suspend_visibility',
     'timer_hit_after_preload',
     'timer_hit_in_preload',
@@ -67,8 +70,11 @@
     'h5vcc_storage_write_verify_test',
     'http_cache',
     'persistent_cookie',
+    'service_worker_add_to_cache_test',
     'service_worker_cache_keys_test',
+    'service_worker_controller_activation_test',
     'service_worker_get_registrations_test',
+    'service_worker_fetch_main_resource_test',
     'service_worker_fetch_test',
     'service_worker_message_test',
     'service_worker_test',
@@ -222,13 +228,8 @@
     if self.proxy_port == '-1':
       return 1
 
-    # Temporary means to determine if we are running on CI
-    # TODO: Update to IS_CI environment variable or similar
-    out_dir = _launcher_params.out_directory
-    is_ci = out_dir and 'mh_lab' in out_dir  # pylint: disable=unsupported-membership-test
-
-    if is_ci and (f'{_launcher_params.platform}/{_launcher_params.config}'
-                  in _DISABLED_BLACKBOXTEST_CONFIGS):
+    if (f'{_launcher_params.platform}/{_launcher_params.config}'
+        in _DISABLED_BLACKBOXTEST_CONFIGS):
       logging.warning('Blackbox tests disabled for platform:%s config:%s',
                       _launcher_params.platform, _launcher_params.config)
       return 0
diff --git a/cobalt/black_box_tests/testdata/preload_visibility.html b/cobalt/black_box_tests/testdata/preload_visibility.html
index 1c1eab8..6063d37 100644
--- a/cobalt/black_box_tests/testdata/preload_visibility.html
+++ b/cobalt/black_box_tests/testdata/preload_visibility.html
@@ -15,13 +15,20 @@
     assertEqual("hidden", document.visibilityState);
     assertFalse(document.hasFocus());
 
+    var visibilityStateVisible = false;
     // Wait for visibility change to verify visibilityState and having focus.
     function handleVisibilityChange() {
-      assertEqual("visible", document.visibilityState);
       assertFalse(document.hasFocus());
-      onEndTest();
+      if (visibilityStateVisible) {
+        assertEqual("hidden", document.visibilityState);
+        // Allow the app to become visible and then hidden at most once.
+      } else {
+        assertEqual("visible", document.visibilityState);
+        visibilityStateVisible = true;
+        onEndTest();
+      }
     }
     document.addEventListener("visibilitychange", handleVisibilityChange);
     setupFinished();
   </script>
-</body>
\ No newline at end of file
+</body>
diff --git a/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.html b/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.html
new file mode 100644
index 0000000..c8a0a85
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2023 The Cobalt Authors. All Rights Reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<html>
+<head>
+  <title>Cobalt Service Worker Add to Cache Test</title>
+  <script src='black_box_js_test_utils.js'></script>
+</head>
+<body>
+  <script>
+    h5vcc.storage.clearServiceWorkerCache();
+
+    const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
+        Promise.all(registrations.map(r => r.unregister())));
+    const fail = msg => {
+      if (msg) {
+        console.error(msg);
+      }
+      unregisterAll().then(notReached);
+    };
+    const timeoutId = window.setTimeout(fail, 10000);
+    const success = () => unregisterAll().then(() => {
+      clearTimeout(timeoutId);
+      onEndTest();
+    });
+    navigator.serviceWorker.onmessage = event => {
+      if (event.data === 'SUCCESS') {
+        success();
+        return;
+      }
+      fail(event.data);
+    };
+
+    navigator.serviceWorker.ready.then(registration => {
+      registration.active.postMessage('start-test');
+    });
+
+    unregisterAll().then(() => {
+      navigator.serviceWorker.register('service_worker_add_to_cache_test.js').catch(fail);
+    });
+
+    setupFinished();
+  </script>
+</body>
+</html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.js b/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.js
new file mode 100644
index 0000000..5a259e7
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_add_to_cache_test.js
@@ -0,0 +1,97 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+const interceptedBody = 'window.activeServiceWorker.postMessage("script-intercepted");';
+let shouldIntercept = false;
+
+const postMessage = message => {
+  const options = {
+    includeUncontrolled: false, type: 'window'
+  };
+  self.clients.matchAll(options).then(clients => {
+    clients.forEach(c => {
+      c.postMessage(message);
+    });
+  });
+};
+
+self.addEventListener("install", event => {
+  self.skipWaiting();
+});
+
+self.addEventListener('activate', event => {
+  self.clients.claim();
+});
+
+const noop = () => {};
+const fail = msg => {
+  if (msg) {
+    console.error(msg);
+  }
+  postMessage('FAIL');
+};
+const assertEquals = (expected, actual, msg) => {
+  if (expected === actual) {
+    return;
+  }
+  const errorMessage = `Expected: '${expected}', but was '${actual}'`;
+  fail(msg ? `${msg}(${errorMessage})` : errorMessage);
+};
+const assertNotEquals = (notExpected, actual, msg) => {
+  if (notExpected !== actual) {
+    return;
+  }
+  const errorMessage = `Not expected: '${notExpected}'`;
+  fail(msg ? `${msg}(${errorMessage})` : errorMessage);
+};
+
+const ASSET_CACHE_NAME = 'asset-cache-name';
+const RESOURCE = self.location.pathname;
+const RESOURCE_WITH_QUERY = self.location.pathname + '?foo=bar';
+const RESOURCE_NOT_INDIRECTLY_CACHED = self.location.pathname + '?should_not_resolve_to_resource1';
+const RESOURCE_NOT_PRESENT = self.location.pathname + '.not_present';
+
+let assetCache = null;
+const getAssetCache = async () => {
+  if (!assetCache) {
+    assetCache = await self.caches.open(ASSET_CACHE_NAME);
+  }
+  return assetCache;
+};
+const cacheUrl = async (cache, url) => {
+  if (await cache.match(url)) {
+    return;
+  }
+  return cache.add(url);
+};
+const cacheAssetUrls = async urls => {
+  const cache = await getAssetCache();
+  return Promise.all(urls.map(url => cacheUrl(cache, url).catch(noop)));
+};
+
+self.addEventListener('message', async event => {
+  if (event.data === 'start-test') {
+    await self.caches.delete(ASSET_CACHE_NAME);
+    await cacheAssetUrls([RESOURCE, RESOURCE_WITH_QUERY, RESOURCE_NOT_PRESENT]);
+    const cache = await self.caches.open(ASSET_CACHE_NAME);
+    assertEquals(2, (await cache.keys()).length);
+    assertNotEquals(undefined, await cache.match(RESOURCE));
+    assertNotEquals(undefined, await cache.match(RESOURCE_WITH_QUERY));
+    assertEquals(undefined, await cache.match(RESOURCE_NOT_INDIRECTLY_CACHED));
+    assertEquals(undefined, await cache.match(RESOURCE_NOT_PRESENT));
+    postMessage('SUCCESS');
+    return;
+  }
+  postMessage(`${JSON.stringify(event.data)}-unexpected-message`);
+});
diff --git a/cobalt/black_box_tests/testdata/service_worker_cache_keys_test.html b/cobalt/black_box_tests/testdata/service_worker_cache_keys_test.html
index c5a57e9..0bedc3e 100644
--- a/cobalt/black_box_tests/testdata/service_worker_cache_keys_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_cache_keys_test.html
@@ -25,6 +25,7 @@
 </head>
 <body>
   <script>
+    h5vcc.storage.clearServiceWorkerCache();
     const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
         Promise.all(registrations.map(r => r.unregister())));
     const fail = msg => {
diff --git a/cobalt/black_box_tests/testdata/service_worker_controller_activation_test.html b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test.html
new file mode 100644
index 0000000..56321a8
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2023 The Cobalt Authors. All Rights Reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!--
+  Test for service worker controller activation.
+-->
+
+<html>
+
+<head>
+    <title>Cobalt Service Worker Controller Activation Test</title>
+    <script src='black_box_js_test_utils.js'></script>
+</head>
+
+<body>
+    <script src='service_worker_controller_activation_test_script.js'></script>
+</body>
+
+</html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_script.js b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_script.js
new file mode 100644
index 0000000..b5d6ee9
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_script.js
@@ -0,0 +1,131 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+h5vcc.storage.clearServiceWorkerCache();
+
+const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
+  Promise.all(registrations.map(r => r.unregister())));
+setTearDown(unregisterAll);
+
+function TEST(test) {
+  console.log('[ RUN', test.name, ']');
+  test();
+}
+
+/**
+* @param {KeyboardEvent} event
+*/
+window.onkeydown = function (event) {
+  assertEqual(undefined, self.clients);
+
+  if (!('serviceWorker' in navigator)) {
+    console.log("serviceWorker not in navigator, ending test");
+    onEndTest();
+  }
+
+  navigator.serviceWorker.ready.then(function (registration) {
+    assertNotEqual(null, registration);
+    console.log('(Expected) Registration ready promise',
+      registration, 'with active worker ', registration.active);
+    assertNotEqual(null, registration.active);
+  });
+
+  navigator.serviceWorker.oncontrollerchange = function (event) {
+    console.log('Got oncontrollerchange event', event.target);
+  }
+
+  navigator.serviceWorker.onmessage = function (event) {
+    console.log('Got onmessage event', event.target, event.data);
+  }
+
+  if (event.key == 0) {
+    console.log('Keydown 0');
+    TEST(SuccessfulRegistration);
+  } else if (event.key == 1) {
+    console.log('Keydown 1');
+    TEST(SuccessfulActivation);
+  } else if (event.key == 2) {
+    console.log('Keydown 2');
+    unregisterAll().then(() => onEndTest());
+ }
+}
+
+function SuccessfulRegistration() {
+  navigator.serviceWorker.register('service_worker_controller_activation_test_worker.js', {
+    scope: '/testdata',
+  }).then(function (registration) {
+    console.log('(Expected) Registration Succeeded:',
+      registration);
+    assertNotEqual(null, registration);
+    // The default value for RegistrationOptions.type is
+    // 'imports'.
+    assertEqual('imports', registration.updateViaCache);
+    assertTrue(registration.scope.endsWith('/testdata'));
+
+    // Check that the registration has an activated worker after
+    // some time. The delay used here should be long enough for
+    // the service worker to complete activating and have the
+    // state 'activated'. It has to be longer than the combined
+    // delays in the install or activate event handlers.
+    window.setTimeout(function () {
+      // Since these events are asynchronous, the service
+      // worker can be either of these states.
+      assertNotEqual(null, registration.active);
+      registration.active.postMessage('Registration is active after waiting.');
+      assertEqual('activated',
+        registration.active.state);
+      assertNotEqual(null, navigator.serviceWorker.controller);
+      assertEqual('activated',
+        navigator.serviceWorker.controller.state);
+      if (failed()) window.close();
+      console.log('Reload page');
+      window.location.href =
+        window.location.origin + window.location.pathname +
+        '?result=SuccessfulRegistration';
+    }, 1000);
+  }, function (error) {
+    console.log(`(Unexpected): ${error}`, error);
+    notReached();
+    onEndTest();
+  });
+}
+
+function SuccessfulActivation() {
+  navigator.serviceWorker.getRegistration().then(registration => {
+    assertTrue(!!registration);
+    assertEqual('imports', registration.updateViaCache);
+    assertNotEqual(null, registration.active);
+    assertEqual('activated', registration.active.state);
+
+    if (failed()) window.close();
+    console.log('Reload page');
+    window.location.href =
+      window.location.origin + window.location.pathname +
+      '?result=Success';
+  })
+    .catch(error => {
+      console.log(`(Unexpected): ${error}`, error);
+      notReached();
+      onEndTest();
+    });
+  assertNotEqual(null, navigator.serviceWorker.controller);
+  assertEqual('activated',
+    navigator.serviceWorker.controller.state);
+}
+
+var search = document.createElement('div');
+search.id = window.location.search.replace(/\?result=/, 'Result');
+document.body.appendChild(search);
+
+setupFinished();
diff --git a/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_worker.js b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_worker.js
new file mode 100644
index 0000000..4bda3e0
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_controller_activation_test_worker.js
@@ -0,0 +1,26 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+console.log('Service Worker Script Started');
+self.onmessage = function (event) {
+  console.log('Got onmessage event', event.source, event.target, event.data);
+}
+
+self.oninstall = function (e) {
+  console.log('oninstall event received', e);
+}
+
+self.onactivate = function (e) {
+  console.log('onactivate event received', e);
+}
diff --git a/cobalt/black_box_tests/testdata/service_worker_csp_test.html b/cobalt/black_box_tests/testdata/service_worker_csp_test.html
index ff058e3..7e6b711 100644
--- a/cobalt/black_box_tests/testdata/service_worker_csp_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_csp_test.html
@@ -22,6 +22,8 @@
 
 <body>
   <script>
+  h5vcc.storage.clearServiceWorkerCache();
+
   var window_onerror_count = 0;
   window.onerror = (message, filename, lineno, colno, error) => {
     ++window_onerror_count;
diff --git a/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource.html b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource.html
new file mode 100644
index 0000000..244cc4c
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2023 The Cobalt Authors. All Rights Reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<html>
+<head>
+  <title>Cobalt Service Worker Fetch Main Resource</title>
+  <script src='black_box_js_test_utils.js'></script>
+</head>
+<body>
+  <script>
+    const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
+        Promise.all(registrations.map(r => r.unregister())));
+    const fail = msg => {
+      if (msg) {
+        console.error(msg);
+      }
+      unregisterAll().then(notReached);
+    };
+    const success = () => unregisterAll().then(() => {
+      clearTimeout(timeoutId);
+      onEndTest();
+    });
+    const assertEquals = (expected, actual, msg) => {
+      if (expected === actual) {
+        return;
+      }
+      const errorMessage = `Expected: '${expected}', but was '${actual}'`;
+      fail(msg ? `${msg}(${errorMessage})` : errorMessage);
+    };
+    const timeoutId = window.setTimeout(fail, 5000);
+    navigator.serviceWorker.onmessage = event => {
+      const requests = event.data;
+      assertEquals(2, requests.length);
+      // The sub resource is black_box_js_test_utils.js.
+      const [mainResourceRequest, subResourceRequest] = requests;
+      assertEquals('navigate', mainResourceRequest.mode);
+      assertEquals('cors', subResourceRequest.mode);
+      success();
+    };
+
+    navigator.serviceWorker.getRegistration().then(registration => {
+      if (!registration || !registration.active) {
+        fail('Expected active registration, but none present.');
+      }
+      registration.active.postMessage('start');
+    });
+
+    setupFinished();
+  </script>
+</body>
+</html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.html b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.html
new file mode 100644
index 0000000..eb9d331
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<!--
+  Copyright 2023 The Cobalt Authors. All Rights Reserved.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<html>
+<head>
+  <title>Cobalt Service Worker Fetch Main Resource Test</title>
+  <script src='black_box_js_test_utils.js'></script>
+</head>
+<body>
+  <script>
+    h5vcc.storage.enableCache();
+    const mebibyte = 1024 * 1024;
+    const res = h5vcc.storage.setQuota({
+      other: 14 * mebibyte,
+      html: mebibyte,
+      css: mebibyte,
+      image: mebibyte,
+      font: mebibyte,
+      splash: mebibyte,
+      uncompiled_js: mebibyte,
+      compiled_js: mebibyte,
+      cache_api: mebibyte,
+      service_worker_js: mebibyte,
+      total: 23 * mebibyte,
+    });
+    h5vcc.storage.clearServiceWorkerCache();
+
+    const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
+        Promise.all(registrations.map(r => r.unregister())));
+    const fail = msg => {
+      if (msg) {
+        console.error(msg);
+      }
+      unregisterAll().then(notReached);
+    };
+    const timeoutId = window.setTimeout(fail, 5000);
+    navigator.serviceWorker.ready.then(async () => {
+      clearTimeout(timeoutId);
+      window.location = 'service_worker_fetch_main_resource.html';
+    }).catch(fail);
+
+    unregisterAll().then(() =>
+      navigator.serviceWorker.register('service_worker_fetch_main_resource_test.js')).catch(fail);
+  </script>
+</body>
+</html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.js b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.js
new file mode 100644
index 0000000..19e761f
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_fetch_main_resource_test.js
@@ -0,0 +1,36 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+const postMessage = message => {
+  const options = {
+    includeUncontrolled: false,
+    type: 'window',
+  };
+  self.clients.matchAll(options).then(clients => {
+    clients.forEach(c => {
+      c.postMessage(message);
+    });
+  });
+};
+
+self.addEventListener("install", () => self.skipWaiting());
+self.addEventListener('activate', () => self.clients.claim());
+
+const fetchRequests = [];
+self.addEventListener('message', () => postMessage(fetchRequests));
+self.addEventListener('fetch', ({request: {url, method, mode, headers}}) => {
+  fetchRequests.push({
+    url, method, mode, headers: Array.from(headers.entries()),
+  });
+});
diff --git a/cobalt/black_box_tests/testdata/service_worker_fetch_test.html b/cobalt/black_box_tests/testdata/service_worker_fetch_test.html
index a325b69..1dcc7b7 100644
--- a/cobalt/black_box_tests/testdata/service_worker_fetch_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_fetch_test.html
@@ -25,11 +25,13 @@
 </head>
 <body>
   <script>
+    h5vcc.storage.clearServiceWorkerCache();
+
     const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
         Promise.all(registrations.map(r => r.unregister())));
     const unregisterAndNotReached = () => unregisterAll().then(notReached);
 
-    const fetch_resource = () => fetch('service_worker_fetch_resource.js').then(r => r.text());
+    const fetchResource = () => fetch('service_worker_fetch_resource.js').then(r => r.text());
     const timeoutId = window.setTimeout(unregisterAndNotReached, 10000);
     window.activeServiceWorker = null;
     navigator.serviceWorker.onmessage = event => {
@@ -44,7 +46,7 @@
           unregisterAndNotReached();
           return;
         }
-        fetch_resource().then(body => {
+        fetchResource().then(body => {
           window.activeServiceWorker.postMessage({test: event.data.test, result: body});
         });
         return;
@@ -64,7 +66,7 @@
       window.activeServiceWorker.postMessage('start-test');
     });
 
-    unregisterAll().then(fetch_resource).then(body => {
+    unregisterAll().then(fetchResource).then(body => {
       if ('window.activeServiceWorker.postMessage("script-not-intercepted");\n' !== body) {
         unregisterAndNotReached();
         return;
diff --git a/cobalt/black_box_tests/testdata/service_worker_fetch_test.js b/cobalt/black_box_tests/testdata/service_worker_fetch_test.js
index 22da79e..6b9ca7d 100644
--- a/cobalt/black_box_tests/testdata/service_worker_fetch_test.js
+++ b/cobalt/black_box_tests/testdata/service_worker_fetch_test.js
@@ -89,6 +89,8 @@
 self.addEventListener('fetch', event => {
   fetchEventCount++;
   if (shouldIntercept) {
-    event.respondWith(Promise.resolve(new Response(interceptedBody)));
+    event.respondWith(new Promise(resolve => {
+      setTimeout(() => resolve(new Response(interceptedBody)), 100);
+    }));
   }
 });
diff --git a/cobalt/black_box_tests/testdata/service_worker_get_registrations_test.html b/cobalt/black_box_tests/testdata/service_worker_get_registrations_test.html
index 21cf71d..2c8283b 100644
--- a/cobalt/black_box_tests/testdata/service_worker_get_registrations_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_get_registrations_test.html
@@ -25,6 +25,8 @@
 </head>
 <body>
   <script>
+    h5vcc.storage.clearServiceWorkerCache();
+
     // TODO: check multiple registrations.
     const unregisterAll = () => navigator.serviceWorker.getRegistrations().then(registrations =>
         Promise.all(registrations.map(r => r.unregister())));
diff --git a/cobalt/black_box_tests/testdata/service_worker_message_test.html b/cobalt/black_box_tests/testdata/service_worker_message_test.html
index 8b74c05..4eb4cf4 100644
--- a/cobalt/black_box_tests/testdata/service_worker_message_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_message_test.html
@@ -27,6 +27,8 @@
 
 <body>
     <script>
+        h5vcc.storage.clearServiceWorkerCache();
+
         var expected_event_count = 0;
 
         function count_event(expected_value) {
diff --git a/cobalt/black_box_tests/testdata/service_worker_persist_test_script.js b/cobalt/black_box_tests/testdata/service_worker_persist_test_script.js
index 5638ecd..888aec0 100644
--- a/cobalt/black_box_tests/testdata/service_worker_persist_test_script.js
+++ b/cobalt/black_box_tests/testdata/service_worker_persist_test_script.js
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+h5vcc.storage.clearServiceWorkerCache();
 
 /**
 * @param {KeyboardEvent} event
@@ -40,17 +41,18 @@
     }
 
     if (event.key == 0) {
+        h5vcc.storage.enableCache();
         test_successful_registration();
     } else if (event.key == 1) {
         test_persistent_registration();
     } else if (event.key == 2) {
-        test_persistent_registration_does_not_exist();
+        test_unregistered_persistent_registration_does_not_exist();
     }
 }
 
 function test_successful_registration() {
     console.log('test_successful_registration()');
-    navigator.serviceWorker.register('service_worker_test_worker.js', {
+    navigator.serviceWorker.register('service_worker_test_persisted_worker.js', {
         scope: '/bar/registration/scope',
     }).then(function (registration) {
         console.log('(Expected) Registration Succeeded:',
@@ -74,8 +76,6 @@
                 'Registration active check after timeout',
                 registration);
             assertNotEqual(null, registration.active);
-            registration.active.postMessage(
-                'Registration is active after waiting.');
             console.log('Registration active',
                 registration.active, 'state:',
                 registration.active.state);
@@ -103,20 +103,15 @@
                 'bar/registration/scope'));
 
             window.setTimeout(function () {
-                // TODO(b/259731731): Activate persisted registrations
-                // correctly before enabling these activation checks.
-
-                // console.log(
-                //     'Registration active check after timeout',
-                //     registration);
-                // assertNotEqual(null, registration.active);
-                // registration.active.postMessage(
-                //     'Registration is active after waiting.');
-                // console.log('Registration active',
-                //     registration.active, 'state:',
-                //     registration.active.state);
-                // assertEqual('activated',
-                //     registration.active.state);
+                console.log(
+                    'Registration active check after timeout',
+                    registration);
+                assertNotEqual(null, registration.active);
+                console.log('Registration active',
+                    registration.active, 'state:',
+                    registration.active.state);
+                assertEqual('activated',
+                    registration.active.state);
 
                 registration.unregister()
                 .then(function (success) {
@@ -127,9 +122,6 @@
                     navigator.serviceWorker.getRegistration(
                         'bar/registration/scope')
                         .then(function (registration) {
-                            console.log('(Expected) ' +
-                                'getRegistration Succeeded: ',
-                                registration);
                             assertTrue(null == registration ||
                                 undefined == registration);
                             onEndTest();
@@ -154,8 +146,8 @@
         });
 }
 
-function test_persistent_registration_does_not_exist() {
-    console.log("test_persistent_registration_does_not_exist()");
+function test_unregistered_persistent_registration_does_not_exist() {
+    console.log("test_unregistered_persistent_registration_does_not_exist()");
     navigator.serviceWorker.getRegistration(
         '/bar/registration/scope')
         .then(function (registration) {
diff --git a/cobalt/black_box_tests/testdata/service_worker_test.html b/cobalt/black_box_tests/testdata/service_worker_test.html
index 34782ec..d50434c 100644
--- a/cobalt/black_box_tests/testdata/service_worker_test.html
+++ b/cobalt/black_box_tests/testdata/service_worker_test.html
@@ -22,12 +22,12 @@
 <html>
 
 <head>
-    <title>Cobalt Service Worker Test</title>
-    <script src='black_box_js_test_utils.js'></script>
+  <title>Cobalt Service Worker Test</title>
+  <script nonce="blackboxtest" src='black_box_js_test_utils.js'></script>
 </head>
 
 <body>
-    <script src='service_worker_test_script.js'></script>
+  <script nonce="blackboxtest" src='service_worker_test_script.js'></script>
 </body>
 
 </html>
diff --git a/cobalt/black_box_tests/testdata/service_worker_test_persisted_worker.js b/cobalt/black_box_tests/testdata/service_worker_test_persisted_worker.js
new file mode 100644
index 0000000..c808e3c
--- /dev/null
+++ b/cobalt/black_box_tests/testdata/service_worker_test_persisted_worker.js
@@ -0,0 +1,15 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+console.log('Service Worker Persist Script Started');
diff --git a/cobalt/black_box_tests/testdata/service_worker_test_script.js b/cobalt/black_box_tests/testdata/service_worker_test_script.js
index 55d40eb..3b5f371 100644
--- a/cobalt/black_box_tests/testdata/service_worker_test_script.js
+++ b/cobalt/black_box_tests/testdata/service_worker_test_script.js
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+h5vcc.storage.clearServiceWorkerCache();
+
 const eventCounts = {};
 const countEvent = (fnName, expectedEventCount) => {
   if (fnName in eventCounts) {
@@ -292,7 +294,7 @@
   () => navigator.serviceWorker.register('service_worker_test_nonexist.js')
       .then(fail(`Unknown script did not raise error.`))
       .catch(error => {
-        assertEqual('NetworkError', error.name);
+        assertEqual('SecurityError', error.name);
       }),
   checkSuccessfulRegistration,
   unregisterAll,
diff --git a/cobalt/black_box_tests/tests/deep_links.py b/cobalt/black_box_tests/tests/deep_links.py
index 4a69ffe..211e867 100644
--- a/cobalt/black_box_tests/tests/deep_links.py
+++ b/cobalt/black_box_tests/tests/deep_links.py
@@ -78,6 +78,14 @@
 class DeepLink(black_box_tests.BlackBoxTestCase):
   """Tests firing deep links before web module is loaded."""
 
+  def setUp(self) -> None:
+    _script_loading_signal.clear()
+    return super().setUp()
+
+  def tearDown(self) -> None:
+    _script_loading_signal.clear()
+    return super().tearDown()
+
   def _load_page(self, webdriver, url):
     """Instructs webdriver to navigate to url."""
     try:
diff --git a/cobalt/black_box_tests/tests/service_worker_add_to_cache_test.py b/cobalt/black_box_tests/tests/service_worker_add_to_cache_test.py
new file mode 100644
index 0000000..eaa8051
--- /dev/null
+++ b/cobalt/black_box_tests/tests/service_worker_add_to_cache_test.py
@@ -0,0 +1,28 @@
+# Copyright 2023 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests Service Worker Add to Cache functionality."""
+
+from cobalt.black_box_tests import black_box_tests
+from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer
+
+
+class ServiceWorkerAddToCacheTest(black_box_tests.BlackBoxTestCase):
+
+  def test_service_worker_add_to_cache(self):
+    with ThreadedWebServer(binding_address=self.GetBindingAddress()) as server:
+      url = server.GetURL(
+          file_name='testdata/service_worker_add_to_cache_test.html')
+      with self.CreateCobaltRunner(url=url) as runner:
+        runner.WaitForJSTestsSetup()
+        self.assertTrue(runner.JSTestsSucceeded())
diff --git a/cobalt/black_box_tests/tests/service_worker_controller_activation_test.py b/cobalt/black_box_tests/tests/service_worker_controller_activation_test.py
new file mode 100644
index 0000000..cf79f71
--- /dev/null
+++ b/cobalt/black_box_tests/tests/service_worker_controller_activation_test.py
@@ -0,0 +1,80 @@
+# Copyright 2023 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests Service Worker controller activation functionality."""
+
+import logging
+import os
+from six.moves import SimpleHTTPServer
+
+from cobalt.black_box_tests import black_box_tests
+from cobalt.black_box_tests.threaded_web_server import MakeRequestHandlerClass
+from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer
+from cobalt.tools.automated_testing import webdriver_utils
+
+# The base path of the requested assets is the parent directory.
+_SERVER_ROOT_PATH = os.path.join(os.path.dirname(__file__), os.pardir)
+
+keys = webdriver_utils.import_selenium_module('webdriver.common.keys')
+
+
+class ServiceWorkerRequestDetector(MakeRequestHandlerClass(_SERVER_ROOT_PATH)):
+  """Proxies everything to SimpleHTTPRequestHandler, except some paths."""
+
+  def end_headers(self):
+    self.send_my_headers()
+    SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
+
+  def send_header(self, header, value):
+    # Ensure that the Content-Type for paths ending in '.js' are always
+    # 'text/javascript'.
+    if header == 'Content-Type' and self.path.endswith('.js'):
+      SimpleHTTPServer.SimpleHTTPRequestHandler.send_header(
+          self, header, 'text/javascript')
+    else:
+      SimpleHTTPServer.SimpleHTTPRequestHandler.send_header(self, header, value)
+
+  def send_my_headers(self):
+    # Add 'Service-Worker-Allowed' header for the main service worker scripts.
+    if self.path.endswith(
+        '/service_worker_controller_activation_test_worker.js'):
+      self.send_header('Service-Worker-Allowed', '/testdata')
+
+
+class ServiceWorkerControllerActivationTest(black_box_tests.BlackBoxTestCase):
+  """Test basic Service Worker functionality."""
+
+  def test_service_worker_controller_activation(self):
+
+    with ThreadedWebServer(
+        ServiceWorkerRequestDetector,
+        binding_address=self.GetBindingAddress()) as server:
+      url = server.GetURL(
+          file_name='testdata/service_worker_controller_activation_test.html')
+
+      with self.CreateCobaltRunner(url=url) as runner:
+        runner.WaitForJSTestsSetup()
+
+        logging.info('SendKeys NUMPAD0.')
+        runner.SendKeys(keys.Keys.NUMPAD0)
+        logging.info('Wait.')
+        runner.PollUntilFoundOrTestsFailedWithReconnects(
+            '#ResultSuccessfulRegistration')
+
+        logging.info('SendKeys NUMPAD1.')
+        runner.SendKeys(keys.Keys.NUMPAD1)
+        runner.PollUntilFoundOrTestsFailedWithReconnects('#ResultSuccess')
+
+        logging.info('SendKeys NUMPAD2.')
+        runner.SendKeys(keys.Keys.NUMPAD2)
+        self.assertTrue(runner.JSTestsSucceeded())
diff --git a/cobalt/black_box_tests/tests/service_worker_fetch_main_resource_test.py b/cobalt/black_box_tests/tests/service_worker_fetch_main_resource_test.py
new file mode 100644
index 0000000..aeec28d
--- /dev/null
+++ b/cobalt/black_box_tests/tests/service_worker_fetch_main_resource_test.py
@@ -0,0 +1,28 @@
+# Copyright 2023 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests Service Worker Fetch Main Resource functionality."""
+
+from cobalt.black_box_tests import black_box_tests
+from cobalt.black_box_tests.threaded_web_server import ThreadedWebServer
+
+
+class ServiceWorkerFetchMainResourceTest(black_box_tests.BlackBoxTestCase):
+
+  def test_service_worker_fetch_main_resource(self):
+    with ThreadedWebServer(binding_address=self.GetBindingAddress()) as server:
+      url = server.GetURL(
+          file_name='testdata/service_worker_fetch_main_resource_test.html')
+      with self.CreateCobaltRunner(url=url) as runner:
+        runner.WaitForJSTestsSetup()
+        self.assertTrue(runner.JSTestsSucceeded())
diff --git a/cobalt/black_box_tests/tests/service_worker_test.py b/cobalt/black_box_tests/tests/service_worker_test.py
index f66b2dc..fc5c7e5 100644
--- a/cobalt/black_box_tests/tests/service_worker_test.py
+++ b/cobalt/black_box_tests/tests/service_worker_test.py
@@ -23,16 +23,33 @@
 # The base path of the requested assets is the parent directory.
 _SERVER_ROOT_PATH = os.path.join(os.path.dirname(__file__), os.pardir)
 
+paths_to_headers = {
+    'service_worker_test.html': {
+        'Content-Security-Policy':
+            "script-src 'nonce-blackboxtest' ; worker-src 'self'"
+    },
+    'service_worker_test_worker.js': {
+        'Content-Security-Policy':
+            "connect-src 'self' ; script-src 'none' ; worker-src 'self'"
+    }
+}
+
+#path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+
 
 class ServiceWorkerRequestDetector(MakeRequestHandlerClass(_SERVER_ROOT_PATH)):
   """Proxies everything to SimpleHTTPRequestHandler, except some paths."""
 
   def end_headers(self):
     self.send_my_headers()
-
     SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self)
 
   def send_header(self, header, value):
+    for partial_path, headers in paths_to_headers.items():
+      if partial_path in self.path:
+        for header_key, header_value in headers.items():
+          SimpleHTTPServer.SimpleHTTPRequestHandler.send_header(
+              self, header_key, header_value)
     # Ensure that the Content-Type for paths ending in '.js' are always
     # 'text/javascript'.
     if header == 'Content-Type' and self.path.endswith('.js'):
@@ -43,7 +60,9 @@
 
   def send_my_headers(self):
     # Add 'Service-Worker-Allowed' header for the main service worker scripts.
-    if self.path.endswith('/service_worker_test_worker.js'):
+    if self.path.endswith(
+        '/service_worker_test_worker.js') or self.path.endswith(
+            '/service_worker_test_persisted_worker.js'):
       self.send_header('Service-Worker-Allowed', '/bar')
 
   def do_GET(self):  # pylint: disable=invalid-name
@@ -58,12 +77,11 @@
 
       if not (service_worker_request_header
               == expected_service_worker_request_header):
-        raise ValueError('Service-Worker HTTP request header value does not '
-                         'match with expected value.\n'
-                         'Header value:%s\n'
-                         'Expected value:%s' %
-                         (service_worker_request_header,
-                          expected_service_worker_request_header))
+        raise ValueError(
+            'Service-Worker HTTP request header value does not '
+            'match with expected value.\n'
+            f'Header value:{service_worker_request_header}\n'
+            f'Expected value:{expected_service_worker_request_header}')
 
     return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
 
diff --git a/cobalt/browser/BUILD.gn b/cobalt/browser/BUILD.gn
index e8cf8d3..07a6de0 100644
--- a/cobalt/browser/BUILD.gn
+++ b/cobalt/browser/BUILD.gn
@@ -70,6 +70,9 @@
       "//cobalt/content/fonts:fonts_xml",
     ]
   }
+  if (sb_is_evergreen) {
+    data_deps += [ "//cobalt/updater/version_manifest:copy_version_manifest" ]
+  }
   if (!is_gold) {
     data_deps += [
       "//cobalt/debug/backend/content:copy_backend_web_files",
diff --git a/cobalt/browser/application.cc b/cobalt/browser/application.cc
index 07af384..fe4c098 100644
--- a/cobalt/browser/application.cc
+++ b/cobalt/browser/application.cc
@@ -852,8 +852,9 @@
 #endif  // defined(COBALT_FORCE_CSP)
 
   network_module_options.https_requirement = security_flags.https_requirement;
-  options.web_module_options.require_csp = security_flags.csp_header_policy;
-  options.web_module_options.csp_enforcement_mode = web::kCspEnforcementEnable;
+  options.web_module_options.csp_header_policy =
+      security_flags.csp_header_policy;
+  options.web_module_options.csp_enforcement_type = web::kCspEnforcementEnable;
 
   options.requested_viewport_size = requested_viewport_size;
 
diff --git a/cobalt/browser/browser_module.cc b/cobalt/browser/browser_module.cc
index c82aa97..26d036a 100644
--- a/cobalt/browser/browser_module.cc
+++ b/cobalt/browser/browser_module.cc
@@ -293,7 +293,7 @@
 
   platform_info_.reset(new browser::UserAgentPlatformInfo());
   service_worker_registry_.reset(new ServiceWorkerRegistry(
-      &web_settings_, network_module, platform_info_.get()));
+      &web_settings_, network_module, platform_info_.get(), url));
 
 #if SB_HAS(CORE_DUMP_HANDLER_SUPPORT)
   SbCoreDumpRegisterHandler(BrowserModule::CoreDumpHandler, this);
@@ -529,6 +529,15 @@
 
   main_web_module_layer_->Reset();
 
+  // Service worker should only start for HTTP or HTTPS fetches.
+  // https://fetch.spec.whatwg.org/commit-snapshots/8f8ab504da6ca9681db5c7f8aa3d1f4b6bf8840c/#http-fetch
+  bool can_start_service_worker = url.SchemeIsHTTPOrHTTPS();
+  auto service_worker_started_event = std::make_unique<base::WaitableEvent>();
+  if (can_start_service_worker) {
+    service_worker_registry_->EnsureServiceWorkerStarted(
+        url::Origin::Create(url), url, service_worker_started_event.get());
+  }
+
   // Wait until after the old WebModule is destroyed before setting the navigate
   // time so that it won't be included in the time taken to load the URL.
   navigate_time_ = base::TimeTicks::Now().ToInternalValue();
@@ -617,6 +626,10 @@
       service_worker_registry_->service_worker_jobs();
   options.web_options.platform_info = platform_info_.get();
   web_module_.reset(new WebModule("MainWebModule"));
+  // Wait for service worker to start if one exists.
+  if (can_start_service_worker) {
+    service_worker_started_event->Wait();
+  }
   web_module_->Run(
       url, application_state_, scroll_engine_.get(),
       base::Bind(&BrowserModule::QueueOnRenderTreeProduced,
@@ -1191,6 +1204,7 @@
 
 void BrowserModule::OnError(const GURL& url, const std::string& error) {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::OnError()");
+  LOG(ERROR) << error;
   if (base::MessageLoop::current() != self_message_loop_) {
     self_message_loop_->task_runner()->PostTask(
         FROM_HERE, base::Bind(&BrowserModule::OnError, weak_this_, url, error));
diff --git a/cobalt/browser/debug_console.cc b/cobalt/browser/debug_console.cc
index 197233b..b08fed0 100644
--- a/cobalt/browser/debug_console.cc
+++ b/cobalt/browser/debug_console.cc
@@ -121,7 +121,7 @@
   web_module_options.image_cache_capacity = 0;
   // Disable CSP for the Debugger's WebModule. This will also allow eval() in
   // javascript.
-  web_module_options.csp_enforcement_mode = web::kCspEnforcementDisable;
+  web_module_options.csp_enforcement_type = web::kCspEnforcementDisable;
   web_module_options.csp_insecure_allowed_token =
       web::CspDelegateFactory::GetInsecureAllowedToken();
 
diff --git a/cobalt/browser/service_worker_registry.cc b/cobalt/browser/service_worker_registry.cc
index 2fdd068..23a1a1c 100644
--- a/cobalt/browser/service_worker_registry.cc
+++ b/cobalt/browser/service_worker_registry.cc
@@ -39,7 +39,7 @@
 
 ServiceWorkerRegistry::ServiceWorkerRegistry(
     web::WebSettings* web_settings, network::NetworkModule* network_module,
-    web::UserAgentPlatformInfo* platform_info)
+    web::UserAgentPlatformInfo* platform_info, const GURL& url)
     : thread_("ServiceWorkerRegistry") {
   if (!thread_.Start()) return;
   DCHECK(message_loop());
@@ -47,7 +47,7 @@
   message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&ServiceWorkerRegistry::Initialize, base::Unretained(this),
-                 web_settings, network_module, platform_info));
+                 web_settings, network_module, platform_info, url));
 
   // Register as a destruction observer to shut down the Web Agent once all
   // pending tasks have been executed and the message loop is about to be
@@ -73,8 +73,16 @@
   // Ensure that the destruction observer got added before stopping the thread.
   // Stop the thread. This will cause the destruction observer to be notified.
   destruction_observer_added_.Wait();
-  service_worker_jobs_->Stop();
+  DCHECK_NE(thread_.message_loop(), base::MessageLoop::current());
   thread_.Stop();
+  DCHECK(!service_worker_jobs_);
+}
+
+void ServiceWorkerRegistry::EnsureServiceWorkerStarted(
+    const url::Origin& storage_key, const GURL& client_url,
+    base::WaitableEvent* done_event) {
+  service_worker_jobs()->EnsureServiceWorkerStarted(storage_key, client_url,
+                                                    done_event);
 }
 
 worker::ServiceWorkerJobs* ServiceWorkerRegistry::service_worker_jobs() {
@@ -85,11 +93,11 @@
 
 void ServiceWorkerRegistry::Initialize(
     web::WebSettings* web_settings, network::NetworkModule* network_module,
-    web::UserAgentPlatformInfo* platform_info) {
+    web::UserAgentPlatformInfo* platform_info, const GURL& url) {
   TRACE_EVENT0("cobalt::browser", "ServiceWorkerRegistry::Initialize()");
   DCHECK_EQ(base::MessageLoop::current(), message_loop());
   service_worker_jobs_.reset(new worker::ServiceWorkerJobs(
-      web_settings, network_module, platform_info, message_loop()));
+      web_settings, network_module, platform_info, message_loop(), url));
 }
 
 }  // namespace browser
diff --git a/cobalt/browser/service_worker_registry.h b/cobalt/browser/service_worker_registry.h
index 14abedd..8c37083 100644
--- a/cobalt/browser/service_worker_registry.h
+++ b/cobalt/browser/service_worker_registry.h
@@ -34,7 +34,8 @@
  public:
   ServiceWorkerRegistry(web::WebSettings* web_settings,
                         network::NetworkModule* network_module,
-                        web::UserAgentPlatformInfo* platform_info);
+                        web::UserAgentPlatformInfo* platform_info,
+                        const GURL& url);
   ~ServiceWorkerRegistry();
 
   // The message loop this object is running on.
@@ -43,6 +44,10 @@
   // From base::MessageLoop::DestructionObserver.
   void WillDestroyCurrentMessageLoop() override;
 
+  void EnsureServiceWorkerStarted(const url::Origin& storage_key,
+                                  const GURL& client_url,
+                                  base::WaitableEvent* done_event);
+
   worker::ServiceWorkerJobs* service_worker_jobs();
 
  private:
@@ -50,7 +55,7 @@
   // the dedicated thread.
   void Initialize(web::WebSettings* web_settings,
                   network::NetworkModule* network_module,
-                  web::UserAgentPlatformInfo* platform_info);
+                  web::UserAgentPlatformInfo* platform_info, const GURL& url);
 
   // The thread created and owned by the Service Worker Registry.
   // All registry mutations occur on this thread. The thread has to outlive all
diff --git a/cobalt/browser/web_module.cc b/cobalt/browser/web_module.cc
index dc7ae32..3531cbf 100644
--- a/cobalt/browser/web_module.cc
+++ b/cobalt/browser/web_module.cc
@@ -27,6 +27,7 @@
 #include "base/optional.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
 #include "cobalt/base/c_val.h"
 #include "cobalt/base/debugger_hooks.h"
@@ -109,6 +110,25 @@
   }
 }
 
+void CancelScroll(ui_navigation::scroll_engine::ScrollEngine* scroll_engine,
+                  const scoped_refptr<ui_navigation::NavItem>& nav_item) {
+  auto nav_items = std::vector<scoped_refptr<ui_navigation::NavItem>>{nav_item};
+  scroll_engine->thread()->message_loop()->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&ui_navigation::scroll_engine::ScrollEngine::
+                                CancelActiveScrollsForNavItems,
+                            base::Unretained(scroll_engine), nav_items));
+}
+
+dom::Window::NavItemCallback CancelScrollCallback(
+    ui_navigation::scroll_engine::ScrollEngine* scroll_engine) {
+  if (scroll_engine) {
+    return base::Bind(CancelScroll, base::Unretained(scroll_engine));
+  } else {
+    return base::Callback<void(
+        const scoped_refptr<cobalt::ui_navigation::NavItem>& nav_item)>();
+  }
+}
+
 }  // namespace
 
 // Private WebModule implementation. Each WebModule owns a single instance of
@@ -291,8 +311,6 @@
   void ProcessOnRenderTreeRasterized(const base::TimeTicks& produced_time,
                                      const base::TimeTicks& rasterized_time);
 
-  void OnCspPolicyChanged();
-
   scoped_refptr<script::GlobalEnvironment> global_environment() {
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
     return web_context_->global_environment();
@@ -514,7 +532,7 @@
   dom_parser_.reset(new dom_parser::Parser(
       kDOMMaxElementDepth,
       base::Bind(&WebModule::Impl::OnLoadComplete, base::Unretained(this)),
-      data.options.require_csp));
+      data.options.csp_header_policy));
   DCHECK(dom_parser_);
 
   on_before_unload_fired_but_not_handled_ =
@@ -581,7 +599,7 @@
     memory_info = stub_decoder_buffer_memory_info_.get();
   }
 
-  web_context_->setup_environment_settings(new dom::DOMSettings(
+  web_context_->SetupEnvironmentSettings(new dom::DOMSettings(
       debugger_hooks_, kDOMMaxElementDepth, media_source_registry_.get(),
       data.can_play_type_handler, memory_info, &mutation_observer_task_manager_,
       data.options.dom_settings_options));
@@ -597,6 +615,9 @@
   dom::Window::CacheCallback splash_screen_cache_callback =
       CacheUrlContentCallback(data.options.splash_screen_cache);
 
+  dom::Window::NavItemCallback cancel_scroll_callback =
+      CancelScrollCallback(data.scroll_engine);
+
   // These members will reference other |Traceable|s, however are not
   // accessible from |Window|, so we must explicitly add them as roots.
   web_context_->global_environment()->AddRoot(&mutation_observer_task_manager_);
@@ -635,9 +656,10 @@
       base::GetSystemLanguageScript(), data.options.navigation_callback,
       base::Bind(&WebModule::Impl::OnLoadComplete, base::Unretained(this)),
       web_context_->network_module()->cookie_jar(),
-      web_context_->network_module()->GetPostSender(), data.options.require_csp,
-      data.options.csp_enforcement_mode,
-      base::Bind(&WebModule::Impl::OnCspPolicyChanged, base::Unretained(this)),
+      web::CspDelegate::Options(web_context_->network_module()->GetPostSender(),
+                                data.options.csp_header_policy,
+                                data.options.csp_enforcement_type,
+                                data.options.csp_insecure_allowed_token),
       base::Bind(&WebModule::Impl::OnRanAnimationFrameCallbacks,
                  base::Unretained(this)),
       data.window_close_callback, data.window_minimize_callback,
@@ -645,10 +667,11 @@
       base::Bind(&WebModule::Impl::OnStartDispatchEvent,
                  base::Unretained(this)),
       base::Bind(&WebModule::Impl::OnStopDispatchEvent, base::Unretained(this)),
-      data.options.provide_screenshot_function, synchronous_loader_interrupt_,
-      data.options.enable_inline_script_warnings, data.ui_nav_root,
-      data.options.enable_map_to_mesh, data.options.csp_insecure_allowed_token,
-      data.dom_max_element_depth, data.options.video_playback_rate_multiplier,
+      data.options.provide_screenshot_function, cancel_scroll_callback,
+      synchronous_loader_interrupt_, data.options.enable_inline_script_warnings,
+      data.ui_nav_root, data.options.enable_map_to_mesh,
+      data.options.csp_insecure_allowed_token, data.dom_max_element_depth,
+      data.options.video_playback_rate_multiplier,
 #if defined(ENABLE_TEST_RUNNER)
       data.options.layout_trigger == layout::LayoutManager::kTestRunnerMode
           ? dom::Window::kClockTypeTestRunner
@@ -700,7 +723,7 @@
   DCHECK(layout_manager_);
 
 #if !defined(COBALT_FORCE_CSP)
-  if (data.options.csp_enforcement_mode == web::kCspEnforcementDisable) {
+  if (data.options.csp_enforcement_type == web::kCspEnforcementDisable) {
     // If CSP is disabled, enable eval(). Otherwise, it will be enabled by
     // a CSP directive.
     web_context_->global_environment()->EnableEval();
@@ -734,6 +757,7 @@
       data.options.collect_unload_event_time_callback;
 
   is_running_ = true;
+  web_context_->SetupFinished();
 }
 
 WebModule::Impl::~Impl() {
@@ -1015,21 +1039,6 @@
   }
 }
 
-void WebModule::Impl::OnCspPolicyChanged() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(is_running_);
-  DCHECK(window_);
-  DCHECK(window_->csp_delegate());
-
-  std::string eval_disabled_message;
-  bool allow_eval = window_->csp_delegate()->AllowEval(&eval_disabled_message);
-  if (allow_eval) {
-    web_context_->global_environment()->EnableEval();
-  } else {
-    web_context_->global_environment()->DisableEval(eval_disabled_message);
-  }
-}
-
 bool WebModule::Impl::ReportScriptError(
     const script::ErrorReport& error_report) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/cobalt/browser/web_module.h b/cobalt/browser/web_module.h
index d3fa41c..6b0f07c 100644
--- a/cobalt/browser/web_module.h
+++ b/cobalt/browser/web_module.h
@@ -24,7 +24,6 @@
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
-#include "base/threading/thread_checker.h"
 #include "cobalt/base/address_sanitizer.h"
 #include "cobalt/base/source_location.h"
 #include "cobalt/browser/lifecycle_observer.h"
@@ -121,7 +120,7 @@
     dom::DOMSettings::Options dom_settings_options;
 
     // Whether Cobalt is forbidden to render without receiving CSP headers.
-    csp::CSPHeaderPolicy require_csp;
+    csp::CSPHeaderPolicy csp_header_policy;
 
     // If true, Cobalt will log a warning each time it parses a non-async
     // <script> tag inlined in HTML.  Cobalt has a known issue where if it is
@@ -149,7 +148,7 @@
     bool enable_map_to_mesh = true;
 
     // Content Security Policy enforcement mode for this web module.
-    web::CspEnforcementType csp_enforcement_mode = web::kCspEnforcementEnable;
+    web::CspEnforcementType csp_enforcement_type = web::kCspEnforcementEnable;
 
     // Token obtained from CSP to allow creation of insecure delegates.
     int csp_insecure_allowed_token = 0;
diff --git a/cobalt/build/build.id b/cobalt/build/build.id
index 7dca786..0a3476e 100644
--- a/cobalt/build/build.id
+++ b/cobalt/build/build.id
@@ -1 +1 @@
-310436
\ No newline at end of file
+311259
\ No newline at end of file
diff --git a/cobalt/cache/cache.cc b/cobalt/cache/cache.cc
index 2dc360a..8082d0a 100644
--- a/cobalt/cache/cache.cc
+++ b/cobalt/cache/cache.cc
@@ -22,12 +22,12 @@
 #include "base/files/file_util.h"
 #include "base/memory/singleton.h"
 #include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "cobalt/configuration/configuration.h"
 #include "cobalt/extension/javascript_cache.h"
 #include "cobalt/persistent_storage/persistent_settings.h"
 #include "net/disk_cache/cobalt/cobalt_backend_impl.h"
-#include "starboard/common/murmurhash2.h"
 #include "starboard/configuration_constants.h"
 #include "starboard/system.h"
 
@@ -96,11 +96,6 @@
   return base::Singleton<Cache, base::LeakySingletonTraits<Cache>>::get();
 }
 
-// static
-uint32_t Cache::CreateKey(const std::string& s) {
-  return starboard::MurmurHash2_32(s.c_str(), s.size());
-}
-
 bool Cache::Delete(disk_cache::ResourceType resource_type, uint32_t key) {
   auto* memory_capped_directory = GetMemoryCappedDirectory(resource_type);
   if (memory_capped_directory) {
@@ -131,13 +126,13 @@
   return std::vector<uint32_t>();
 }
 
-std::unique_ptr<base::Value> Cache::Metadata(
+base::Optional<base::Value> Cache::Metadata(
     disk_cache::ResourceType resource_type, uint32_t key) {
   auto* memory_capped_directory = GetMemoryCappedDirectory(resource_type);
   if (memory_capped_directory) {
     return memory_capped_directory->Metadata(key);
   }
-  return nullptr;
+  return base::nullopt;
 }
 
 std::unique_ptr<std::vector<uint8_t>> Cache::Retrieve(
@@ -252,7 +247,8 @@
 
 void Cache::Resize(disk_cache::ResourceType resource_type, uint32_t bytes) {
   if (resource_type != disk_cache::ResourceType::kCacheApi &&
-      resource_type != disk_cache::ResourceType::kCompiledScript)
+      resource_type != disk_cache::ResourceType::kCompiledScript &&
+      resource_type != disk_cache::ResourceType::kServiceWorkerScript)
     return;
   if (bytes == disk_cache::kTypeMetadata[resource_type].max_size_bytes) return;
 
@@ -328,12 +324,24 @@
 
 bool Cache::CanCache(disk_cache::ResourceType resource_type,
                      uint32_t data_size) {
-  return enabled_ &&
-         cobalt::configuration::Configuration::GetInstance()
-             ->CobaltCanStoreCompiledJavascript() &&
-         data_size > 0u &&
-         data_size >= GetMinSizeToCacheInBytes(resource_type) &&
-         data_size <= GetMaxCacheStorageInBytes(resource_type);
+  bool size_okay = data_size > 0u &&
+                   data_size >= GetMinSizeToCacheInBytes(resource_type) &&
+                   data_size <= GetMaxCacheStorageInBytes(resource_type);
+  if (!size_okay) {
+    return false;
+  }
+  if (resource_type == disk_cache::ResourceType::kServiceWorkerScript ||
+      resource_type == disk_cache::ResourceType::kCacheApi) {
+    return true;
+  }
+  if (!enabled_) {
+    return false;
+  }
+  if (resource_type == disk_cache::ResourceType::kCompiledScript) {
+    return cobalt::configuration::Configuration::GetInstance()
+        ->CobaltCanStoreCompiledJavascript();
+  }
+  return true;
 }
 
 }  // namespace cache
diff --git a/cobalt/cache/cache.h b/cobalt/cache/cache.h
index fc9339b..40bd225 100644
--- a/cobalt/cache/cache.h
+++ b/cobalt/cache/cache.h
@@ -45,15 +45,14 @@
 class Cache {
  public:
   static Cache* GetInstance();
-  static uint32_t CreateKey(const std::string& s);
 
   bool Delete(disk_cache::ResourceType resource_type, uint32_t key);
   void Delete(disk_cache::ResourceType resource_type);
   void DeleteAll();
   std::vector<uint32_t> KeysWithMetadata(
       disk_cache::ResourceType resource_type);
-  std::unique_ptr<base::Value> Metadata(disk_cache::ResourceType resource_type,
-                                        uint32_t key);
+  base::Optional<base::Value> Metadata(disk_cache::ResourceType resource_type,
+                                       uint32_t key);
   std::unique_ptr<std::vector<uint8_t>> Retrieve(
       disk_cache::ResourceType resource_type, uint32_t key,
       std::function<std::pair<std::unique_ptr<std::vector<uint8_t>>,
diff --git a/cobalt/cache/memory_capped_directory.cc b/cobalt/cache/memory_capped_directory.cc
index b44b3c6..d6c40fd 100644
--- a/cobalt/cache/memory_capped_directory.cc
+++ b/cobalt/cache/memory_capped_directory.cc
@@ -126,7 +126,7 @@
 }
 
 std::vector<uint32_t> MemoryCappedDirectory::KeysWithMetadata() {
-  std::vector<uint32_t> keys(file_keys_with_metadata_.size());
+  std::vector<uint32_t> keys;
   for (auto it = file_keys_with_metadata_.begin();
        it != file_keys_with_metadata_.end(); ++it) {
     keys.push_back(it->second);
@@ -134,14 +134,15 @@
   return keys;
 }
 
-std::unique_ptr<base::Value> MemoryCappedDirectory::Metadata(uint32_t key) {
+base::Optional<base::Value> MemoryCappedDirectory::Metadata(uint32_t key) {
   auto metadata_path = GetFilePath(key).AddExtension(kMetadataExtension);
   if (!base::PathExists(metadata_path)) {
-    return nullptr;
+    return base::nullopt;
   }
   std::string serialized_metadata;
   base::ReadFileToString(metadata_path, &serialized_metadata);
-  return base::JSONReader::Read(serialized_metadata);
+  return base::Value::FromUniquePtrValue(
+      base::JSONReader::Read(serialized_metadata));
 }
 
 std::unique_ptr<std::vector<uint8_t>> MemoryCappedDirectory::Retrieve(
diff --git a/cobalt/cache/memory_capped_directory.h b/cobalt/cache/memory_capped_directory.h
index 39d227d..6bbe028 100644
--- a/cobalt/cache/memory_capped_directory.h
+++ b/cobalt/cache/memory_capped_directory.h
@@ -54,7 +54,7 @@
   bool Delete(uint32_t key);
   void DeleteAll();
   std::vector<uint32_t> KeysWithMetadata();
-  std::unique_ptr<base::Value> Metadata(uint32_t key);
+  base::Optional<base::Value> Metadata(uint32_t key);
   std::unique_ptr<std::vector<uint8_t>> Retrieve(uint32_t key);
   void Store(uint32_t key, const std::vector<uint8_t>& data,
              const base::Optional<base::Value>& metadata);
diff --git a/cobalt/content/fonts/config/android/fonts.xml b/cobalt/content/fonts/config/android/fonts.xml
index 9ced68c..dcdfb2b 100644
--- a/cobalt/content/fonts/config/android/fonts.xml
+++ b/cobalt/content/fonts/config/android/fonts.xml
@@ -170,15 +170,13 @@
     -->
     <family fallback_priority="0" name="Noto Naskh Arabic UI">
         <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
-        <font weight="400" style="normal">NotoNaskhUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-        <font weight="700" style="normal">NotoNaskhUI-Bold.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
-        <font weight="400" style="normal">NotoSansEthiopic-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansEthiopic-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Ethiopic" postscript_name="NotoSansEthiopic-Regular">NotoSansEthiopic-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Ethiopic Bold" postscript_name="NotoSansEthiopic-Bold">NotoSansEthiopic-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
@@ -193,22 +191,24 @@
         <font weight="400" style="normal">NotoSansArmenian-Regular.otf</font>
         <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansArmenian-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansArmenian-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansArmenian-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Armenian" postscript_name="NotoSansArmenian-Regular">NotoSansArmenian-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Armenian Bold" postscript_name="NotoSansArmenian-Bold">NotoSansArmenian-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
         <font weight="400" style="normal">NotoSansGeorgian-Regular.otf</font>
         <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansGeorgian-Bold.otf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Georgian" postscript_name="NotoSansGeorgian-Regular">NotoSansGeorgian-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Georgian Bold" postscript_name="NotoSansGeorgian-Bold">NotoSansGeorgian-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
         <font weight="400" style="normal">NotoSansDevanagariUI-Regular.otf</font>
         <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansDevanagariUI-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansDevanagariUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansDevanagariUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Devanagari UI" postscript_name="NotoSansDevanagariUI-Regular">NotoSansDevanagariUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Devanagari UI Bold" postscript_name="NotoSansDevanagariUI-Bold">NotoSansDevanagariUI-VF.ttf</font>
     </family>
     <!-- Gujarati should come after Devanagari -->
     <family>
@@ -219,44 +219,44 @@
     <family>
         <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
-        <font weight="400" style="normal">NotoSansGurmukhiUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansGurmukhiUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Gurmukhi UI" postscript_name="NotoSansGurmukhiUI-Regular">NotoSansGurmukhiUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Gurmukhi UI Bold" postscript_name="NotoSansGurmukhiUI-Bold">NotoSansGurmukhiUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
         <font weight="400" style="normal">NotoSansTamilUI-Regular.otf</font>
         <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansTamilUI-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansTamilUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansTamilUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Tamil UI" postscript_name="NotoSansTamilUI-Regular">NotoSansTamilUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Tamil UI Bold" postscript_name="NotoSansTamilUI-Bold">NotoSansTamilUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
         <font weight="400" style="normal">NotoSansMalayalamUI-Regular.otf</font>
         <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansMalayalamUI-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansMalayalamUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansMalayalamUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Malayalam UI" postscript_name="NotoSansMalayalamUI-Regular">NotoSansMalayalamUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Malayalam UI Bold" postscript_name="NotoSansMalayalamUI-Bold">NotoSansMalayalamUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
         <font weight="400" style="normal">NotoSansBengaliUI-Regular.otf</font>
         <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansBengaliUI-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansBengaliUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansBengaliUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Bengali UI" postscript_name="NotoSansBengaliUI-Regular">NotoSansBengaliUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Bengali UI Bold" postscript_name="NotoSansBengaliUI-Bold">NotoSansBengaliUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
-        <font weight="400" style="normal">NotoSansTeluguUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansTeluguUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Telugu UI" postscript_name="NotoSansTeluguUI-Regular">NotoSansTeluguUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Telugu UI Bold" postscript_name="NotoSansTeluguUI-Bold">NotoSansTeluguUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
-        <font weight="400" style="normal">NotoSansKannadaUI-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansKannadaUI-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Kannada UI" postscript_name="NotoSansKannadaUI-Regular">NotoSansKannadaUI-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Kannada UI Bold" postscript_name="NotoSansKannadaUI-Bold">NotoSansKannadaUI-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
@@ -267,8 +267,8 @@
         <font weight="400" style="normal">NotoSansSinhala-Regular.otf</font>
         <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
         <font weight="700" style="normal">NotoSansSinhala-Bold.otf</font>
-        <font weight="400" style="normal">NotoSansSinhala-VF.ttf</font>
-        <font weight="700" style="normal">NotoSansSinhala-VF.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Sinhala" postscript_name="NotoSansSinhala-Regular">NotoSansSinhala-VF.ttf</font>
+        <font weight="700" style="normal" tag_wght="700" font_name="Noto Sans Sinhala Bold" postscript_name="NotoSansSinhala-Bold">NotoSansSinhala-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
@@ -294,6 +294,7 @@
     </family>
     <family>
         <font weight="400" style="normal">NotoSansAdlam-Regular.ttf</font>
+        <font weight="400" style="normal" tag_wght="400" font_name="Noto Sans Adlam" postscript_name="NotoSansAdlam-Regular">NotoSansAdlam-VF.ttf</font>
     </family>
     <family>
         <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font>
@@ -481,18 +482,11 @@
         <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
     </family>
     <family>
-        <font weight="400" style="normal">Lohit-Odia.ttf</font>
-    </family>
-    <family>
         <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
     </family>
     <family lang="zh-Hans">
         <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
     </family>
-    <family lang="zh-Hans">
-        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
-        <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
-    </family>
     <family lang="zh-Hant">
         <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
     </family>
@@ -509,12 +503,6 @@
     <family lang="ko">
         <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
     </family>
-    <family lang="ko">
-        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
-    </family>
-    <family>
-        <font weight="400" style="normal">NanumGothic.ttf</font>
-    </family>
     <family>
         <font weight="400" style="normal" disable_synthetic_bolding="true">NotoColorEmoji.ttf</font>
     </family>
@@ -529,9 +517,6 @@
     <family>
         <font weight="400" style="normal" disable_synthetic_bolding="true">DroidSansFallback.ttf</font>
     </family>
-    <family lang="ja">
-        <font weight="400" style="normal">MTLmr3m.ttf</font>
-    </family>
     <!--
         Tai Le, Yi, Mongolian, and Phags-pa are intentionally kept last, to make sure they don't
         override the East Asian punctuation for Chinese.
@@ -548,49 +533,4 @@
     <family>
         <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font>
     </family>
-
-
-    <!--
-        Include font files on android version R under /system/fonts directory.
-        The program will find the first font file that contains the glyph for the character,
-        when no font file has the glyph, it will show broken string, to avoid this, include fonts
-        files on the android OS.
-    -->
-    <family>
-            <font weight="400" style="normal">NotoSansAdlam-VF.ttf</font>
-            <font weight="700" style="normal">NotoSansAdlam-VF.ttf</font>
-    </family>
-    <family>
-            <font weight="400" style="normal">NotoSansGeorgian-VF.ttf</font>
-            <font weight="700" style="normal">NotoSansGeorgian-VF.ttf</font>
-    </family>
-    <family>
-            <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font>
-    </family>
-    <family>
-            <font weight="400" style="normal">RobotoCondensed-Medium.ttf</font>
-    </family>
-    <family>
-            <font weight="400" style="normal">RobotoCondensed-MediumItalic.ttf</font>
-    </family>
-
-    <!--
-        Include font files on android version S under /system/fonts directory.
-    -->
-    <family lang="zh-Hans">
-        <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
-    </family>
-    <family lang="zh-Hant,zh-Bopo">
-        <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
-    </family>
-    <family lang="ja">
-        <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
-    </family>
-    <family lang="ko">
-        <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font>
-        <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font>
-    </family>
 </familyset>
diff --git a/cobalt/content/licenses/platform/android/licenses_cobalt.txt b/cobalt/content/licenses/platform/android/licenses_cobalt.txt
index 6754136..8821b6d 100644
--- a/cobalt/content/licenses/platform/android/licenses_cobalt.txt
+++ b/cobalt/content/licenses/platform/android/licenses_cobalt.txt
@@ -735,42 +735,472 @@
 
   Netscape Portable Runtime (NSPR)
 
+                             MOZILLA PUBLIC LICENSE
+                                Version 1.1
 
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is the Netscape Portable Runtime (NSPR).
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 1998-2000
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
+   The contents of this file are subject to the Mozilla Public License Version
+   1.1 (the "License"); you may not use this file except in compliance with
+   the License. You may obtain a copy of the License at
+   http://www.mozilla.org/MPL/
+
+   Software distributed under the License is distributed on an "AS IS" basis,
+   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   for the specific language governing rights and limitations under the
+   License.
+
+   The Original Code is the Netscape Portable Runtime (NSPR).
+
+   The Initial Developer of the Original Code is
+   Netscape Communications Corporation.
+   Portions created by the Initial Developer are Copyright (C) 1998-2000
+   the Initial Developer. All Rights Reserved.
+
+   Contributor(s):
+
+   Alternatively, the contents of this file may be used under the terms of
+   either the GNU General Public License Version 2 or later (the "GPL"), or
+   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   in which case the provisions of the GPL or the LGPL are applicable instead
+   of those above. If you wish to allow use of your version of this file only
+   under the terms of either the GPL or the LGPL, and not to allow others to
+   use your version of this file under the terms of the MPL, indicate your
+   decision by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL or the LGPL. If you do not delete
+   the provisions above, a recipient may use your version of this file under
+   the terms of any one of the MPL, the GPL or the LGPL.
 
 
   symbolize
@@ -1057,455 +1487,6 @@
 
 
 
-  nss
-
-
-    NSS is available under the Mozilla Public License, version 2, a copy of which
-  is below.
-
-  Note on GPL Compatibility
-  -------------------------
-
-  The MPL 2, section 3.3, permits you to combine NSS with code under the GNU
-  General Public License (GPL) version 2, or any later version of that
-  license, to make a Larger Work, and distribute the result under the GPL.
-  The only condition is that you must also make NSS, and any changes you
-  have made to it, available to recipients under the terms of the MPL 2 also.
-
-  Anyone who receives the combined code from you does not have to continue
-  to dual licence in this way, and may, if they wish, distribute under the
-  terms of either of the two licences - either the MPL alone or the GPL
-  alone. However, we discourage people from distributing copies of NSS under
-  the GPL alone, because it means that any improvements they make cannot be
-  reincorporated into the main version of NSS. There is never a need to do
-  this for license compatibility reasons.
-
-  Note on LGPL Compatibility
-  --------------------------
-
-  The above also applies to combining MPLed code in a single library with
-  code under the GNU Lesser General Public License (LGPL) version 2.1, or
-  any later version of that license. If the LGPLed code and the MPLed code
-  are not in the same library, then the copyleft coverage of the two
-  licences does not overlap, so no issues arise.
-
-
-  Mozilla Public License Version 2.0
-  ==================================
-
-  1. Definitions
-  --------------
-
-  1.1. "Contributor"
-      means each individual or legal entity that creates, contributes to
-      the creation of, or owns Covered Software.
-
-  1.2. "Contributor Version"
-      means the combination of the Contributions of others (if any) used
-      by a Contributor and that particular Contributor's Contribution.
-
-  1.3. "Contribution"
-      means Covered Software of a particular Contributor.
-
-  1.4. "Covered Software"
-      means Source Code Form to which the initial Contributor has attached
-      the notice in Exhibit A, the Executable Form of such Source Code
-      Form, and Modifications of such Source Code Form, in each case
-      including portions thereof.
-
-  1.5. "Incompatible With Secondary Licenses"
-      means
-
-      (a) that the initial Contributor has attached the notice described
-          in Exhibit B to the Covered Software; or
-
-      (b) that the Covered Software was made available under the terms of
-          version 1.1 or earlier of the License, but not also under the
-          terms of a Secondary License.
-
-  1.6. "Executable Form"
-      means any form of the work other than Source Code Form.
-
-  1.7. "Larger Work"
-      means a work that combines Covered Software with other material, in
-      a separate file or files, that is not Covered Software.
-
-  1.8. "License"
-      means this document.
-
-  1.9. "Licensable"
-      means having the right to grant, to the maximum extent possible,
-      whether at the time of the initial grant or subsequently, any and
-      all of the rights conveyed by this License.
-
-  1.10. "Modifications"
-      means any of the following:
-
-      (a) any file in Source Code Form that results from an addition to,
-          deletion from, or modification of the contents of Covered
-          Software; or
-
-      (b) any new file in Source Code Form that contains any Covered
-          Software.
-
-  1.11. "Patent Claims" of a Contributor
-      means any patent claim(s), including without limitation, method,
-      process, and apparatus claims, in any patent Licensable by such
-      Contributor that would be infringed, but for the grant of the
-      License, by the making, using, selling, offering for sale, having
-      made, import, or transfer of either its Contributions or its
-      Contributor Version.
-
-  1.12. "Secondary License"
-      means either the GNU General Public License, Version 2.0, the GNU
-      Lesser General Public License, Version 2.1, the GNU Affero General
-      Public License, Version 3.0, or any later versions of those
-      licenses.
-
-  1.13. "Source Code Form"
-      means the form of the work preferred for making modifications.
-
-  1.14. "You" (or "Your")
-      means an individual or a legal entity exercising rights under this
-      License. For legal entities, "You" includes any entity that
-      controls, is controlled by, or is under common control with You. For
-      purposes of this definition, "control" means (a) the power, direct
-      or indirect, to cause the direction or management of such entity,
-      whether by contract or otherwise, or (b) ownership of more than
-      fifty percent (50%) of the outstanding shares or beneficial
-      ownership of such entity.
-
-  2. License Grants and Conditions
-  --------------------------------
-
-  2.1. Grants
-
-  Each Contributor hereby grants You a world-wide, royalty-free,
-  non-exclusive license:
-
-  (a) under intellectual property rights (other than patent or trademark)
-      Licensable by such Contributor to use, reproduce, make available,
-      modify, display, perform, distribute, and otherwise exploit its
-      Contributions, either on an unmodified basis, with Modifications, or
-      as part of a Larger Work; and
-
-  (b) under Patent Claims of such Contributor to make, use, sell, offer
-      for sale, have made, import, and otherwise transfer either its
-      Contributions or its Contributor Version.
-
-  2.2. Effective Date
-
-  The licenses granted in Section 2.1 with respect to any Contribution
-  become effective for each Contribution on the date the Contributor first
-  distributes such Contribution.
-
-  2.3. Limitations on Grant Scope
-
-  The licenses granted in this Section 2 are the only rights granted under
-  this License. No additional rights or licenses will be implied from the
-  distribution or licensing of Covered Software under this License.
-  Notwithstanding Section 2.1(b) above, no patent license is granted by a
-  Contributor:
-
-  (a) for any code that a Contributor has removed from Covered Software;
-      or
-
-  (b) for infringements caused by: (i) Your and any other third party's
-      modifications of Covered Software, or (ii) the combination of its
-      Contributions with other software (except as part of its Contributor
-      Version); or
-
-  (c) under Patent Claims infringed by Covered Software in the absence of
-      its Contributions.
-
-  This License does not grant any rights in the trademarks, service marks,
-  or logos of any Contributor (except as may be necessary to comply with
-  the notice requirements in Section 3.4).
-
-  2.4. Subsequent Licenses
-
-  No Contributor makes additional grants as a result of Your choice to
-  distribute the Covered Software under a subsequent version of this
-  License (see Section 10.2) or under the terms of a Secondary License (if
-  permitted under the terms of Section 3.3).
-
-  2.5. Representation
-
-  Each Contributor represents that the Contributor believes its
-  Contributions are its original creation(s) or it has sufficient rights
-  to grant the rights to its Contributions conveyed by this License.
-
-  2.6. Fair Use
-
-  This License is not intended to limit any rights You have under
-  applicable copyright doctrines of fair use, fair dealing, or other
-  equivalents.
-
-  2.7. Conditions
-
-  Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-  in Section 2.1.
-
-  3. Responsibilities
-  -------------------
-
-  3.1. Distribution of Source Form
-
-  All distribution of Covered Software in Source Code Form, including any
-  Modifications that You create or to which You contribute, must be under
-  the terms of this License. You must inform recipients that the Source
-  Code Form of the Covered Software is governed by the terms of this
-  License, and how they can obtain a copy of this License. You may not
-  attempt to alter or restrict the recipients' rights in the Source Code
-  Form.
-
-  3.2. Distribution of Executable Form
-
-  If You distribute Covered Software in Executable Form then:
-
-  (a) such Covered Software must also be made available in Source Code
-      Form, as described in Section 3.1, and You must inform recipients of
-      the Executable Form how they can obtain a copy of such Source Code
-      Form by reasonable means in a timely manner, at a charge no more
-      than the cost of distribution to the recipient; and
-
-  (b) You may distribute such Executable Form under the terms of this
-      License, or sublicense it under different terms, provided that the
-      license for the Executable Form does not attempt to limit or alter
-      the recipients' rights in the Source Code Form under this License.
-
-  3.3. Distribution of a Larger Work
-
-  You may create and distribute a Larger Work under terms of Your choice,
-  provided that You also comply with the requirements of this License for
-  the Covered Software. If the Larger Work is a combination of Covered
-  Software with a work governed by one or more Secondary Licenses, and the
-  Covered Software is not Incompatible With Secondary Licenses, this
-  License permits You to additionally distribute such Covered Software
-  under the terms of such Secondary License(s), so that the recipient of
-  the Larger Work may, at their option, further distribute the Covered
-  Software under the terms of either this License or such Secondary
-  License(s).
-
-  3.4. Notices
-
-  You may not remove or alter the substance of any license notices
-  (including copyright notices, patent notices, disclaimers of warranty,
-  or limitations of liability) contained within the Source Code Form of
-  the Covered Software, except that You may alter any license notices to
-  the extent required to remedy known factual inaccuracies.
-
-  3.5. Application of Additional Terms
-
-  You may choose to offer, and to charge a fee for, warranty, support,
-  indemnity or liability obligations to one or more recipients of Covered
-  Software. However, You may do so only on Your own behalf, and not on
-  behalf of any Contributor. You must make it absolutely clear that any
-  such warranty, support, indemnity, or liability obligation is offered by
-  You alone, and You hereby agree to indemnify every Contributor for any
-  liability incurred by such Contributor as a result of warranty, support,
-  indemnity or liability terms You offer. You may include additional
-  disclaimers of warranty and limitations of liability specific to any
-  jurisdiction.
-
-  4. Inability to Comply Due to Statute or Regulation
-  ---------------------------------------------------
-
-  If it is impossible for You to comply with any of the terms of this
-  License with respect to some or all of the Covered Software due to
-  statute, judicial order, or regulation then You must: (a) comply with
-  the terms of this License to the maximum extent possible; and (b)
-  describe the limitations and the code they affect. Such description must
-  be placed in a text file included with all distributions of the Covered
-  Software under this License. Except to the extent prohibited by statute
-  or regulation, such description must be sufficiently detailed for a
-  recipient of ordinary skill to be able to understand it.
-
-  5. Termination
-  --------------
-
-  5.1. The rights granted under this License will terminate automatically
-  if You fail to comply with any of its terms. However, if You become
-  compliant, then the rights granted under this License from a particular
-  Contributor are reinstated (a) provisionally, unless and until such
-  Contributor explicitly and finally terminates Your grants, and (b) on an
-  ongoing basis, if such Contributor fails to notify You of the
-  non-compliance by some reasonable means prior to 60 days after You have
-  come back into compliance. Moreover, Your grants from a particular
-  Contributor are reinstated on an ongoing basis if such Contributor
-  notifies You of the non-compliance by some reasonable means, this is the
-  first time You have received notice of non-compliance with this License
-  from such Contributor, and You become compliant prior to 30 days after
-  Your receipt of the notice.
-
-  5.2. If You initiate litigation against any entity by asserting a patent
-  infringement claim (excluding declaratory judgment actions,
-  counter-claims, and cross-claims) alleging that a Contributor Version
-  directly or indirectly infringes any patent, then the rights granted to
-  You by any and all Contributors for the Covered Software under Section
-  2.1 of this License shall terminate.
-
-  5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-  end user license agreements (excluding distributors and resellers) which
-  have been validly granted by You or Your distributors under this License
-  prior to termination shall survive termination.
-
-  ************************************************************************
-  *                                                                      *
-  *  6. Disclaimer of Warranty                                           *
-  *  -------------------------                                           *
-  *                                                                      *
-  *  Covered Software is provided under this License on an "as is"       *
-  *  basis, without warranty of any kind, either expressed, implied, or  *
-  *  statutory, including, without limitation, warranties that the       *
-  *  Covered Software is free of defects, merchantable, fit for a        *
-  *  particular purpose or non-infringing. The entire risk as to the     *
-  *  quality and performance of the Covered Software is with You.        *
-  *  Should any Covered Software prove defective in any respect, You     *
-  *  (not any Contributor) assume the cost of any necessary servicing,   *
-  *  repair, or correction. This disclaimer of warranty constitutes an   *
-  *  essential part of this License. No use of any Covered Software is   *
-  *  authorized under this License except under this disclaimer.         *
-  *                                                                      *
-  ************************************************************************
-
-  ************************************************************************
-  *                                                                      *
-  *  7. Limitation of Liability                                          *
-  *  --------------------------                                          *
-  *                                                                      *
-  *  Under no circumstances and under no legal theory, whether tort      *
-  *  (including negligence), contract, or otherwise, shall any           *
-  *  Contributor, or anyone who distributes Covered Software as          *
-  *  permitted above, be liable to You for any direct, indirect,         *
-  *  special, incidental, or consequential damages of any character      *
-  *  including, without limitation, damages for lost profits, loss of    *
-  *  goodwill, work stoppage, computer failure or malfunction, or any    *
-  *  and all other commercial damages or losses, even if such party      *
-  *  shall have been informed of the possibility of such damages. This   *
-  *  limitation of liability shall not apply to liability for death or   *
-  *  personal injury resulting from such party's negligence to the       *
-  *  extent applicable law prohibits such limitation. Some               *
-  *  jurisdictions do not allow the exclusion or limitation of           *
-  *  incidental or consequential damages, so this exclusion and          *
-  *  limitation may not apply to You.                                    *
-  *                                                                      *
-  ************************************************************************
-
-  8. Litigation
-  -------------
-
-  Any litigation relating to this License may be brought only in the
-  courts of a jurisdiction where the defendant maintains its principal
-  place of business and such litigation shall be governed by laws of that
-  jurisdiction, without reference to its conflict-of-law provisions.
-  Nothing in this Section shall prevent a party's ability to bring
-  cross-claims or counter-claims.
-
-  9. Miscellaneous
-  ----------------
-
-  This License represents the complete agreement concerning the subject
-  matter hereof. If any provision of this License is held to be
-  unenforceable, such provision shall be reformed only to the extent
-  necessary to make it enforceable. Any law or regulation which provides
-  that the language of a contract shall be construed against the drafter
-  shall not be used to construe this License against a Contributor.
-
-  10. Versions of the License
-  ---------------------------
-
-  10.1. New Versions
-
-  Mozilla Foundation is the license steward. Except as provided in Section
-  10.3, no one other than the license steward has the right to modify or
-  publish new versions of this License. Each version will be given a
-  distinguishing version number.
-
-  10.2. Effect of New Versions
-
-  You may distribute the Covered Software under the terms of the version
-  of the License under which You originally received the Covered Software,
-  or under the terms of any subsequent version published by the license
-  steward.
-
-  10.3. Modified Versions
-
-  If you create software not governed by this License, and you want to
-  create a new license for such software, you may create and use a
-  modified version of this License if you rename the license and remove
-  any references to the name of the license steward (except to note that
-  such modified license differs from this License).
-
-  10.4. Distributing Source Code Form that is Incompatible With Secondary
-  Licenses
-
-  If You choose to distribute Source Code Form that is Incompatible With
-  Secondary Licenses under the terms of this version of the License, the
-  notice described in Exhibit B of this License must be attached.
-
-  Exhibit A - Source Code Form License Notice
-  -------------------------------------------
-
-    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 it is not possible or desirable to put the notice in a particular
-  file, then You may include the notice in a location (such as a LICENSE
-  file in a relevant directory) where a recipient would be likely to look
-  for such a notice.
-
-  You may add additional accurate notices of copyright ownership.
-
-  Exhibit B - "Incompatible With Secondary Licenses" Notice
-  ---------------------------------------------------------
-
-    This Source Code Form is "Incompatible With Secondary Licenses", as
-    defined by the Mozilla Public License, v. 2.0.
-
-
-
-  mozilla_security_manager
-
-
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is mozilla.org code.
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 2001
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
-
-
   mozilla(url/third_party/mozilla)
 
 
@@ -1543,6 +1524,443 @@
   The file url_parse.cc is based on nsURLParsers.cc from Mozilla. This file is
   licensed separately as follows:
 
+  --------------------------------------------------------------------------------
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
   The contents of this file are subject to the Mozilla Public License Version
   1.1 (the "License"); you may not use this file except in compliance with
   the License. You may obtain a copy of the License at
@@ -1884,6 +2302,115 @@
 
 
 
+  libjpeg-turbo
+
+  libjpeg-turbo Licenses libjpeg-turbo is covered by three compatible BSD-style
+  open source licenses:
+
+  The IJG (Independent JPEG Group) License, which is listed in README.ijg
+
+  This license applies to the libjpeg API library and associated programs (any
+  code inherited from libjpeg, and any modifications to that code.)
+
+  The Modified (3-clause) BSD License, which is listed below
+
+  This license covers the TurboJPEG API library and associated programs, as well
+  as the build system.
+
+  The zlib License
+
+  This license is a subset of the other two, and it covers the libjpeg-turbo
+  SIMD extensions.
+
+  Complying with the libjpeg-turbo Licenses This section provides a roll-up of
+  the libjpeg-turbo licensing terms, to the best of our understanding.
+
+  If you are distributing a modified version of the libjpeg-turbo source, then:
+
+  You cannot alter or remove any existing copyright or license notices from the
+  source.
+
+  Origin
+
+  Clause 1 of the IJG License Clause 1 of the Modified BSD License Clauses 1 and
+  3 of the zlib License You must add your own copyright notice to the header of
+  each source file you modified, so others can tell that you modified that file
+  (if there is not an existing copyright header in that file, then you can
+  simply add a notice stating that you modified the file.)
+
+  Origin
+
+  Clause 1 of the IJG License Clause 2 of the zlib License You must include the
+  IJG README file, and you must not alter any of the copyright or license text
+  in that file.
+
+  Origin
+
+  Clause 1 of the IJG License If you are distributing only libjpeg-turbo
+  binaries without the source, or if you are distributing an application that
+  statically links with libjpeg-turbo, then:
+
+  Your product documentation must include a message stating:
+
+  This software is based in part on the work of the Independent JPEG Group.
+
+  Origin
+
+  Clause 2 of the IJG license If your binary distribution includes or uses the
+  TurboJPEG API, then your product documentation must include the text of the
+  Modified BSD License (see below.)
+
+  Origin
+
+  Clause 2 of the Modified BSD License You cannot use the name of the IJG or The
+  libjpeg-turbo Project or the contributors thereof in advertising, publicity,
+  etc.
+
+  Origin
+
+  IJG License Clause 3 of the Modified BSD License The IJG and The libjpeg-turbo
+  Project do not warrant libjpeg-turbo to be free of defects, nor do we accept
+  any liability for undesirable consequences resulting from your use of the
+  software.
+
+  Origin
+
+  IJG License Modified BSD License zlib License The Modified (3-clause) BSD
+  License Copyright (C)2009-2021 D. R. Commander. All Rights Reserved.
+  Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.  Redistributions in binary
+  form must reproduce the above copyright notice, this list of conditions and
+  the following disclaimer in the documentation and/or other materials provided
+  with the distribution.  Neither the name of the libjpeg-turbo Project nor the
+  names of its contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.  THIS SOFTWARE
+  IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+  EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Why Three Licenses?  The zlib License could have been used instead of the
+  Modified (3-clause) BSD License, and since the IJG License effectively
+  subsumes the distribution conditions of the zlib License, this would have
+  effectively placed libjpeg-turbo binary distributions under the IJG License.
+  However, the IJG License specifically refers to the Independent JPEG Group and
+  does not extend attribution and endorsement protections to other entities.
+  Thus, it was desirable to choose a license that granted us the same
+  protections for new code that were granted to the IJG for code derived from
+  their software.
+
+
   libpng
 
 
@@ -2700,6 +3227,41 @@
   POSSIBILITY OF SUCH DAMAGE.
 
 
+
+  flac
+
+
+  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  - Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+  - Neither the name of the Xiph.org Foundation nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
   angle
 
 
@@ -3706,6 +4268,36 @@
   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+
+  lz4_lib
+
+
+  LZ4 Library
+  Copyright (c) 2011-2016, Yann Collet
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification,
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or
+    other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
   libwebp
 
   Copyright (c) 2010, Google Inc. All rights reserved.  Redistribution and use
diff --git a/cobalt/content/licenses/platform/darwin/licenses_cobalt.txt b/cobalt/content/licenses/platform/darwin/licenses_cobalt.txt
new file mode 100644
index 0000000..d80e0a5
--- /dev/null
+++ b/cobalt/content/licenses/platform/darwin/licenses_cobalt.txt
@@ -0,0 +1,4343 @@
+Where applicable, source code for modified versions of the libraries below is available at:
+https://cobalt.googlesource.com/cobalt.
+
+
+
+  Cobalt
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+   1. Definitions.
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+   END OF TERMS AND CONDITIONS
+   APPENDIX: How to apply the Apache License to your work.
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+   Copyright [yyyy] [name of copyright owner]
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+       http://www.apache.org/licenses/LICENSE-2.0
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+  Chromium
+
+  // Copyright 2015 The Chromium Authors. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  V8
+
+  This license applies to all parts of V8 that are not externally
+  maintained libraries.  The externally maintained libraries used by V8
+  are:
+
+    - PCRE test suite, located in
+      test/mjsunit/third_party/regexp-pcre/regexp-pcre.js.  This is based on the
+      test suite from PCRE-7.3, which is copyrighted by the University
+      of Cambridge and Google, Inc.  The copyright notice and license
+      are embedded in regexp-pcre.js.
+
+    - Layout tests, located in test/mjsunit/third_party/object-keys.  These are
+      based on layout tests from webkit.org which are copyrighted by
+      Apple Computer, Inc. and released under a 3-clause BSD license.
+
+    - Strongtalk assembler, the basis of the files assembler-arm-inl.h,
+      assembler-arm.cc, assembler-arm.h, assembler-ia32-inl.h,
+      assembler-ia32.cc, assembler-ia32.h, assembler-x64-inl.h,
+      assembler-x64.cc, assembler-x64.h, assembler-mips-inl.h,
+      assembler-mips.cc, assembler-mips.h, assembler.cc and assembler.h.
+      This code is copyrighted by Sun Microsystems Inc. and released
+      under a 3-clause BSD license.
+
+    - Valgrind client API header, located at src/third_party/valgrind/valgrind.h
+      This is released under the BSD license.
+
+    - The Wasm C/C++ API headers, located at third_party/wasm-api/wasm.{h,hh}
+      This is released under the Apache license. The API's upstream prototype
+      implementation also formed the basis of V8's implementation in
+      src/wasm/c-api.cc.
+
+  These libraries have their own licenses; we recommend you read them,
+  as their terms may differ from the terms below.
+
+  Further license information can be found in LICENSE files located in
+  sub-directories.
+
+  Copyright 2014, the V8 project authors. All rights reserved.
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+      * Neither the name of Google Inc. nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  devtools
+
+
+  // Copyright 2014 The Chromium Authors. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  boringssl
+
+
+  BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
+  licensing. Files that are completely new have a Google copyright and an ISC
+  license. This license is reproduced at the bottom of this file.
+
+  Contributors to BoringSSL are required to follow the CLA rules for Chromium:
+  https://cla.developers.google.com/clas
+
+  Files in third_party/ have their own licenses, as described therein. The MIT
+  license, for third_party/fiat, which, unlike other third_party directories, is
+  compiled into non-test libraries, is included below.
+
+  The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
+  OpenSSL License and the original SSLeay license apply to the toolkit. See below
+  for the actual license texts. Actually both licenses are BSD-style Open Source
+  licenses. In case of any license issues related to OpenSSL please contact
+  openssl-core@openssl.org.
+
+  The following are Google-internal bug numbers where explicit permission from
+  some authors is recorded for use of their work. (This is purely for our own
+  record keeping.)
+    27287199
+    27287880
+    27287883
+
+    OpenSSL License
+    ---------------
+
+  /* ====================================================================
+   * Copyright (c) 1998-2011 The OpenSSL Project.  All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions
+   * are met:
+   *
+   * 1. Redistributions of source code must retain the above copyright
+   *    notice, this list of conditions and the following disclaimer.
+   *
+   * 2. Redistributions in binary form must reproduce the above copyright
+   *    notice, this list of conditions and the following disclaimer in
+   *    the documentation and/or other materials provided with the
+   *    distribution.
+   *
+   * 3. All advertising materials mentioning features or use of this
+   *    software must display the following acknowledgment:
+   *    "This product includes software developed by the OpenSSL Project
+   *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+   *
+   * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+   *    endorse or promote products derived from this software without
+   *    prior written permission. For written permission, please contact
+   *    openssl-core@openssl.org.
+   *
+   * 5. Products derived from this software may not be called "OpenSSL"
+   *    nor may "OpenSSL" appear in their names without prior written
+   *    permission of the OpenSSL Project.
+   *
+   * 6. Redistributions of any form whatsoever must retain the following
+   *    acknowledgment:
+   *    "This product includes software developed by the OpenSSL Project
+   *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+   * OF THE POSSIBILITY OF SUCH DAMAGE.
+   * ====================================================================
+   *
+   * This product includes cryptographic software written by Eric Young
+   * (eay@cryptsoft.com).  This product includes software written by Tim
+   * Hudson (tjh@cryptsoft.com).
+   *
+   */
+
+   Original SSLeay License
+   -----------------------
+
+  /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+   * All rights reserved.
+   *
+   * This package is an SSL implementation written
+   * by Eric Young (eay@cryptsoft.com).
+   * The implementation was written so as to conform with Netscapes SSL.
+   *
+   * This library is free for commercial and non-commercial use as long as
+   * the following conditions are aheared to.  The following conditions
+   * apply to all code found in this distribution, be it the RC4, RSA,
+   * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+   * included with this distribution is covered by the same copyright terms
+   * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+   *
+   * Copyright remains Eric Young's, and as such any Copyright notices in
+   * the code are not to be removed.
+   * If this package is used in a product, Eric Young should be given attribution
+   * as the author of the parts of the library used.
+   * This can be in the form of a textual message at program startup or
+   * in documentation (online or textual) provided with the package.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions
+   * are met:
+   * 1. Redistributions of source code must retain the copyright
+   *    notice, this list of conditions and the following disclaimer.
+   * 2. Redistributions in binary form must reproduce the above copyright
+   *    notice, this list of conditions and the following disclaimer in the
+   *    documentation and/or other materials provided with the distribution.
+   * 3. All advertising materials mentioning features or use of this software
+   *    must display the following acknowledgement:
+   *    "This product includes cryptographic software written by
+   *     Eric Young (eay@cryptsoft.com)"
+   *    The word 'cryptographic' can be left out if the rouines from the library
+   *    being used are not cryptographic related :-).
+   * 4. If you include any Windows specific code (or a derivative thereof) from
+   *    the apps directory (application code) you must include an acknowledgement:
+   *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+   *
+   * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+   * SUCH DAMAGE.
+   *
+   * The licence and distribution terms for any publically available version or
+   * derivative of this code cannot be changed.  i.e. this code cannot simply be
+   * copied and put under another distribution licence
+   * [including the GNU Public Licence.]
+   */
+
+
+  ISC license used for completely new code in BoringSSL:
+
+  /* Copyright (c) 2015, Google Inc.
+   *
+   * Permission to use, copy, modify, and/or distribute this software for any
+   * purpose with or without fee is hereby granted, provided that the above
+   * copyright notice and this permission notice appear in all copies.
+   *
+   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+   * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+   * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+
+  The code in third_party/fiat carries the MIT license:
+
+  Copyright (c) 2015-2016 the fiat-crypto authors (see
+  https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS).
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+
+
+  Licenses for support code
+  -------------------------
+
+  Parts of the TLS test suite are under the Go license. This code is not included
+  in BoringSSL (i.e. libcrypto and libssl) when compiled, however, so
+  distributing code linked against BoringSSL does not trigger this license:
+
+  Copyright (c) 2009 The Go Authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+     * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+     * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  BoringSSL uses the Chromium test infrastructure to run a continuous build,
+  trybots etc. The scripts which manage this, and the script for generating build
+  metadata, are under the Chromium license. Distributing code linked against
+  BoringSSL does not trigger this license.
+
+  Copyright 2015 The Chromium Authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+     * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+     * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  dmg_fp
+
+
+  /****************************************************************
+   *
+   * The author of this software is David M. Gay.
+   *
+   * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+   *
+   * Permission to use, copy, modify, and distribute this software for any
+   * purpose without fee is hereby granted, provided that this entire notice
+   * is included in all copies of any software which is or includes a copy
+   * or modification of this software and in all copies of the supporting
+   * documentation for such software.
+   *
+   * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+   * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+   * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+   * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+   *
+   ***************************************************************/
+
+
+
+  dynamic_annotations
+
+
+  /* Copyright (c) 2008-2009, Google Inc.
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *     * Redistributions of source code must retain the above copyright
+   * notice, this list of conditions and the following disclaimer.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   *
+   * ---
+   * Author: Kostya Serebryany
+   */
+
+
+
+  icu(base/third_party/icu)
+
+
+  COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later)
+
+  Copyright © 1991-2017 Unicode, Inc. All rights reserved.
+  Distributed under the Terms of Use in http://www.unicode.org/copyright.html
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of the Unicode data files and any associated documentation
+  (the "Data Files") or Unicode software and any associated documentation
+  (the "Software") to deal in the Data Files or Software
+  without restriction, including without limitation the rights to use,
+  copy, modify, merge, publish, distribute, and/or sell copies of
+  the Data Files or Software, and to permit persons to whom the Data Files
+  or Software are furnished to do so, provided that either
+  (a) this copyright and permission notice appear with all copies
+  of the Data Files or Software, or
+  (b) this copyright and permission notice appear in associated
+  Documentation.
+
+  THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+  ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+  NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+  DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+  DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+  TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+  PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+  Except as contained in this notice, the name of a copyright holder
+  shall not be used in advertising or otherwise to promote the sale,
+  use or other dealings in these Data Files or Software without prior
+  written authorization of the copyright holder.
+
+  ---------------------
+
+  Third-Party Software Licenses
+
+  This section contains third-party software notices and/or additional
+  terms for licensed third-party software components included within ICU
+  libraries.
+
+  1. ICU License - ICU 1.8.1 to ICU 57.1
+
+  COPYRIGHT AND PERMISSION NOTICE
+
+  Copyright (c) 1995-2016 International Business Machines Corporation and others
+  All rights reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, and/or sell copies of the Software, and to permit persons
+  to whom the Software is furnished to do so, provided that the above
+  copyright notice(s) and this permission notice appear in all copies of
+  the Software and that both the above copyright notice(s) and this
+  permission notice appear in supporting documentation.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+  OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+  HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+  SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+  RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+  CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+  Except as contained in this notice, the name of a copyright holder
+  shall not be used in advertising or otherwise to promote the sale, use
+  or other dealings in this Software without prior written authorization
+  of the copyright holder.
+
+  All trademarks and registered trademarks mentioned herein are the
+  property of their respective owners.
+
+
+
+  libxml
+
+
+  LibXml Ruby Project
+    Copyright (c) 2008-2013 Charlie Savage and contributors
+    Copyright (c) 2002-2007 Sean Chittenden and contributors
+    Copyright (c) 2001 Wai-Sun "Squidster" Chia
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy of
+  this software and associated documentation files (the "Software"), to deal in
+  the Software without restriction, including without limitation the rights to
+  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+  of the Software, and to permit persons to whom the Software is furnished to do
+  so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+
+
+
+  Netscape Portable Runtime (NSPR)
+
+                             MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
+   The contents of this file are subject to the Mozilla Public License Version
+   1.1 (the "License"); you may not use this file except in compliance with
+   the License. You may obtain a copy of the License at
+   http://www.mozilla.org/MPL/
+
+   Software distributed under the License is distributed on an "AS IS" basis,
+   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   for the specific language governing rights and limitations under the
+   License.
+
+   The Original Code is the Netscape Portable Runtime (NSPR).
+
+   The Initial Developer of the Original Code is
+   Netscape Communications Corporation.
+   Portions created by the Initial Developer are Copyright (C) 1998-2000
+   the Initial Developer. All Rights Reserved.
+
+   Contributor(s):
+
+   Alternatively, the contents of this file may be used under the terms of
+   either the GNU General Public License Version 2 or later (the "GPL"), or
+   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   in which case the provisions of the GPL or the LGPL are applicable instead
+   of those above. If you wish to allow use of your version of this file only
+   under the terms of either the GPL or the LGPL, and not to allow others to
+   use your version of this file under the terms of the MPL, indicate your
+   decision by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL or the LGPL. If you do not delete
+   the provisions above, a recipient may use your version of this file under
+   the terms of any one of the MPL, the GPL or the LGPL.
+
+
+  symbolize
+
+
+  // Copyright (c) 2006, Google Inc.
+  // All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //     * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //     * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //     * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  valgrind
+
+
+   Notice that the following BSD-style license applies to the Valgrind header
+   files used by Chromium (valgrind.h and memcheck.h). However, the rest of
+   Valgrind is licensed under the terms of the GNU General Public License,
+   version 2, unless otherwise indicated.
+
+   ----------------------------------------------------------------
+
+   Copyright (C) 2000-2008 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must
+      not claim that you wrote the original software.  If you use this
+      software in a product, an acknowledgment in the product
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote
+      products derived from this software without specific prior written
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  uri_template
+
+
+                                   Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+  mozilla(url/third_party/mozilla)
+
+
+  Copyright 2007, Google Inc.
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+      * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  -------------------------------------------------------------------------------
+
+  The file url_parse.cc is based on nsURLParsers.cc from Mozilla. This file is
+  licensed separately as follows:
+
+  --------------------------------------------------------------------------------
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
+  The contents of this file are subject to the Mozilla Public License Version
+  1.1 (the "License"); you may not use this file except in compliance with
+  the License. You may obtain a copy of the License at
+  http://www.mozilla.org/MPL/
+
+  Software distributed under the License is distributed on an "AS IS" basis,
+  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+  for the specific language governing rights and limitations under the
+  License.
+
+  The Original Code is mozilla.org code.
+
+  The Initial Developer of the Original Code is
+  Netscape Communications Corporation.
+  Portions created by the Initial Developer are Copyright (C) 1998
+  the Initial Developer. All Rights Reserved.
+
+  Contributor(s):
+    Darin Fisher (original author)
+
+  Alternatively, the contents of this file may be used under the terms of
+  either the GNU General Public License Version 2 or later (the "GPL"), or
+  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+  in which case the provisions of the GPL or the LGPL are applicable instead
+  of those above. If you wish to allow use of your version of this file only
+  under the terms of either the GPL or the LGPL, and not to allow others to
+  use your version of this file under the terms of the MPL, indicate your
+  decision by deleting the provisions above and replace them with the notice
+  and other provisions required by the GPL or the LGPL. If you do not delete
+  the provisions above, a recipient may use your version of this file under
+  the terms of any one of the MPL, the GPL or the LGPL.
+
+
+  nist-pkits
+
+  Name: NIST Public Key Interoperability Test Suite
+  Short Name: NIST PKITS
+  URL: http://csrc.nist.gov/groups/ST/crypto_apps_infra/pki/pkitesting.html
+  Version: 1.0.1
+  Date: April 14, 2011
+  License: Public Domain: United States Government Work under 17 U.S.C. 105
+  License File: NOT_SHIPPED
+
+  Description:
+  The Public Key Interoperability Test Suite (PKITS) is a comprehensive X.509
+  path validation test suite that was developed by NIST in conjunction with BAE
+  Systems and NSA.  The PKITS path validation test suite is designed to cover
+  most of the features specified in X.509 and RFC 3280.
+
+  Local Modifications:
+  Only the certs/ and crls/ directories were extracted from PKITS_data.zip.
+
+  pkits_testcases-inl.h is generated from the test descriptions in PKITS.pdf
+  using generate_tests.py.
+
+
+
+  FreeType
+
+
+                      The FreeType Project LICENSE
+                      ----------------------------
+
+                              2006-Jan-27
+
+                      Copyright 1996-2002, 2006 by
+            David Turner, Robert Wilhelm, and Werner Lemberg
+
+
+
+  Introduction
+  ============
+
+    The FreeType  Project is distributed in  several archive packages;
+    some of them may contain, in addition to the FreeType font engine,
+    various tools and  contributions which rely on, or  relate to, the
+    FreeType Project.
+
+    This  license applies  to all  files found  in such  packages, and
+    which do not  fall under their own explicit  license.  The license
+    affects  thus  the  FreeType   font  engine,  the  test  programs,
+    documentation and makefiles, at the very least.
+
+    This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG
+    (Independent JPEG  Group) licenses, which  all encourage inclusion
+    and  use of  free  software in  commercial  and freeware  products
+    alike.  As a consequence, its main points are that:
+
+      o We don't promise that this software works. However, we will be
+        interested in any kind of bug reports. (`as is' distribution)
+
+      o You can  use this software for whatever you  want, in parts or
+        full form, without having to pay us. (`royalty-free' usage)
+
+      o You may not pretend that  you wrote this software.  If you use
+        it, or  only parts of it,  in a program,  you must acknowledge
+        somewhere  in  your  documentation  that  you  have  used  the
+        FreeType code. (`credits')
+
+    We  specifically  permit  and  encourage  the  inclusion  of  this
+    software, with  or without modifications,  in commercial products.
+    We  disclaim  all warranties  covering  The  FreeType Project  and
+    assume no liability related to The FreeType Project.
+
+
+    Finally,  many  people  asked  us  for  a  preferred  form  for  a
+    credit/disclaimer to use in compliance with this license.  We thus
+    encourage you to use the following text:
+
+     """
+      Portions of this software are copyright © <year> The FreeType
+      Project (www.freetype.org).  All rights reserved.
+     """
+
+    Please replace <year> with the value from the FreeType version you
+    actually use.
+
+
+  Legal Terms
+  ===========
+
+  0. Definitions
+  --------------
+
+    Throughout this license,  the terms `package', `FreeType Project',
+    and  `FreeType  archive' refer  to  the  set  of files  originally
+    distributed  by the  authors  (David Turner,  Robert Wilhelm,  and
+    Werner Lemberg) as the `FreeType Project', be they named as alpha,
+    beta or final release.
+
+    `You' refers to  the licensee, or person using  the project, where
+    `using' is a generic term including compiling the project's source
+    code as  well as linking it  to form a  `program' or `executable'.
+    This  program is  referred to  as  `a program  using the  FreeType
+    engine'.
+
+    This  license applies  to all  files distributed  in  the original
+    FreeType  Project,   including  all  source   code,  binaries  and
+    documentation,  unless  otherwise  stated   in  the  file  in  its
+    original, unmodified form as  distributed in the original archive.
+    If you are  unsure whether or not a particular  file is covered by
+    this license, you must contact us to verify this.
+
+    The FreeType  Project is copyright (C) 1996-2000  by David Turner,
+    Robert Wilhelm, and Werner Lemberg.  All rights reserved except as
+    specified below.
+
+  1. No Warranty
+  --------------
+
+    THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY
+    KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,
+    WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR
+    PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+    BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO
+    USE, OF THE FREETYPE PROJECT.
+
+  2. Redistribution
+  -----------------
+
+    This  license  grants  a  worldwide, royalty-free,  perpetual  and
+    irrevocable right  and license to use,  execute, perform, compile,
+    display,  copy,   create  derivative  works   of,  distribute  and
+    sublicense the  FreeType Project (in  both source and  object code
+    forms)  and  derivative works  thereof  for  any  purpose; and  to
+    authorize others  to exercise  some or all  of the  rights granted
+    herein, subject to the following conditions:
+
+      o Redistribution of  source code  must retain this  license file
+        (`FTL.TXT') unaltered; any  additions, deletions or changes to
+        the original  files must be clearly  indicated in accompanying
+        documentation.   The  copyright   notices  of  the  unaltered,
+        original  files must  be  preserved in  all  copies of  source
+        files.
+
+      o Redistribution in binary form must provide a  disclaimer  that
+        states  that  the software is based in part of the work of the
+        FreeType Team,  in  the  distribution  documentation.  We also
+        encourage you to put an URL to the FreeType web page  in  your
+        documentation, though this isn't mandatory.
+
+    These conditions  apply to any  software derived from or  based on
+    the FreeType Project,  not just the unmodified files.   If you use
+    our work, you  must acknowledge us.  However, no  fee need be paid
+    to us.
+
+  3. Advertising
+  --------------
+
+    Neither the  FreeType authors and  contributors nor you  shall use
+    the name of the  other for commercial, advertising, or promotional
+    purposes without specific prior written permission.
+
+    We suggest,  but do not require, that  you use one or  more of the
+    following phrases to refer  to this software in your documentation
+    or advertising  materials: `FreeType Project',  `FreeType Engine',
+    `FreeType library', or `FreeType Distribution'.
+
+    As  you have  not signed  this license,  you are  not  required to
+    accept  it.   However,  as  the FreeType  Project  is  copyrighted
+    material, only  this license, or  another one contracted  with the
+    authors, grants you  the right to use, distribute,  and modify it.
+    Therefore,  by  using,  distributing,  or modifying  the  FreeType
+    Project, you indicate that you understand and accept all the terms
+    of this license.
+
+  4. Contacts
+  -----------
+
+    There are two mailing lists related to FreeType:
+
+      o freetype@nongnu.org
+
+        Discusses general use and applications of FreeType, as well as
+        future and  wanted additions to the  library and distribution.
+        If  you are looking  for support,  start in  this list  if you
+        haven't found anything to help you in the documentation.
+
+      o freetype-devel@nongnu.org
+
+        Discusses bugs,  as well  as engine internals,  design issues,
+        specific licenses, porting, etc.
+
+    Our home page can be found at
+
+      http://www.freetype.org
+
+
+  --- end of FTL.TXT ---
+
+
+
+  harfbuzz-ng
+
+  HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
+  For parts of HarfBuzz that are licensed under different licenses see individual
+  files names COPYING in subdirectories where applicable.
+
+  Copyright © 2010,2011,2012  Google, Inc.
+  Copyright © 2012  Mozilla Foundation
+  Copyright © 2011  Codethink Limited
+  Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
+  Copyright © 2009  Keith Stribley
+  Copyright © 2009  Martin Hosken and SIL International
+  Copyright © 2007  Chris Wilson
+  Copyright © 2006  Behdad Esfahbod
+  Copyright © 2005  David Turner
+  Copyright © 2004,2007,2008,2009,2010  Red Hat, Inc.
+  Copyright © 1998-2004  David Turner and Werner Lemberg
+
+  For full copyright notices consult the individual files in the package.
+
+
+  Permission is hereby granted, without written agreement and without
+  license or royalty fees, to use, copy, modify, and distribute this
+  software and its documentation for any purpose, provided that the
+  above copyright notice and the following two paragraphs appear in
+  all copies of this software.
+
+  IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+  DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+  IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+  THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+  BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+  FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+  ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+  PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+
+
+  icu
+
+
+  ICU License - ICU 1.8.1 and later
+
+  COPYRIGHT AND PERMISSION NOTICE
+
+  Copyright (c) 1995-2010 International Business Machines Corporation and others
+
+  All rights reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, and/or sell
+  copies of the Software, and to permit persons
+  to whom the Software is furnished to do so, provided that the above
+  copyright notice(s) and this permission notice appear in all copies
+  of the Software and that both the above copyright notice(s) and this
+  permission notice appear in supporting documentation.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT
+  SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY
+  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+  CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+  WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+  Except as contained in this notice, the name of a copyright holder shall not be
+  used in advertising or otherwise to promote the sale, use or other dealings in
+  this Software without prior written authorization of the copyright holder.
+
+  All trademarks and registered trademarks mentioned herein are the property of
+  their respective owners.
+
+
+
+  libevent
+
+  Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
+  Copyright 2007-2009 Niels Provos and Nick Mathewson
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  3. The name of the author may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  libjpeg-turbo
+
+  libjpeg-turbo Licenses libjpeg-turbo is covered by three compatible BSD-style
+  open source licenses:
+
+  The IJG (Independent JPEG Group) License, which is listed in README.ijg
+
+  This license applies to the libjpeg API library and associated programs (any
+  code inherited from libjpeg, and any modifications to that code.)
+
+  The Modified (3-clause) BSD License, which is listed below
+
+  This license covers the TurboJPEG API library and associated programs, as well
+  as the build system.
+
+  The zlib License
+
+  This license is a subset of the other two, and it covers the libjpeg-turbo
+  SIMD extensions.
+
+  Complying with the libjpeg-turbo Licenses This section provides a roll-up of
+  the libjpeg-turbo licensing terms, to the best of our understanding.
+
+  If you are distributing a modified version of the libjpeg-turbo source, then:
+
+  You cannot alter or remove any existing copyright or license notices from the
+  source.
+
+  Origin
+
+  Clause 1 of the IJG License Clause 1 of the Modified BSD License Clauses 1 and
+  3 of the zlib License You must add your own copyright notice to the header of
+  each source file you modified, so others can tell that you modified that file
+  (if there is not an existing copyright header in that file, then you can
+  simply add a notice stating that you modified the file.)
+
+  Origin
+
+  Clause 1 of the IJG License Clause 2 of the zlib License You must include the
+  IJG README file, and you must not alter any of the copyright or license text
+  in that file.
+
+  Origin
+
+  Clause 1 of the IJG License If you are distributing only libjpeg-turbo
+  binaries without the source, or if you are distributing an application that
+  statically links with libjpeg-turbo, then:
+
+  Your product documentation must include a message stating:
+
+  This software is based in part on the work of the Independent JPEG Group.
+
+  Origin
+
+  Clause 2 of the IJG license If your binary distribution includes or uses the
+  TurboJPEG API, then your product documentation must include the text of the
+  Modified BSD License (see below.)
+
+  Origin
+
+  Clause 2 of the Modified BSD License You cannot use the name of the IJG or The
+  libjpeg-turbo Project or the contributors thereof in advertising, publicity,
+  etc.
+
+  Origin
+
+  IJG License Clause 3 of the Modified BSD License The IJG and The libjpeg-turbo
+  Project do not warrant libjpeg-turbo to be free of defects, nor do we accept
+  any liability for undesirable consequences resulting from your use of the
+  software.
+
+  Origin
+
+  IJG License Modified BSD License zlib License The Modified (3-clause) BSD
+  License Copyright (C)2009-2021 D. R. Commander. All Rights Reserved.
+  Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.  Redistributions in binary
+  form must reproduce the above copyright notice, this list of conditions and
+  the following disclaimer in the documentation and/or other materials provided
+  with the distribution.  Neither the name of the libjpeg-turbo Project nor the
+  names of its contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.  THIS SOFTWARE
+  IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+  EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Why Three Licenses?  The zlib License could have been used instead of the
+  Modified (3-clause) BSD License, and since the IJG License effectively
+  subsumes the distribution conditions of the zlib License, this would have
+  effectively placed libjpeg-turbo binary distributions under the IJG License.
+  However, the IJG License specifically refers to the Independent JPEG Group and
+  does not extend attribution and endorsement protections to other entities.
+  Thus, it was desirable to choose a license that granted us the same
+  protections for new code that were granted to the IJG for code derived from
+  their software.
+
+
+  libpng
+
+
+  This copy of the libpng notices is provided for your convenience.  In case of
+  any discrepancy between this copy and the notices in the file png.h that is
+  included in the libpng distribution, the latter shall prevail.
+
+  COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+
+  If you modify libpng you may insert additional notices immediately following
+  this sentence.
+
+  This code is released under the libpng license.
+
+  libpng versions 1.2.6, August 15, 2004, through 1.2.45, July 7, 2011, are
+  Copyright (c) 2004, 2006-2009 Glenn Randers-Pehrson, and are
+  distributed according to the same disclaimer and license as libpng-1.2.5
+  with the following individual added to the list of Contributing Authors
+
+     Cosmin Truta
+
+  libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are
+  Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
+  distributed according to the same disclaimer and license as libpng-1.0.6
+  with the following individuals added to the list of Contributing Authors
+
+     Simon-Pierre Cadieux
+     Eric S. Raymond
+     Gilles Vollant
+
+  and with the following additions to the disclaimer:
+
+     There is no warranty against interference with your enjoyment of the
+     library or against infringement.  There is no warranty that our
+     efforts or the library will fulfill any of your particular purposes
+     or needs.  This library is provided with all faults, and the entire
+     risk of satisfactory quality, performance, accuracy, and effort is with
+     the user.
+
+  libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+  Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are
+  distributed according to the same disclaimer and license as libpng-0.96,
+  with the following individuals added to the list of Contributing Authors:
+
+     Tom Lane
+     Glenn Randers-Pehrson
+     Willem van Schaik
+
+  libpng versions 0.89, June 1996, through 0.96, May 1997, are
+  Copyright (c) 1996, 1997 Andreas Dilger
+  Distributed according to the same disclaimer and license as libpng-0.88,
+  with the following individuals added to the list of Contributing Authors:
+
+     John Bowler
+     Kevin Bracey
+     Sam Bushell
+     Magnus Holmgren
+     Greg Roelofs
+     Tom Tanner
+
+  libpng versions 0.5, May 1995, through 0.88, January 1996, are
+  Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+
+  For the purposes of this copyright and license, "Contributing Authors"
+  is defined as the following set of individuals:
+
+     Andreas Dilger
+     Dave Martindale
+     Guy Eric Schalnat
+     Paul Schmidt
+     Tim Wegner
+
+  The PNG Reference Library is supplied "AS IS".  The Contributing Authors
+  and Group 42, Inc. disclaim all warranties, expressed or implied,
+  including, without limitation, the warranties of merchantability and of
+  fitness for any purpose.  The Contributing Authors and Group 42, Inc.
+  assume no liability for direct, indirect, incidental, special, exemplary,
+  or consequential damages, which may result from the use of the PNG
+  Reference Library, even if advised of the possibility of such damage.
+
+  Permission is hereby granted to use, copy, modify, and distribute this
+  source code, or portions hereof, for any purpose, without fee, subject
+  to the following restrictions:
+
+  1. The origin of this source code must not be misrepresented.
+
+  2. Altered versions must be plainly marked as such and must not
+     be misrepresented as being the original source.
+
+  3. This Copyright notice may not be removed or altered from any
+     source or altered source distribution.
+
+  The Contributing Authors and Group 42, Inc. specifically permit, without
+  fee, and encourage the use of this source code as a component to
+  supporting the PNG file format in commercial products.  If you use this
+  source code in a product, acknowledgment is not required but would be
+  appreciated.
+
+
+  A "png_get_copyright" function is available, for convenient use in "about"
+  boxes and the like:
+
+     printf("%s",png_get_copyright(NULL));
+
+  Also, the PNG logo (in PNG format, of course) is supplied in the
+  files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+
+  Libpng is OSI Certified Open Source Software.  OSI Certified Open Source is a
+  certification mark of the Open Source Initiative.
+
+  Glenn Randers-Pehrson
+  glennrp at users.sourceforge.net
+  July 7, 2011
+
+
+
+
+
+  WebP image encoder/decoder
+
+
+  Copyright (c) 2010, Google Inc. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+
+    * Neither the name of Google nor the names of its contributors may
+      be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Additional IP Rights Grant (Patents)
+
+  "This implementation" means the copyrightable works distributed by
+  Google as part of the WebM Project.
+
+  Google hereby grants to you a perpetual, worldwide, non-exclusive,
+  no-charge, royalty-free, irrevocable (except as stated in this section)
+  patent license to make, have made, use, offer to sell, sell, import,
+  transfer, and otherwise run, modify and propagate the contents of this
+  implementation of VP8, where such license applies only to those patent
+  claims, both currently owned by Google and acquired in the future,
+  licensable by Google that are necessarily infringed by this
+  implementation of VP8. This grant does not include claims that would be
+  infringed only as a consequence of further modification of this
+  implementation. If you or your agent or exclusive licensee institute or
+  order or agree to the institution of patent litigation against any
+  entity (including a cross-claim or counterclaim in a lawsuit) alleging
+  that this implementation of VP8 or any code incorporated within this
+  implementation of VP8 constitutes direct or contributory patent
+  infringement, or inducement of patent infringement, then any patent
+  rights granted to you under this License for this implementation of VP8
+  shall terminate as of the date such litigation is filed.
+
+
+
+  libxml
+
+
+  Except where otherwise noted in the source code (e.g. the files hash.c,
+  list.c and the trio files, which are covered by a similar licence but
+  with different Copyright notices) all the files are:
+
+   Copyright (C) 1998-2003 Daniel Veillard.  All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is fur-
+  nished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
+  NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON-
+  NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+  Except as contained in this notice, the name of Daniel Veillard shall not
+  be used in advertising or otherwise to promote the sale, use or other deal-
+  ings in this Software without prior written authorization from him.
+
+
+
+  modp base64 decoder
+
+
+   * MODP_B64 - High performance base64 encoder/decoder
+   * Version 1.3 -- 17-Mar-2006
+   * http://modp.com/release/base64
+   *
+   * Copyright (c) 2005, 2006  Nick Galbreath -- nickg [at] modp [dot] com
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *   Redistributions of source code must retain the above copyright
+   *   notice, this list of conditions and the following disclaimer.
+   *
+   *   Redistributions in binary form must reproduce the above copyright
+   *   notice, this list of conditions and the following disclaimer in the
+   *   documentation and/or other materials provided with the distribution.
+   *
+   *   Neither the name of the modp.com nor the names of its
+   *   contributors may be used to endorse or promote products derived from
+   *   this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  OTS (OpenType Sanitizer)
+
+
+  // Copyright (c) 2009 The Chromium Authors. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  protobuf
+
+  This license applies to all parts of Protocol Buffers except the following:
+
+    - Atomicops support for generic gcc, located in
+      src/google/protobuf/stubs/atomicops_internals_generic_gcc.h.
+      This file is copyrighted by Red Hat Inc.
+
+    - Atomicops support for AIX/POWER, located in
+      src/google/protobuf/stubs/atomicops_internals_power.h.
+      This file is copyrighted by Bloomberg Finance LP.
+
+  Copyright 2014, Google Inc.  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+      * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Code generated by the Protocol Buffer compiler is owned by the owner
+  of the input file used when generating it.  This code is not
+  standalone and requires a support library to be linked with it.  This
+  support library is itself covered by the above license.
+
+
+
+  Skia
+
+
+  // Copyright (c) 2011 Google Inc. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  zlib
+
+
+  /* zlib.h -- interface of the 'zlib' general purpose compression library
+    version 1.2.4, March 14th, 2010
+
+    Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+    This software is provided 'as-is', without any express or implied
+    warranty.  In no event will the authors be held liable for any damages
+    arising from the use of this software.
+
+    Permission is granted to anyone to use this software for any purpose,
+    including commercial applications, and to alter it and redistribute it
+    freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not
+       claim that you wrote the original software. If you use this software
+       in a product, an acknowledgment in the product documentation would be
+       appreciated but is not required.
+    2. Altered source versions must be plainly marked as such, and must not be
+       misrepresented as being the original software.
+    3. This notice may not be removed or altered from any source distribution.
+
+    Jean-loup Gailly
+    Mark Adler
+
+  */
+
+
+
+  WebKit
+
+  Copyright (C) 2006, 2007, 2008, 2009 Apple Inc.  All rights reserved.
+  Copyright (C) 2007-2009 Torch Mobile, Inc.
+  Copyright (C) Research In Motion Limited 2010. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  SuperFastHash
+
+  Paul Hsieh OLD BSD license
+
+  Copyright (c) 2010, Paul Hsieh
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification,
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or
+    other materials provided with the distribution.
+  * Neither my name, Paul Hsieh, nor the names of any other contributors to the
+    code use may not be used to endorse or promote products derived from this
+    software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  musl
+
+  ----------------------------------------------------------------------
+  Copyright © 2005-2014 Rich Felker, et al.
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  ----------------------------------------------------------------------
+
+
+
+  brotli
+
+  Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+
+
+  woff2
+
+  Copyright (c) 2013-2017 by the WOFF2 Authors.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+
+
+  jsmn(indirect usage in ce_cdm)
+
+  Copyright (c) 2010 Serge A. Zaitsev
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+
+
+
+  libvpx
+
+
+  Copyright (c) 2010, The WebM Project authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the
+      distribution.
+
+    * Neither the name of Google, nor the WebM Project, nor the names
+      of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written
+      permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  ots
+
+
+  Copyright (c) 2009-2017 The OTS Authors. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+     * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+     * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+     * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  quiche
+
+  // Copyright 2015 The Chromium Authors. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  jinja2
+
+  Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
+
+  Some rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+
+      * The names of the contributors may not be used to endorse or
+        promote products derived from this software without specific
+        prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  opus
+
+
+  Contributions to the collaboration shall not be considered confidential.
+
+  Each contributor represents and warrants that it has the right and
+  authority to license copyright in its contributions to the collaboration.
+
+  Each contributor agrees to license the copyright in the contributions
+  under the Modified (2-clause or 3-clause) BSD License or the Clear BSD License.
+
+  Please see the IPR statements submitted to the IETF for the complete
+  patent licensing details:
+
+  Xiph.Org Foundation:
+  https://datatracker.ietf.org/ipr/1524/
+
+  Microsoft Corporation:
+  https://datatracker.ietf.org/ipr/1914/
+
+  Skype Limited:
+  https://datatracker.ietf.org/ipr/1602/
+
+  Broadcom Corporation:
+  https://datatracker.ietf.org/ipr/1526/
+
+
+
+  LLVM
+
+
+  ==============================================================================
+  LLVM Release License
+  ==============================================================================
+  University of Illinois/NCSA
+  Open Source License
+
+  Copyright (c) 2003-2018 University of Illinois at Urbana-Champaign.
+  All rights reserved.
+
+  Developed by:
+
+      LLVM Team
+
+      University of Illinois at Urbana-Champaign
+
+      http://llvm.org
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy of
+  this software and associated documentation files (the "Software"), to deal with
+  the Software without restriction, including without limitation the rights to
+  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+  of the Software, and to permit persons to whom the Software is furnished to do
+  so, subject to the following conditions:
+
+      * Redistributions of source code must retain the above copyright notice,
+        this list of conditions and the following disclaimers.
+
+      * Redistributions in binary form must reproduce the above copyright notice,
+        this list of conditions and the following disclaimers in the
+        documentation and/or other materials provided with the distribution.
+
+      * Neither the names of the LLVM Team, University of Illinois at
+        Urbana-Champaign, nor the names of its contributors may be used to
+        endorse or promote products derived from this Software without specific
+        prior written permission.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+  SOFTWARE.
+
+  ==============================================================================
+  Copyrights and Licenses for Third Party Software Distributed with LLVM:
+  ==============================================================================
+  The LLVM software contains code written by third parties.  Such software will
+  have its own individual LICENSE.TXT file in the directory in which it appears.
+  This file will describe the copyrights, license, and restrictions which apply
+  to that code.
+
+  The disclaimer of warranty in the University of Illinois Open Source License
+  applies to all code in the LLVM Distribution, and nothing in any of the
+  other licenses gives permission to use the names of the LLVM Team or the
+  University of Illinois to endorse or promote products derived from this
+  Software.
+
+  The following pieces of software have additional or alternate copyrights,
+  licenses, and/or restrictions:
+
+  Program             Directory
+  -------             ---------
+  Google Test         llvm/utils/unittest/googletest
+  OpenBSD regex       llvm/lib/Support/{reg*, COPYRIGHT.regex}
+  pyyaml tests        llvm/test/YAMLParser/{*.data, LICENSE.TXT}
+  ARM contributions   llvm/lib/Target/ARM/LICENSE.TXT
+  md5 contributions   llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
+
+
+
+  libaom(headers only)
+
+
+  Copyright (c) 2016, Alliance for Open Media. All rights reserved.
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in
+     the documentation and/or other materials provided with the
+     distribution.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+
+
+  flac
+
+
+  Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007  Josh Coalson
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+
+  - Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+  - Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+  - Neither the name of the Xiph.org Foundation nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  angle
+
+
+  // Copyright 2018 The ANGLE Project Authors.
+  // All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions
+  // are met:
+  //
+  //     Redistributions of source code must retain the above copyright
+  //     notice, this list of conditions and the following disclaimer.
+  //
+  //     Redistributions in binary form must reproduce the above
+  //     copyright notice, this list of conditions and the following
+  //     disclaimer in the documentation and/or other materials provided
+  //     with the distribution.
+  //
+  //     Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc.
+  //     Ltd., nor the names of their contributors may be used to endorse
+  //     or promote products derived from this software without specific
+  //     prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+  // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+  // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+  // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+  // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+  // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  // POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  quirc
+
+
+  quirc -- QR-code recognition library
+  Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>
+
+  Permission to use, copy, modify, and/or distribute this software for
+  any purpose with or without fee is hereby granted, provided that the
+  above copyright notice and this permission notice appear in all
+  copies.
+
+  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+  WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+  AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+  PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+  TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+  PERFORMANCE OF THIS SOFTWARE.
+
+
+
+  markupsafe
+
+
+  Copyright (c) 2010 by Armin Ronacher and contributors.  See AUTHORS
+  for more details.
+
+  Some rights reserved.
+
+  Redistribution and use in source and binary forms of the software as well
+  as documentation, with or without modification, are permitted provided
+  that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following
+    disclaimer in the documentation and/or other materials provided
+    with the distribution.
+
+  * The names of the contributors may not be used to endorse or
+    promote products derived from this software without specific
+    prior written permission.
+
+  THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+
+
+  websocket-client
+
+
+  Copyright 2018 Hiroki Ohtani.
+
+  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+   pyjson5
+
+
+   Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+  proxy_py
+
+
+  Copyright (c) 2013-2018 by Abhinav Singh and contributors.
+
+  Some rights reserved.
+
+  Redistribution and use in source and binary forms of the software as well
+  as documentation, with or without modification, are permitted provided
+  that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following
+    disclaimer in the documentation and/or other materials provided
+    with the distribution.
+
+  * The names of the contributors may not be used to endorse or
+    promote products derived from this software without specific
+    prior written permission.
+
+  THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.
+
+
+
+  web platform tests
+
+
+  This repository is covered by the dual-licensing approach described in:
+
+    http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
+
+
+
+  ply
+
+
+  PLY (Python Lex-Yacc)                   Version 3.4
+
+  Copyright (C) 2001-2011,
+  David M. Beazley (Dabeaz LLC)
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the name of the David Beazley or Dabeaz LLC may be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  khronos
+
+
+  Copyright (c) 2007-2010 The Khronos Group Inc.
+
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and/or associated documentation files (the
+  "Materials"), to deal in the Materials without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Materials, and to
+  permit persons to whom the Materials are furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Materials.
+
+  THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+  MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
+
+  SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+
+  Copyright (C) 1992 Silicon Graphics, Inc. All Rights Reserved.
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy of
+  this software and associated documentation files (the "Software"), to deal in
+  the Software without restriction, including without limitation the rights to
+  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+  of the Software, and to permit persons to whom the Software is furnished to do
+  so, subject to the following conditions:
+
+  The above copyright notice including the dates of first publication and either
+  this permission notice or a reference to http://oss.sgi.com/projects/FreeB/
+  shall be included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON
+  GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+  Except as contained in this notice, the name of Silicon Graphics, Inc. shall
+  not be used in advertising or otherwise to promote the sale, use or other
+  dealings in this Software without prior written authorization from Silicon
+  Graphics, Inc.
+
+
+
+  google_benchmark
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+  crashpad
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
+  libdav1d
+
+
+  Copyright © 2018-2019, VideoLAN and dav1d authors
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice, this
+     list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright notice,
+     this list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  linux-syscall-support
+
+
+  Copyright (c) 2005-2011, Google Inc.
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+  * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+  * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  ---
+  Author: Markus Gutschke
+
+
+
+  mini_chromium
+
+
+  // Copyright 2006-2008 The Chromium Authors. All rights reserved.
+  //
+  // Redistribution and use in source and binary forms, with or without
+  // modification, are permitted provided that the following conditions are
+  // met:
+  //
+  //    * Redistributions of source code must retain the above copyright
+  // notice, this list of conditions and the following disclaimer.
+  //    * Redistributions in binary form must reproduce the above
+  // copyright notice, this list of conditions and the following disclaimer
+  // in the documentation and/or other materials provided with the
+  // distribution.
+  //    * Neither the name of Google Inc. nor the names of its
+  // contributors may be used to endorse or promote products derived from
+  // this software without specific prior written permission.
+  //
+  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  googletest
+
+
+  Copyright 2008, Google Inc.
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+
+      * Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the following disclaimer
+  in the documentation and/or other materials provided with the
+  distribution.
+      * Neither the name of Google Inc. nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+  lz4_lib
+
+
+  LZ4 Library
+  Copyright (c) 2011-2016, Yann Collet
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification,
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice, this
+    list of conditions and the following disclaimer in the documentation and/or
+    other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+  libwebp
+
+  Copyright (c) 2010, Google Inc. All rights reserved.  Redistribution and use
+  in source and binary forms, with or without modification, are permitted
+  provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of Google nor the names of its contributors may be used
+      to endorse or promote products derived from this software without specific
+      prior written permission.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+  HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  Additional IP Rights Grant (Patents) ------------------------------------
+  "These implementations" means the copyrightable works that implement the
+  WebM codecs distributed by Google as part of the WebM Project.  Google
+  hereby grants to you a perpetual, worldwide, non-exclusive, no-charge,
+  royalty-free, irrevocable (except as stated in this section) patent
+  license to make, have made, use, offer to sell, sell, import, transfer,
+  and otherwise run, modify and propagate the contents of these
+  implementations of WebM, where such license applies only to those patent
+  claims, both currently owned by Google and acquired in the future,
+  licensable by Google that are necessarily infringed by these
+  implementations of WebM. This grant does not include claims that would be
+  infringed only as a consequence of further modification of these
+  implementations. If you or your agent or exclusive licensee institute or
+  order or agree to the institution of patent litigation or any other patent
+  enforcement activity against any entity (including a cross-claim or
+  counterclaim in a lawsuit) alleging that any of these implementations of
+  WebM or any code incorporated within any of these implementations of WebM
+  constitute direct or contributory patent infringement, or inducement of
+  patent infringement, then any patent rights granted to you under this
+  License for these implementations of WebM shall terminate as of the date
+  such litigation is filed.
diff --git a/cobalt/content/licenses/platform/default/licenses_cobalt.txt b/cobalt/content/licenses/platform/default/licenses_cobalt.txt
index 3b7afae..7d3b733 100644
--- a/cobalt/content/licenses/platform/default/licenses_cobalt.txt
+++ b/cobalt/content/licenses/platform/default/licenses_cobalt.txt
@@ -176,6 +176,68 @@
    limitations under the License.
 
 
+  Fraunhofer FDK AAC Codec Library
+
+  Software License for The Fraunhofer FDK AAC Codec Library for Android
+  © Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
+    All rights reserved.
+  1.    INTRODUCTION
+  The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
+  the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
+  This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
+  AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
+  audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
+  independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
+  of the MPEG specifications.
+  Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
+  may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
+  individually for the purpose of encoding or decoding bit streams in products that are compliant with
+  the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
+  these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
+  software may already be covered under those patent licenses when it is used for those licensed purposes only.
+  Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
+  are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
+  applications information and documentation.
+  2.    COPYRIGHT LICENSE
+  Redistribution and use in source and binary forms, with or without modification, are permitted without
+  payment of copyright license fees provided that you satisfy the following conditions:
+  You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
+  your modifications thereto in source code form.
+  You must retain the complete text of this software license in the documentation and/or other materials
+  provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
+  You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
+  modifications thereto to recipients of copies in binary form.
+  The name of Fraunhofer may not be used to endorse or promote products derived from this library without
+  prior written permission.
+  You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
+  software or your modifications thereto.
+  Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
+  and the date of any change. For modified versions of the FDK AAC Codec, the term
+  "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
+  "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
+  3.    NO PATENT LICENSE
+  NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
+  ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
+  respect to this software.
+  You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
+  by appropriate patent licenses.
+  4.    DISCLAIMER
+  This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
+  "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
+  of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+  CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
+  including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
+  or business interruption, however caused and on any theory of liability, whether in contract, strict
+  liability, or tort (including negligence), arising in any way out of the use of this software, even if
+  advised of the possibility of such damage.
+  5.    CONTACT INFORMATION
+  Fraunhofer Institute for Integrated Circuits IIS
+  Attention: Audio and Multimedia Departments - FDK AAC LL
+  Am Wolfsmantel 33
+  91058 Erlangen, Germany
+  www.iis.fraunhofer.de/amm
+  amm-info@iis.fraunhofer.de
+
 
   Chromium
 
@@ -735,42 +797,472 @@
 
   Netscape Portable Runtime (NSPR)
 
+                             MOZILLA PUBLIC LICENSE
+                                Version 1.1
 
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is the Netscape Portable Runtime (NSPR).
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 1998-2000
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
+   The contents of this file are subject to the Mozilla Public License Version
+   1.1 (the "License"); you may not use this file except in compliance with
+   the License. You may obtain a copy of the License at
+   http://www.mozilla.org/MPL/
+
+   Software distributed under the License is distributed on an "AS IS" basis,
+   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   for the specific language governing rights and limitations under the
+   License.
+
+   The Original Code is the Netscape Portable Runtime (NSPR).
+
+   The Initial Developer of the Original Code is
+   Netscape Communications Corporation.
+   Portions created by the Initial Developer are Copyright (C) 1998-2000
+   the Initial Developer. All Rights Reserved.
+
+   Contributor(s):
+
+   Alternatively, the contents of this file may be used under the terms of
+   either the GNU General Public License Version 2 or later (the "GPL"), or
+   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   in which case the provisions of the GPL or the LGPL are applicable instead
+   of those above. If you wish to allow use of your version of this file only
+   under the terms of either the GPL or the LGPL, and not to allow others to
+   use your version of this file under the terms of the MPL, indicate your
+   decision by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL or the LGPL. If you do not delete
+   the provisions above, a recipient may use your version of this file under
+   the terms of any one of the MPL, the GPL or the LGPL.
 
 
   symbolize
@@ -1237,455 +1729,6 @@
 
 
 
-  nss
-
-
-    NSS is available under the Mozilla Public License, version 2, a copy of which
-  is below.
-
-  Note on GPL Compatibility
-  -------------------------
-
-  The MPL 2, section 3.3, permits you to combine NSS with code under the GNU
-  General Public License (GPL) version 2, or any later version of that
-  license, to make a Larger Work, and distribute the result under the GPL.
-  The only condition is that you must also make NSS, and any changes you
-  have made to it, available to recipients under the terms of the MPL 2 also.
-
-  Anyone who receives the combined code from you does not have to continue
-  to dual licence in this way, and may, if they wish, distribute under the
-  terms of either of the two licences - either the MPL alone or the GPL
-  alone. However, we discourage people from distributing copies of NSS under
-  the GPL alone, because it means that any improvements they make cannot be
-  reincorporated into the main version of NSS. There is never a need to do
-  this for license compatibility reasons.
-
-  Note on LGPL Compatibility
-  --------------------------
-
-  The above also applies to combining MPLed code in a single library with
-  code under the GNU Lesser General Public License (LGPL) version 2.1, or
-  any later version of that license. If the LGPLed code and the MPLed code
-  are not in the same library, then the copyleft coverage of the two
-  licences does not overlap, so no issues arise.
-
-
-  Mozilla Public License Version 2.0
-  ==================================
-
-  1. Definitions
-  --------------
-
-  1.1. "Contributor"
-      means each individual or legal entity that creates, contributes to
-      the creation of, or owns Covered Software.
-
-  1.2. "Contributor Version"
-      means the combination of the Contributions of others (if any) used
-      by a Contributor and that particular Contributor's Contribution.
-
-  1.3. "Contribution"
-      means Covered Software of a particular Contributor.
-
-  1.4. "Covered Software"
-      means Source Code Form to which the initial Contributor has attached
-      the notice in Exhibit A, the Executable Form of such Source Code
-      Form, and Modifications of such Source Code Form, in each case
-      including portions thereof.
-
-  1.5. "Incompatible With Secondary Licenses"
-      means
-
-      (a) that the initial Contributor has attached the notice described
-          in Exhibit B to the Covered Software; or
-
-      (b) that the Covered Software was made available under the terms of
-          version 1.1 or earlier of the License, but not also under the
-          terms of a Secondary License.
-
-  1.6. "Executable Form"
-      means any form of the work other than Source Code Form.
-
-  1.7. "Larger Work"
-      means a work that combines Covered Software with other material, in
-      a separate file or files, that is not Covered Software.
-
-  1.8. "License"
-      means this document.
-
-  1.9. "Licensable"
-      means having the right to grant, to the maximum extent possible,
-      whether at the time of the initial grant or subsequently, any and
-      all of the rights conveyed by this License.
-
-  1.10. "Modifications"
-      means any of the following:
-
-      (a) any file in Source Code Form that results from an addition to,
-          deletion from, or modification of the contents of Covered
-          Software; or
-
-      (b) any new file in Source Code Form that contains any Covered
-          Software.
-
-  1.11. "Patent Claims" of a Contributor
-      means any patent claim(s), including without limitation, method,
-      process, and apparatus claims, in any patent Licensable by such
-      Contributor that would be infringed, but for the grant of the
-      License, by the making, using, selling, offering for sale, having
-      made, import, or transfer of either its Contributions or its
-      Contributor Version.
-
-  1.12. "Secondary License"
-      means either the GNU General Public License, Version 2.0, the GNU
-      Lesser General Public License, Version 2.1, the GNU Affero General
-      Public License, Version 3.0, or any later versions of those
-      licenses.
-
-  1.13. "Source Code Form"
-      means the form of the work preferred for making modifications.
-
-  1.14. "You" (or "Your")
-      means an individual or a legal entity exercising rights under this
-      License. For legal entities, "You" includes any entity that
-      controls, is controlled by, or is under common control with You. For
-      purposes of this definition, "control" means (a) the power, direct
-      or indirect, to cause the direction or management of such entity,
-      whether by contract or otherwise, or (b) ownership of more than
-      fifty percent (50%) of the outstanding shares or beneficial
-      ownership of such entity.
-
-  2. License Grants and Conditions
-  --------------------------------
-
-  2.1. Grants
-
-  Each Contributor hereby grants You a world-wide, royalty-free,
-  non-exclusive license:
-
-  (a) under intellectual property rights (other than patent or trademark)
-      Licensable by such Contributor to use, reproduce, make available,
-      modify, display, perform, distribute, and otherwise exploit its
-      Contributions, either on an unmodified basis, with Modifications, or
-      as part of a Larger Work; and
-
-  (b) under Patent Claims of such Contributor to make, use, sell, offer
-      for sale, have made, import, and otherwise transfer either its
-      Contributions or its Contributor Version.
-
-  2.2. Effective Date
-
-  The licenses granted in Section 2.1 with respect to any Contribution
-  become effective for each Contribution on the date the Contributor first
-  distributes such Contribution.
-
-  2.3. Limitations on Grant Scope
-
-  The licenses granted in this Section 2 are the only rights granted under
-  this License. No additional rights or licenses will be implied from the
-  distribution or licensing of Covered Software under this License.
-  Notwithstanding Section 2.1(b) above, no patent license is granted by a
-  Contributor:
-
-  (a) for any code that a Contributor has removed from Covered Software;
-      or
-
-  (b) for infringements caused by: (i) Your and any other third party's
-      modifications of Covered Software, or (ii) the combination of its
-      Contributions with other software (except as part of its Contributor
-      Version); or
-
-  (c) under Patent Claims infringed by Covered Software in the absence of
-      its Contributions.
-
-  This License does not grant any rights in the trademarks, service marks,
-  or logos of any Contributor (except as may be necessary to comply with
-  the notice requirements in Section 3.4).
-
-  2.4. Subsequent Licenses
-
-  No Contributor makes additional grants as a result of Your choice to
-  distribute the Covered Software under a subsequent version of this
-  License (see Section 10.2) or under the terms of a Secondary License (if
-  permitted under the terms of Section 3.3).
-
-  2.5. Representation
-
-  Each Contributor represents that the Contributor believes its
-  Contributions are its original creation(s) or it has sufficient rights
-  to grant the rights to its Contributions conveyed by this License.
-
-  2.6. Fair Use
-
-  This License is not intended to limit any rights You have under
-  applicable copyright doctrines of fair use, fair dealing, or other
-  equivalents.
-
-  2.7. Conditions
-
-  Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-  in Section 2.1.
-
-  3. Responsibilities
-  -------------------
-
-  3.1. Distribution of Source Form
-
-  All distribution of Covered Software in Source Code Form, including any
-  Modifications that You create or to which You contribute, must be under
-  the terms of this License. You must inform recipients that the Source
-  Code Form of the Covered Software is governed by the terms of this
-  License, and how they can obtain a copy of this License. You may not
-  attempt to alter or restrict the recipients' rights in the Source Code
-  Form.
-
-  3.2. Distribution of Executable Form
-
-  If You distribute Covered Software in Executable Form then:
-
-  (a) such Covered Software must also be made available in Source Code
-      Form, as described in Section 3.1, and You must inform recipients of
-      the Executable Form how they can obtain a copy of such Source Code
-      Form by reasonable means in a timely manner, at a charge no more
-      than the cost of distribution to the recipient; and
-
-  (b) You may distribute such Executable Form under the terms of this
-      License, or sublicense it under different terms, provided that the
-      license for the Executable Form does not attempt to limit or alter
-      the recipients' rights in the Source Code Form under this License.
-
-  3.3. Distribution of a Larger Work
-
-  You may create and distribute a Larger Work under terms of Your choice,
-  provided that You also comply with the requirements of this License for
-  the Covered Software. If the Larger Work is a combination of Covered
-  Software with a work governed by one or more Secondary Licenses, and the
-  Covered Software is not Incompatible With Secondary Licenses, this
-  License permits You to additionally distribute such Covered Software
-  under the terms of such Secondary License(s), so that the recipient of
-  the Larger Work may, at their option, further distribute the Covered
-  Software under the terms of either this License or such Secondary
-  License(s).
-
-  3.4. Notices
-
-  You may not remove or alter the substance of any license notices
-  (including copyright notices, patent notices, disclaimers of warranty,
-  or limitations of liability) contained within the Source Code Form of
-  the Covered Software, except that You may alter any license notices to
-  the extent required to remedy known factual inaccuracies.
-
-  3.5. Application of Additional Terms
-
-  You may choose to offer, and to charge a fee for, warranty, support,
-  indemnity or liability obligations to one or more recipients of Covered
-  Software. However, You may do so only on Your own behalf, and not on
-  behalf of any Contributor. You must make it absolutely clear that any
-  such warranty, support, indemnity, or liability obligation is offered by
-  You alone, and You hereby agree to indemnify every Contributor for any
-  liability incurred by such Contributor as a result of warranty, support,
-  indemnity or liability terms You offer. You may include additional
-  disclaimers of warranty and limitations of liability specific to any
-  jurisdiction.
-
-  4. Inability to Comply Due to Statute or Regulation
-  ---------------------------------------------------
-
-  If it is impossible for You to comply with any of the terms of this
-  License with respect to some or all of the Covered Software due to
-  statute, judicial order, or regulation then You must: (a) comply with
-  the terms of this License to the maximum extent possible; and (b)
-  describe the limitations and the code they affect. Such description must
-  be placed in a text file included with all distributions of the Covered
-  Software under this License. Except to the extent prohibited by statute
-  or regulation, such description must be sufficiently detailed for a
-  recipient of ordinary skill to be able to understand it.
-
-  5. Termination
-  --------------
-
-  5.1. The rights granted under this License will terminate automatically
-  if You fail to comply with any of its terms. However, if You become
-  compliant, then the rights granted under this License from a particular
-  Contributor are reinstated (a) provisionally, unless and until such
-  Contributor explicitly and finally terminates Your grants, and (b) on an
-  ongoing basis, if such Contributor fails to notify You of the
-  non-compliance by some reasonable means prior to 60 days after You have
-  come back into compliance. Moreover, Your grants from a particular
-  Contributor are reinstated on an ongoing basis if such Contributor
-  notifies You of the non-compliance by some reasonable means, this is the
-  first time You have received notice of non-compliance with this License
-  from such Contributor, and You become compliant prior to 30 days after
-  Your receipt of the notice.
-
-  5.2. If You initiate litigation against any entity by asserting a patent
-  infringement claim (excluding declaratory judgment actions,
-  counter-claims, and cross-claims) alleging that a Contributor Version
-  directly or indirectly infringes any patent, then the rights granted to
-  You by any and all Contributors for the Covered Software under Section
-  2.1 of this License shall terminate.
-
-  5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-  end user license agreements (excluding distributors and resellers) which
-  have been validly granted by You or Your distributors under this License
-  prior to termination shall survive termination.
-
-  ************************************************************************
-  *                                                                      *
-  *  6. Disclaimer of Warranty                                           *
-  *  -------------------------                                           *
-  *                                                                      *
-  *  Covered Software is provided under this License on an "as is"       *
-  *  basis, without warranty of any kind, either expressed, implied, or  *
-  *  statutory, including, without limitation, warranties that the       *
-  *  Covered Software is free of defects, merchantable, fit for a        *
-  *  particular purpose or non-infringing. The entire risk as to the     *
-  *  quality and performance of the Covered Software is with You.        *
-  *  Should any Covered Software prove defective in any respect, You     *
-  *  (not any Contributor) assume the cost of any necessary servicing,   *
-  *  repair, or correction. This disclaimer of warranty constitutes an   *
-  *  essential part of this License. No use of any Covered Software is   *
-  *  authorized under this License except under this disclaimer.         *
-  *                                                                      *
-  ************************************************************************
-
-  ************************************************************************
-  *                                                                      *
-  *  7. Limitation of Liability                                          *
-  *  --------------------------                                          *
-  *                                                                      *
-  *  Under no circumstances and under no legal theory, whether tort      *
-  *  (including negligence), contract, or otherwise, shall any           *
-  *  Contributor, or anyone who distributes Covered Software as          *
-  *  permitted above, be liable to You for any direct, indirect,         *
-  *  special, incidental, or consequential damages of any character      *
-  *  including, without limitation, damages for lost profits, loss of    *
-  *  goodwill, work stoppage, computer failure or malfunction, or any    *
-  *  and all other commercial damages or losses, even if such party      *
-  *  shall have been informed of the possibility of such damages. This   *
-  *  limitation of liability shall not apply to liability for death or   *
-  *  personal injury resulting from such party's negligence to the       *
-  *  extent applicable law prohibits such limitation. Some               *
-  *  jurisdictions do not allow the exclusion or limitation of           *
-  *  incidental or consequential damages, so this exclusion and          *
-  *  limitation may not apply to You.                                    *
-  *                                                                      *
-  ************************************************************************
-
-  8. Litigation
-  -------------
-
-  Any litigation relating to this License may be brought only in the
-  courts of a jurisdiction where the defendant maintains its principal
-  place of business and such litigation shall be governed by laws of that
-  jurisdiction, without reference to its conflict-of-law provisions.
-  Nothing in this Section shall prevent a party's ability to bring
-  cross-claims or counter-claims.
-
-  9. Miscellaneous
-  ----------------
-
-  This License represents the complete agreement concerning the subject
-  matter hereof. If any provision of this License is held to be
-  unenforceable, such provision shall be reformed only to the extent
-  necessary to make it enforceable. Any law or regulation which provides
-  that the language of a contract shall be construed against the drafter
-  shall not be used to construe this License against a Contributor.
-
-  10. Versions of the License
-  ---------------------------
-
-  10.1. New Versions
-
-  Mozilla Foundation is the license steward. Except as provided in Section
-  10.3, no one other than the license steward has the right to modify or
-  publish new versions of this License. Each version will be given a
-  distinguishing version number.
-
-  10.2. Effect of New Versions
-
-  You may distribute the Covered Software under the terms of the version
-  of the License under which You originally received the Covered Software,
-  or under the terms of any subsequent version published by the license
-  steward.
-
-  10.3. Modified Versions
-
-  If you create software not governed by this License, and you want to
-  create a new license for such software, you may create and use a
-  modified version of this License if you rename the license and remove
-  any references to the name of the license steward (except to note that
-  such modified license differs from this License).
-
-  10.4. Distributing Source Code Form that is Incompatible With Secondary
-  Licenses
-
-  If You choose to distribute Source Code Form that is Incompatible With
-  Secondary Licenses under the terms of this version of the License, the
-  notice described in Exhibit B of this License must be attached.
-
-  Exhibit A - Source Code Form License Notice
-  -------------------------------------------
-
-    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 it is not possible or desirable to put the notice in a particular
-  file, then You may include the notice in a location (such as a LICENSE
-  file in a relevant directory) where a recipient would be likely to look
-  for such a notice.
-
-  You may add additional accurate notices of copyright ownership.
-
-  Exhibit B - "Incompatible With Secondary Licenses" Notice
-  ---------------------------------------------------------
-
-    This Source Code Form is "Incompatible With Secondary Licenses", as
-    defined by the Mozilla Public License, v. 2.0.
-
-
-
-  mozilla_security_manager
-
-
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is mozilla.org code.
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 2001
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
-
-
   mozilla(url/third_party/mozilla)
 
 
@@ -1723,6 +1766,443 @@
   The file url_parse.cc is based on nsURLParsers.cc from Mozilla. This file is
   licensed separately as follows:
 
+  --------------------------------------------------------------------------------
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
   The contents of this file are subject to the Mozilla Public License Version
   1.1 (the "License"); you may not use this file except in compliance with
   the License. You may obtain a copy of the License at
@@ -5527,6 +6007,7 @@
   License for these implementations of WebM shall terminate as of the date
   such litigation is filed.
 
+
   QR-Code-generator
 
   Copyright © 2020 Project Nayuki. (MIT License)
@@ -5551,71 +6032,6 @@
   Software.
 
 
-
-  Fraunhofer FDK AAC Codec Library
-
-  Software License for The Fraunhofer FDK AAC Codec Library for Android
-  © Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
-    All rights reserved.
-  1.    INTRODUCTION
-  The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
-  the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
-  This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
-  AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
-  audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
-  independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
-  of the MPEG specifications.
-  Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
-  may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
-  individually for the purpose of encoding or decoding bit streams in products that are compliant with
-  the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
-  these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
-  software may already be covered under those patent licenses when it is used for those licensed purposes only.
-  Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
-  are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
-  applications information and documentation.
-  2.    COPYRIGHT LICENSE
-  Redistribution and use in source and binary forms, with or without modification, are permitted without
-  payment of copyright license fees provided that you satisfy the following conditions:
-  You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
-  your modifications thereto in source code form.
-  You must retain the complete text of this software license in the documentation and/or other materials
-  provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
-  You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
-  modifications thereto to recipients of copies in binary form.
-  The name of Fraunhofer may not be used to endorse or promote products derived from this library without
-  prior written permission.
-  You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
-  software or your modifications thereto.
-  Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
-  and the date of any change. For modified versions of the FDK AAC Codec, the term
-  "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
-  "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
-  3.    NO PATENT LICENSE
-  NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
-  ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
-  respect to this software.
-  You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
-  by appropriate patent licenses.
-  4.    DISCLAIMER
-  This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
-  "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
-  of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-  CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
-  including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
-  or business interruption, however caused and on any theory of liability, whether in contract, strict
-  liability, or tort (including negligence), arising in any way out of the use of this software, even if
-  advised of the possibility of such damage.
-  5.    CONTACT INFORMATION
-  Fraunhofer Institute for Integrated Circuits IIS
-  Attention: Audio and Multimedia Departments - FDK AAC LL
-  Am Wolfsmantel 33
-  91058 Erlangen, Germany
-  www.iis.fraunhofer.de/amm
-  amm-info@iis.fraunhofer.de
-
-
-
   openh264
 
 
diff --git a/cobalt/content/licenses/platform/evergreen/licenses_cobalt.txt b/cobalt/content/licenses/platform/evergreen/licenses_cobalt.txt
index 2244b3d..e889e54 100644
--- a/cobalt/content/licenses/platform/evergreen/licenses_cobalt.txt
+++ b/cobalt/content/licenses/platform/evergreen/licenses_cobalt.txt
@@ -735,42 +735,472 @@
 
   Netscape Portable Runtime (NSPR)
 
+                             MOZILLA PUBLIC LICENSE
+                                Version 1.1
 
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is the Netscape Portable Runtime (NSPR).
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 1998-2000
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
+   The contents of this file are subject to the Mozilla Public License Version
+   1.1 (the "License"); you may not use this file except in compliance with
+   the License. You may obtain a copy of the License at
+   http://www.mozilla.org/MPL/
+
+   Software distributed under the License is distributed on an "AS IS" basis,
+   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   for the specific language governing rights and limitations under the
+   License.
+
+   The Original Code is the Netscape Portable Runtime (NSPR).
+
+   The Initial Developer of the Original Code is
+   Netscape Communications Corporation.
+   Portions created by the Initial Developer are Copyright (C) 1998-2000
+   the Initial Developer. All Rights Reserved.
+
+   Contributor(s):
+
+   Alternatively, the contents of this file may be used under the terms of
+   either the GNU General Public License Version 2 or later (the "GPL"), or
+   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   in which case the provisions of the GPL or the LGPL are applicable instead
+   of those above. If you wish to allow use of your version of this file only
+   under the terms of either the GPL or the LGPL, and not to allow others to
+   use your version of this file under the terms of the MPL, indicate your
+   decision by deleting the provisions above and replace them with the notice
+   and other provisions required by the GPL or the LGPL. If you do not delete
+   the provisions above, a recipient may use your version of this file under
+   the terms of any one of the MPL, the GPL or the LGPL.
 
 
   symbolize
@@ -1237,455 +1667,6 @@
 
 
 
-  nss
-
-
-    NSS is available under the Mozilla Public License, version 2, a copy of which
-  is below.
-
-  Note on GPL Compatibility
-  -------------------------
-
-  The MPL 2, section 3.3, permits you to combine NSS with code under the GNU
-  General Public License (GPL) version 2, or any later version of that
-  license, to make a Larger Work, and distribute the result under the GPL.
-  The only condition is that you must also make NSS, and any changes you
-  have made to it, available to recipients under the terms of the MPL 2 also.
-
-  Anyone who receives the combined code from you does not have to continue
-  to dual licence in this way, and may, if they wish, distribute under the
-  terms of either of the two licences - either the MPL alone or the GPL
-  alone. However, we discourage people from distributing copies of NSS under
-  the GPL alone, because it means that any improvements they make cannot be
-  reincorporated into the main version of NSS. There is never a need to do
-  this for license compatibility reasons.
-
-  Note on LGPL Compatibility
-  --------------------------
-
-  The above also applies to combining MPLed code in a single library with
-  code under the GNU Lesser General Public License (LGPL) version 2.1, or
-  any later version of that license. If the LGPLed code and the MPLed code
-  are not in the same library, then the copyleft coverage of the two
-  licences does not overlap, so no issues arise.
-
-
-  Mozilla Public License Version 2.0
-  ==================================
-
-  1. Definitions
-  --------------
-
-  1.1. "Contributor"
-      means each individual or legal entity that creates, contributes to
-      the creation of, or owns Covered Software.
-
-  1.2. "Contributor Version"
-      means the combination of the Contributions of others (if any) used
-      by a Contributor and that particular Contributor's Contribution.
-
-  1.3. "Contribution"
-      means Covered Software of a particular Contributor.
-
-  1.4. "Covered Software"
-      means Source Code Form to which the initial Contributor has attached
-      the notice in Exhibit A, the Executable Form of such Source Code
-      Form, and Modifications of such Source Code Form, in each case
-      including portions thereof.
-
-  1.5. "Incompatible With Secondary Licenses"
-      means
-
-      (a) that the initial Contributor has attached the notice described
-          in Exhibit B to the Covered Software; or
-
-      (b) that the Covered Software was made available under the terms of
-          version 1.1 or earlier of the License, but not also under the
-          terms of a Secondary License.
-
-  1.6. "Executable Form"
-      means any form of the work other than Source Code Form.
-
-  1.7. "Larger Work"
-      means a work that combines Covered Software with other material, in
-      a separate file or files, that is not Covered Software.
-
-  1.8. "License"
-      means this document.
-
-  1.9. "Licensable"
-      means having the right to grant, to the maximum extent possible,
-      whether at the time of the initial grant or subsequently, any and
-      all of the rights conveyed by this License.
-
-  1.10. "Modifications"
-      means any of the following:
-
-      (a) any file in Source Code Form that results from an addition to,
-          deletion from, or modification of the contents of Covered
-          Software; or
-
-      (b) any new file in Source Code Form that contains any Covered
-          Software.
-
-  1.11. "Patent Claims" of a Contributor
-      means any patent claim(s), including without limitation, method,
-      process, and apparatus claims, in any patent Licensable by such
-      Contributor that would be infringed, but for the grant of the
-      License, by the making, using, selling, offering for sale, having
-      made, import, or transfer of either its Contributions or its
-      Contributor Version.
-
-  1.12. "Secondary License"
-      means either the GNU General Public License, Version 2.0, the GNU
-      Lesser General Public License, Version 2.1, the GNU Affero General
-      Public License, Version 3.0, or any later versions of those
-      licenses.
-
-  1.13. "Source Code Form"
-      means the form of the work preferred for making modifications.
-
-  1.14. "You" (or "Your")
-      means an individual or a legal entity exercising rights under this
-      License. For legal entities, "You" includes any entity that
-      controls, is controlled by, or is under common control with You. For
-      purposes of this definition, "control" means (a) the power, direct
-      or indirect, to cause the direction or management of such entity,
-      whether by contract or otherwise, or (b) ownership of more than
-      fifty percent (50%) of the outstanding shares or beneficial
-      ownership of such entity.
-
-  2. License Grants and Conditions
-  --------------------------------
-
-  2.1. Grants
-
-  Each Contributor hereby grants You a world-wide, royalty-free,
-  non-exclusive license:
-
-  (a) under intellectual property rights (other than patent or trademark)
-      Licensable by such Contributor to use, reproduce, make available,
-      modify, display, perform, distribute, and otherwise exploit its
-      Contributions, either on an unmodified basis, with Modifications, or
-      as part of a Larger Work; and
-
-  (b) under Patent Claims of such Contributor to make, use, sell, offer
-      for sale, have made, import, and otherwise transfer either its
-      Contributions or its Contributor Version.
-
-  2.2. Effective Date
-
-  The licenses granted in Section 2.1 with respect to any Contribution
-  become effective for each Contribution on the date the Contributor first
-  distributes such Contribution.
-
-  2.3. Limitations on Grant Scope
-
-  The licenses granted in this Section 2 are the only rights granted under
-  this License. No additional rights or licenses will be implied from the
-  distribution or licensing of Covered Software under this License.
-  Notwithstanding Section 2.1(b) above, no patent license is granted by a
-  Contributor:
-
-  (a) for any code that a Contributor has removed from Covered Software;
-      or
-
-  (b) for infringements caused by: (i) Your and any other third party's
-      modifications of Covered Software, or (ii) the combination of its
-      Contributions with other software (except as part of its Contributor
-      Version); or
-
-  (c) under Patent Claims infringed by Covered Software in the absence of
-      its Contributions.
-
-  This License does not grant any rights in the trademarks, service marks,
-  or logos of any Contributor (except as may be necessary to comply with
-  the notice requirements in Section 3.4).
-
-  2.4. Subsequent Licenses
-
-  No Contributor makes additional grants as a result of Your choice to
-  distribute the Covered Software under a subsequent version of this
-  License (see Section 10.2) or under the terms of a Secondary License (if
-  permitted under the terms of Section 3.3).
-
-  2.5. Representation
-
-  Each Contributor represents that the Contributor believes its
-  Contributions are its original creation(s) or it has sufficient rights
-  to grant the rights to its Contributions conveyed by this License.
-
-  2.6. Fair Use
-
-  This License is not intended to limit any rights You have under
-  applicable copyright doctrines of fair use, fair dealing, or other
-  equivalents.
-
-  2.7. Conditions
-
-  Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-  in Section 2.1.
-
-  3. Responsibilities
-  -------------------
-
-  3.1. Distribution of Source Form
-
-  All distribution of Covered Software in Source Code Form, including any
-  Modifications that You create or to which You contribute, must be under
-  the terms of this License. You must inform recipients that the Source
-  Code Form of the Covered Software is governed by the terms of this
-  License, and how they can obtain a copy of this License. You may not
-  attempt to alter or restrict the recipients' rights in the Source Code
-  Form.
-
-  3.2. Distribution of Executable Form
-
-  If You distribute Covered Software in Executable Form then:
-
-  (a) such Covered Software must also be made available in Source Code
-      Form, as described in Section 3.1, and You must inform recipients of
-      the Executable Form how they can obtain a copy of such Source Code
-      Form by reasonable means in a timely manner, at a charge no more
-      than the cost of distribution to the recipient; and
-
-  (b) You may distribute such Executable Form under the terms of this
-      License, or sublicense it under different terms, provided that the
-      license for the Executable Form does not attempt to limit or alter
-      the recipients' rights in the Source Code Form under this License.
-
-  3.3. Distribution of a Larger Work
-
-  You may create and distribute a Larger Work under terms of Your choice,
-  provided that You also comply with the requirements of this License for
-  the Covered Software. If the Larger Work is a combination of Covered
-  Software with a work governed by one or more Secondary Licenses, and the
-  Covered Software is not Incompatible With Secondary Licenses, this
-  License permits You to additionally distribute such Covered Software
-  under the terms of such Secondary License(s), so that the recipient of
-  the Larger Work may, at their option, further distribute the Covered
-  Software under the terms of either this License or such Secondary
-  License(s).
-
-  3.4. Notices
-
-  You may not remove or alter the substance of any license notices
-  (including copyright notices, patent notices, disclaimers of warranty,
-  or limitations of liability) contained within the Source Code Form of
-  the Covered Software, except that You may alter any license notices to
-  the extent required to remedy known factual inaccuracies.
-
-  3.5. Application of Additional Terms
-
-  You may choose to offer, and to charge a fee for, warranty, support,
-  indemnity or liability obligations to one or more recipients of Covered
-  Software. However, You may do so only on Your own behalf, and not on
-  behalf of any Contributor. You must make it absolutely clear that any
-  such warranty, support, indemnity, or liability obligation is offered by
-  You alone, and You hereby agree to indemnify every Contributor for any
-  liability incurred by such Contributor as a result of warranty, support,
-  indemnity or liability terms You offer. You may include additional
-  disclaimers of warranty and limitations of liability specific to any
-  jurisdiction.
-
-  4. Inability to Comply Due to Statute or Regulation
-  ---------------------------------------------------
-
-  If it is impossible for You to comply with any of the terms of this
-  License with respect to some or all of the Covered Software due to
-  statute, judicial order, or regulation then You must: (a) comply with
-  the terms of this License to the maximum extent possible; and (b)
-  describe the limitations and the code they affect. Such description must
-  be placed in a text file included with all distributions of the Covered
-  Software under this License. Except to the extent prohibited by statute
-  or regulation, such description must be sufficiently detailed for a
-  recipient of ordinary skill to be able to understand it.
-
-  5. Termination
-  --------------
-
-  5.1. The rights granted under this License will terminate automatically
-  if You fail to comply with any of its terms. However, if You become
-  compliant, then the rights granted under this License from a particular
-  Contributor are reinstated (a) provisionally, unless and until such
-  Contributor explicitly and finally terminates Your grants, and (b) on an
-  ongoing basis, if such Contributor fails to notify You of the
-  non-compliance by some reasonable means prior to 60 days after You have
-  come back into compliance. Moreover, Your grants from a particular
-  Contributor are reinstated on an ongoing basis if such Contributor
-  notifies You of the non-compliance by some reasonable means, this is the
-  first time You have received notice of non-compliance with this License
-  from such Contributor, and You become compliant prior to 30 days after
-  Your receipt of the notice.
-
-  5.2. If You initiate litigation against any entity by asserting a patent
-  infringement claim (excluding declaratory judgment actions,
-  counter-claims, and cross-claims) alleging that a Contributor Version
-  directly or indirectly infringes any patent, then the rights granted to
-  You by any and all Contributors for the Covered Software under Section
-  2.1 of this License shall terminate.
-
-  5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-  end user license agreements (excluding distributors and resellers) which
-  have been validly granted by You or Your distributors under this License
-  prior to termination shall survive termination.
-
-  ************************************************************************
-  *                                                                      *
-  *  6. Disclaimer of Warranty                                           *
-  *  -------------------------                                           *
-  *                                                                      *
-  *  Covered Software is provided under this License on an "as is"       *
-  *  basis, without warranty of any kind, either expressed, implied, or  *
-  *  statutory, including, without limitation, warranties that the       *
-  *  Covered Software is free of defects, merchantable, fit for a        *
-  *  particular purpose or non-infringing. The entire risk as to the     *
-  *  quality and performance of the Covered Software is with You.        *
-  *  Should any Covered Software prove defective in any respect, You     *
-  *  (not any Contributor) assume the cost of any necessary servicing,   *
-  *  repair, or correction. This disclaimer of warranty constitutes an   *
-  *  essential part of this License. No use of any Covered Software is   *
-  *  authorized under this License except under this disclaimer.         *
-  *                                                                      *
-  ************************************************************************
-
-  ************************************************************************
-  *                                                                      *
-  *  7. Limitation of Liability                                          *
-  *  --------------------------                                          *
-  *                                                                      *
-  *  Under no circumstances and under no legal theory, whether tort      *
-  *  (including negligence), contract, or otherwise, shall any           *
-  *  Contributor, or anyone who distributes Covered Software as          *
-  *  permitted above, be liable to You for any direct, indirect,         *
-  *  special, incidental, or consequential damages of any character      *
-  *  including, without limitation, damages for lost profits, loss of    *
-  *  goodwill, work stoppage, computer failure or malfunction, or any    *
-  *  and all other commercial damages or losses, even if such party      *
-  *  shall have been informed of the possibility of such damages. This   *
-  *  limitation of liability shall not apply to liability for death or   *
-  *  personal injury resulting from such party's negligence to the       *
-  *  extent applicable law prohibits such limitation. Some               *
-  *  jurisdictions do not allow the exclusion or limitation of           *
-  *  incidental or consequential damages, so this exclusion and          *
-  *  limitation may not apply to You.                                    *
-  *                                                                      *
-  ************************************************************************
-
-  8. Litigation
-  -------------
-
-  Any litigation relating to this License may be brought only in the
-  courts of a jurisdiction where the defendant maintains its principal
-  place of business and such litigation shall be governed by laws of that
-  jurisdiction, without reference to its conflict-of-law provisions.
-  Nothing in this Section shall prevent a party's ability to bring
-  cross-claims or counter-claims.
-
-  9. Miscellaneous
-  ----------------
-
-  This License represents the complete agreement concerning the subject
-  matter hereof. If any provision of this License is held to be
-  unenforceable, such provision shall be reformed only to the extent
-  necessary to make it enforceable. Any law or regulation which provides
-  that the language of a contract shall be construed against the drafter
-  shall not be used to construe this License against a Contributor.
-
-  10. Versions of the License
-  ---------------------------
-
-  10.1. New Versions
-
-  Mozilla Foundation is the license steward. Except as provided in Section
-  10.3, no one other than the license steward has the right to modify or
-  publish new versions of this License. Each version will be given a
-  distinguishing version number.
-
-  10.2. Effect of New Versions
-
-  You may distribute the Covered Software under the terms of the version
-  of the License under which You originally received the Covered Software,
-  or under the terms of any subsequent version published by the license
-  steward.
-
-  10.3. Modified Versions
-
-  If you create software not governed by this License, and you want to
-  create a new license for such software, you may create and use a
-  modified version of this License if you rename the license and remove
-  any references to the name of the license steward (except to note that
-  such modified license differs from this License).
-
-  10.4. Distributing Source Code Form that is Incompatible With Secondary
-  Licenses
-
-  If You choose to distribute Source Code Form that is Incompatible With
-  Secondary Licenses under the terms of this version of the License, the
-  notice described in Exhibit B of this License must be attached.
-
-  Exhibit A - Source Code Form License Notice
-  -------------------------------------------
-
-    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 it is not possible or desirable to put the notice in a particular
-  file, then You may include the notice in a location (such as a LICENSE
-  file in a relevant directory) where a recipient would be likely to look
-  for such a notice.
-
-  You may add additional accurate notices of copyright ownership.
-
-  Exhibit B - "Incompatible With Secondary Licenses" Notice
-  ---------------------------------------------------------
-
-    This Source Code Form is "Incompatible With Secondary Licenses", as
-    defined by the Mozilla Public License, v. 2.0.
-
-
-
-  mozilla_security_manager
-
-
-  /* ***** BEGIN LICENSE BLOCK *****
-   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
-   *
-   * The contents of this file are subject to the Mozilla Public License Version
-   * 1.1 (the "License"); you may not use this file except in compliance with
-   * the License. You may obtain a copy of the License at
-   * http://www.mozilla.org/MPL/
-   *
-   * Software distributed under the License is distributed on an "AS IS" basis,
-   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-   * for the specific language governing rights and limitations under the
-   * License.
-   *
-   * The Original Code is mozilla.org code.
-   *
-   * The Initial Developer of the Original Code is
-   * Netscape Communications Corporation.
-   * Portions created by the Initial Developer are Copyright (C) 2001
-   * the Initial Developer. All Rights Reserved.
-   *
-   * Contributor(s):
-   *
-   * Alternatively, the contents of this file may be used under the terms of
-   * either the GNU General Public License Version 2 or later (the "GPL"), or
-   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-   * in which case the provisions of the GPL or the LGPL are applicable instead
-   * of those above. If you wish to allow use of your version of this file only
-   * under the terms of either the GPL or the LGPL, and not to allow others to
-   * use your version of this file under the terms of the MPL, indicate your
-   * decision by deleting the provisions above and replace them with the notice
-   * and other provisions required by the GPL or the LGPL. If you do not delete
-   * the provisions above, a recipient may use your version of this file under
-   * the terms of any one of the MPL, the GPL or the LGPL.
-   *
-   * ***** END LICENSE BLOCK ***** */
-
-
   mozilla(url/third_party/mozilla)
 
 
@@ -1723,6 +1704,443 @@
   The file url_parse.cc is based on nsURLParsers.cc from Mozilla. This file is
   licensed separately as follows:
 
+  --------------------------------------------------------------------------------
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+  1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+  2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+  3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+  4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+  5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+  6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+  7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+  8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+  9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+  10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+  11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+  12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+  13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+  EXHIBIT A -Mozilla Public License.
+
   The contents of this file are subject to the Mozilla Public License Version
   1.1 (the "License"); you may not use this file except in compliance with
   the License. You may obtain a copy of the License at
@@ -2064,6 +2482,115 @@
 
 
 
+  libjpeg-turbo
+
+  libjpeg-turbo Licenses libjpeg-turbo is covered by three compatible BSD-style
+  open source licenses:
+
+  The IJG (Independent JPEG Group) License, which is listed in README.ijg
+
+  This license applies to the libjpeg API library and associated programs (any
+  code inherited from libjpeg, and any modifications to that code.)
+
+  The Modified (3-clause) BSD License, which is listed below
+
+  This license covers the TurboJPEG API library and associated programs, as well
+  as the build system.
+
+  The zlib License
+
+  This license is a subset of the other two, and it covers the libjpeg-turbo
+  SIMD extensions.
+
+  Complying with the libjpeg-turbo Licenses This section provides a roll-up of
+  the libjpeg-turbo licensing terms, to the best of our understanding.
+
+  If you are distributing a modified version of the libjpeg-turbo source, then:
+
+  You cannot alter or remove any existing copyright or license notices from the
+  source.
+
+  Origin
+
+  Clause 1 of the IJG License Clause 1 of the Modified BSD License Clauses 1 and
+  3 of the zlib License You must add your own copyright notice to the header of
+  each source file you modified, so others can tell that you modified that file
+  (if there is not an existing copyright header in that file, then you can
+  simply add a notice stating that you modified the file.)
+
+  Origin
+
+  Clause 1 of the IJG License Clause 2 of the zlib License You must include the
+  IJG README file, and you must not alter any of the copyright or license text
+  in that file.
+
+  Origin
+
+  Clause 1 of the IJG License If you are distributing only libjpeg-turbo
+  binaries without the source, or if you are distributing an application that
+  statically links with libjpeg-turbo, then:
+
+  Your product documentation must include a message stating:
+
+  This software is based in part on the work of the Independent JPEG Group.
+
+  Origin
+
+  Clause 2 of the IJG license If your binary distribution includes or uses the
+  TurboJPEG API, then your product documentation must include the text of the
+  Modified BSD License (see below.)
+
+  Origin
+
+  Clause 2 of the Modified BSD License You cannot use the name of the IJG or The
+  libjpeg-turbo Project or the contributors thereof in advertising, publicity,
+  etc.
+
+  Origin
+
+  IJG License Clause 3 of the Modified BSD License The IJG and The libjpeg-turbo
+  Project do not warrant libjpeg-turbo to be free of defects, nor do we accept
+  any liability for undesirable consequences resulting from your use of the
+  software.
+
+  Origin
+
+  IJG License Modified BSD License zlib License The Modified (3-clause) BSD
+  License Copyright (C)2009-2021 D. R. Commander. All Rights Reserved.
+  Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+  Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.  Redistributions in binary
+  form must reproduce the above copyright notice, this list of conditions and
+  the following disclaimer in the documentation and/or other materials provided
+  with the distribution.  Neither the name of the libjpeg-turbo Project nor the
+  names of its contributors may be used to endorse or promote products derived
+  from this software without specific prior written permission.  THIS SOFTWARE
+  IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS
+  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+  EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  Why Three Licenses?  The zlib License could have been used instead of the
+  Modified (3-clause) BSD License, and since the IJG License effectively
+  subsumes the distribution conditions of the zlib License, this would have
+  effectively placed libjpeg-turbo binary distributions under the IJG License.
+  However, the IJG License specifically refers to the Independent JPEG Group and
+  does not extend attribution and endorsement protections to other entities.
+  Thus, it was desirable to choose a license that granted us the same
+  protections for new code that were granted to the IJG for code derived from
+  their software.
+
+
   libpng
 
 
@@ -5372,69 +5899,51 @@
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+  libwebp
 
-  Fraunhofer FDK AAC Codec Library
-
-  Software License for The Fraunhofer FDK AAC Codec Library for Android
-  © Copyright  1995 - 2013 Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V.
-    All rights reserved.
-  1.    INTRODUCTION
-  The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software that implements
-  the MPEG Advanced Audio Coding ("AAC") encoding and decoding scheme for digital audio.
-  This FDK AAC Codec software is intended to be used on a wide variety of Android devices.
-  AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient general perceptual
-  audio codecs. AAC-ELD is considered the best-performing full-bandwidth communications codec by
-  independent studies and is widely deployed. AAC has been standardized by ISO and IEC as part
-  of the MPEG specifications.
-  Patent licenses for necessary patent claims for the FDK AAC Codec (including those of Fraunhofer)
-  may be obtained through Via Licensing (www.vialicensing.com) or through the respective patent owners
-  individually for the purpose of encoding or decoding bit streams in products that are compliant with
-  the ISO/IEC MPEG audio standards. Please note that most manufacturers of Android devices already license
-  these patent claims through Via Licensing or directly from the patent owners, and therefore FDK AAC Codec
-  software may already be covered under those patent licenses when it is used for those licensed purposes only.
-  Commercially-licensed AAC software libraries, including floating-point versions with enhanced sound quality,
-  are also available from Fraunhofer. Users are encouraged to check the Fraunhofer website for additional
-  applications information and documentation.
-  2.    COPYRIGHT LICENSE
-  Redistribution and use in source and binary forms, with or without modification, are permitted without
-  payment of copyright license fees provided that you satisfy the following conditions:
-  You must retain the complete text of this software license in redistributions of the FDK AAC Codec or
-  your modifications thereto in source code form.
-  You must retain the complete text of this software license in the documentation and/or other materials
-  provided with redistributions of the FDK AAC Codec or your modifications thereto in binary form.
-  You must make available free of charge copies of the complete source code of the FDK AAC Codec and your
-  modifications thereto to recipients of copies in binary form.
-  The name of Fraunhofer may not be used to endorse or promote products derived from this library without
-  prior written permission.
-  You may not charge copyright license fees for anyone to use, copy or distribute the FDK AAC Codec
-  software or your modifications thereto.
-  Your modified versions of the FDK AAC Codec must carry prominent notices stating that you changed the software
-  and the date of any change. For modified versions of the FDK AAC Codec, the term
-  "Fraunhofer FDK AAC Codec Library for Android" must be replaced by the term
-  "Third-Party Modified Version of the Fraunhofer FDK AAC Codec Library for Android."
-  3.    NO PATENT LICENSE
-  NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without limitation the patents of Fraunhofer,
-  ARE GRANTED BY THIS SOFTWARE LICENSE. Fraunhofer provides no warranty of patent non-infringement with
-  respect to this software.
-  You may use this FDK AAC Codec software or modifications thereto only for purposes that are authorized
-  by appropriate patent licenses.
-  4.    DISCLAIMER
-  This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright holders and contributors
-  "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, including but not limited to the implied warranties
-  of merchantability and fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
-  CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary, or consequential damages,
-  including but not limited to procurement of substitute goods or services; loss of use, data, or profits,
-  or business interruption, however caused and on any theory of liability, whether in contract, strict
-  liability, or tort (including negligence), arising in any way out of the use of this software, even if
-  advised of the possibility of such damage.
-  5.    CONTACT INFORMATION
-  Fraunhofer Institute for Integrated Circuits IIS
-  Attention: Audio and Multimedia Departments - FDK AAC LL
-  Am Wolfsmantel 33
-  91058 Erlangen, Germany
-  www.iis.fraunhofer.de/amm
-  amm-info@iis.fraunhofer.de
-
+  Copyright (c) 2010, Google Inc. All rights reserved.  Redistribution and use
+  in source and binary forms, with or without modification, are permitted
+  provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    * Neither the name of Google nor the names of its contributors may be used
+      to endorse or promote products derived from this software without specific
+      prior written permission.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+  HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  Additional IP Rights Grant (Patents) ------------------------------------
+  "These implementations" means the copyrightable works that implement the
+  WebM codecs distributed by Google as part of the WebM Project.  Google
+  hereby grants to you a perpetual, worldwide, non-exclusive, no-charge,
+  royalty-free, irrevocable (except as stated in this section) patent
+  license to make, have made, use, offer to sell, sell, import, transfer,
+  and otherwise run, modify and propagate the contents of these
+  implementations of WebM, where such license applies only to those patent
+  claims, both currently owned by Google and acquired in the future,
+  licensable by Google that are necessarily infringed by these
+  implementations of WebM. This grant does not include claims that would be
+  infringed only as a consequence of further modification of these
+  implementations. If you or your agent or exclusive licensee institute or
+  order or agree to the institution of patent litigation or any other patent
+  enforcement activity against any entity (including a cross-claim or
+  counterclaim in a lawsuit) alleging that any of these implementations of
+  WebM or any code incorporated within any of these implementations of WebM
+  constitute direct or contributory patent infringement, or inducement of
+  patent infringement, then any patent rights granted to you under this
+  License for these implementations of WebM shall terminate as of the date
+  such litigation is filed.
 
 
   openh264
diff --git a/cobalt/content/ssl/certs/5273a94c.0 b/cobalt/content/ssl/certs/5273a94c.0
deleted file mode 100644
index 9748599..0000000
--- a/cobalt/content/ssl/certs/5273a94c.0
+++ /dev/null
@@ -1,36 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV
-BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC
-aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV
-BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1
-Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz
-MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+
-BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp
-em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
-ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY
-B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH
-D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF
-Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo
-q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D
-k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH
-fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut
-dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM
-ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8
-zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
-rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX
-U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6
-Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5
-XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF
-Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR
-HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY
-GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c
-77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3
-+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK
-vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6
-FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl
-yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P
-AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD
-y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d
-NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==
------END CERTIFICATE-----
diff --git a/cobalt/csp/content_security_policy.cc b/cobalt/csp/content_security_policy.cc
index 8d53488..926ec1b 100644
--- a/cobalt/csp/content_security_policy.cc
+++ b/cobalt/csp/content_security_policy.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <memory>
-
 #include "cobalt/csp/content_security_policy.h"
 
+#include <memory>
+
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "cobalt/csp/directive_list.h"
@@ -85,7 +85,9 @@
   }
 
   HashAlgorithm valid_hash_algorithms[] = {
-      kHashAlgorithmSha256, kHashAlgorithmSha384, kHashAlgorithmSha512,
+      kHashAlgorithmSha256,
+      kHashAlgorithmSha384,
+      kHashAlgorithmSha512,
   };
 
   for (size_t i = 0; i < arraysize(valid_hash_algorithms); ++i) {
diff --git a/cobalt/demos/content/background-mode-demo/background-mode-demo.js b/cobalt/demos/content/background-mode-demo/background-mode-demo.js
index 2245eb4..d589a2b 100644
--- a/cobalt/demos/content/background-mode-demo/background-mode-demo.js
+++ b/cobalt/demos/content/background-mode-demo/background-mode-demo.js
@@ -13,9 +13,9 @@
 // limitations under the License.
 
 // The page simply plays an audio or a video stream in a loop, it can be used
-// in the following forms:
-//   background-mode-demo.html&type=video
-//   background-mode-demo.html&type=audio
+// by appending following queryable object to url path, e.g.
+//   http://0.0.0.0:8000/cobalt/demos/content/background-mode-demo?type=video
+//   http://0.0.0.0:8000/cobalt/demos/content/background-mode-demo?type=audio
 // If the stream is adaptive, it has to be fit in memory as this demo will
 // download the whole stream at once.
 
@@ -66,7 +66,7 @@
   mediasource.addEventListener('sourceopen', function () {
     if (type == 'audio') {
       var audio_source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
-	downloadAndAppend('../media-element-demo/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () {
+      downloadAndAppend('../media-element-demo/public/assets/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () {
         mediasource.endOfStream();
       });
     }
@@ -74,10 +74,10 @@
     if (type == 'video') {
       var video_source_buffer = mediasource.addSourceBuffer('video/mp4; codecs="avc1.640028"');
       var audio_source_buffer = mediasource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
-      downloadAndAppend('../media-element-demo/dash-video-1080p.mp4', 0, 15 * 1024 * 1024, video_source_buffer, function () {
+      downloadAndAppend('../media-element-demo/public/assets/dash-video-1080p.mp4', 0, 15 * 1024 * 1024, video_source_buffer, function () {
         video_source_buffer.abort();
            // Append the first two segments of the 240p video so we can see the transition.
-        downloadAndAppend('../media-element-demo/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () {
+        downloadAndAppend('../media-element-demo/public/assets/dash-audio.mp4', 0, kAdaptiveAudioChunkSize * 10, audio_source_buffer, function () {
           mediasource.endOfStream();
         });
       });
@@ -96,9 +96,9 @@
 function checkMediaType() {
   var get_parameters = window.location.search.substr(1).split('&');
   for (var param of get_parameters) {
-    splitted = param.split('=');
-    if (splitted[0] == 'type') {
-      type = splitted[1];
+    split = param.split('=');
+    if (split[0] == 'type') {
+      type = split[1];
     }
   }
 
diff --git a/cobalt/demos/content/eme-demo/eme-demo.js b/cobalt/demos/content/eme-demo/eme-demo.js
index 3a0f299..df0b5dc 100644
--- a/cobalt/demos/content/eme-demo/eme-demo.js
+++ b/cobalt/demos/content/eme-demo/eme-demo.js
@@ -49,6 +49,16 @@
 }).then(function(mediaKeys) {
   var videoElement = document.querySelector('video');
 
+  if (mediaKeys.getMetrics) {
+    console.log('Found getMetrics(), calling it ...');
+    try {
+      mediaKeys.getMetrics();
+      console.log('Calling getMetrics() succeeded.');
+    } catch(e) {
+      console.log('Calling getMetrics() failed.');
+    }
+  }
+
   videoElement.setMediaKeys(mediaKeys);
 
   mediaKeySession = mediaKeys.createSession();
diff --git a/cobalt/doc/lifecycle.md b/cobalt/doc/lifecycle.md
index 6de3346..2248908 100644
--- a/cobalt/doc/lifecycle.md
+++ b/cobalt/doc/lifecycle.md
@@ -84,7 +84,7 @@
 
 ### Deprecated `SbSystemRequest` functions.
 
-The `SbSytemRequest` functions are declared in `src/starboard/system.h`
+The `SbSystemRequest` functions are declared in `src/starboard/system.h`
 
 * The `SbSystemRequestPause` event is renamed to `SbSystemRequestBlur`
 * The `SbSystemRequestUnpause` event is renamed to `SbSystemRequestFocus`
diff --git a/cobalt/dom/dom_stat_tracker.cc b/cobalt/dom/dom_stat_tracker.cc
index 2846654..4fb57b9 100644
--- a/cobalt/dom/dom_stat_tracker.cc
+++ b/cobalt/dom/dom_stat_tracker.cc
@@ -20,7 +20,7 @@
 namespace dom {
 
 DomStatTracker::DomStatTracker(const std::string& name)
-    : web::StatTracker(name),
+    : web::StatTracker(name, "DOM"),
       count_html_element_(
           base::StringPrintf("Count.%s.DOM.HtmlElement", name.c_str()), 0,
           "Total number of HTML elements."),
diff --git a/cobalt/dom/html_element.cc b/cobalt/dom/html_element.cc
index 02dafb6..36ad437 100644
--- a/cobalt/dom/html_element.cc
+++ b/cobalt/dom/html_element.cc
@@ -580,6 +580,7 @@
 
   // 11. Scroll the element to x,scrollTop, with the scroll behavior being
   //     "auto".
+  node_document()->window()->CancelScroll(ui_nav_item_);
   float left, top;
   ui_nav_item_->GetContentOffset(&left, &top);
   ui_nav_item_->SetContentOffset(x, top);
@@ -633,6 +634,7 @@
 
   // 11. Scroll the element to scrollLeft,y, with the scroll behavior being
   //     "auto".
+  node_document()->window()->CancelScroll(ui_nav_item_);
   float left, top;
   ui_nav_item_->GetContentOffset(&left, &top);
   ui_nav_item_->SetContentOffset(left, y);
@@ -1221,7 +1223,7 @@
 void HTMLElement::OnUiNavScroll(SbTimeMonotonic /* time */) {
   Document* document = node_document();
   scoped_refptr<Window> window(document ? document->window() : nullptr);
-  DispatchEvent(new UIEvent(base::Tokens::scroll(), web::Event::kBubbles,
+  DispatchEvent(new UIEvent(base::Tokens::scroll(), web::Event::kNotBubbles,
                             web::Event::kNotCancelable, window));
 }
 
diff --git a/cobalt/dom/html_media_element.cc b/cobalt/dom/html_media_element.cc
index 80a57d6..d516ac8 100644
--- a/cobalt/dom/html_media_element.cc
+++ b/cobalt/dom/html_media_element.cc
@@ -821,8 +821,8 @@
                                     const std::string& key_system) {
   DLOG(INFO) << "HTMLMediaElement::LoadResource(" << initial_url << ", "
              << content_type << ", " << key_system;
-  DCHECK(player_);
   if (!player_) {
+    LOG(WARNING) << "LoadResource() without player.";
     return;
   }
 
diff --git a/cobalt/dom/html_script_element.cc b/cobalt/dom/html_script_element.cc
index 3634e62..1a1f7ba 100644
--- a/cobalt/dom/html_script_element.cc
+++ b/cobalt/dom/html_script_element.cc
@@ -341,7 +341,7 @@
           base::Bind(
               &loader::FetcherFactory::CreateSecureFetcher,
               base::Unretained(html_element_context()->fetcher_factory()), url_,
-              csp_callback, request_mode_,
+              /*main_resource=*/false, csp_callback, request_mode_,
               document_->location() ? document_->location()->GetOriginAsObject()
                                     : loader::Origin(),
               disk_cache::kUncompiledScript, net::HttpRequestHeaders(),
@@ -443,7 +443,9 @@
             &prevent_gc_until_error_event_dispatch_);
       }
     } break;
-    default: { NOTREACHED(); }
+    default: {
+      NOTREACHED();
+    }
   }
 }
 
diff --git a/cobalt/dom/media_settings.cc b/cobalt/dom/media_settings.cc
index 411889d..2915df3 100644
--- a/cobalt/dom/media_settings.cc
+++ b/cobalt/dom/media_settings.cc
@@ -53,6 +53,12 @@
       LOG(INFO) << name << ": set to " << value;
       return true;
     }
+  } else if (name == "MediaSource.EnableCallingEndedWhenClosed") {
+    if (value == 0 || value == 1) {
+      is_calling_ended_when_closed_enabled_ = value != 0;
+      LOG(INFO) << name << ": set to " << value;
+      return true;
+    }
   } else if (name == "MediaSource.MaxSizeForImmediateJob") {
     if (value >= 0) {
       max_size_for_immediate_job_ = value;
diff --git a/cobalt/dom/media_settings.h b/cobalt/dom/media_settings.h
index a6acb1c..eace022 100644
--- a/cobalt/dom/media_settings.h
+++ b/cobalt/dom/media_settings.h
@@ -35,6 +35,7 @@
       const = 0;
   virtual base::Optional<bool> IsAsynchronousReductionEnabled() const = 0;
   virtual base::Optional<bool> IsAvoidCopyingArrayBufferEnabled() const = 0;
+  virtual base::Optional<bool> IsCallingEndedWhenClosedEnabled() const = 0;
   virtual base::Optional<int> GetMaxSizeForImmediateJob() const = 0;
   virtual base::Optional<int> GetMaxSourceBufferAppendSizeInBytes() const = 0;
 
@@ -71,6 +72,10 @@
     base::AutoLock auto_lock(lock_);
     return is_avoid_copying_array_buffer_enabled_;
   }
+  base::Optional<bool> IsCallingEndedWhenClosedEnabled() const override {
+    base::AutoLock auto_lock(lock_);
+    return is_calling_ended_when_closed_enabled_;
+  }
   base::Optional<int> GetMaxSizeForImmediateJob() const override {
     base::AutoLock auto_lock(lock_);
     return max_size_for_immediate_job_;
@@ -96,6 +101,7 @@
   base::Optional<int> minimum_processor_count_to_offload_algorithm_;
   base::Optional<bool> is_asynchronous_reduction_enabled_;
   base::Optional<bool> is_avoid_copying_array_buffer_enabled_;
+  base::Optional<bool> is_calling_ended_when_closed_enabled_;
   base::Optional<int> max_size_for_immediate_job_;
   base::Optional<int> max_source_buffer_append_size_in_bytes_;
 
diff --git a/cobalt/dom/media_settings_test.cc b/cobalt/dom/media_settings_test.cc
index 9b10847..8850f72 100644
--- a/cobalt/dom/media_settings_test.cc
+++ b/cobalt/dom/media_settings_test.cc
@@ -27,6 +27,7 @@
   EXPECT_FALSE(impl.GetMinimumProcessorCountToOffloadAlgorithm());
   EXPECT_FALSE(impl.IsAsynchronousReductionEnabled());
   EXPECT_FALSE(impl.IsAvoidCopyingArrayBufferEnabled());
+  EXPECT_FALSE(impl.IsCallingEndedWhenClosedEnabled());
   EXPECT_FALSE(impl.GetMaxSizeForImmediateJob());
   EXPECT_FALSE(impl.GetMaxSourceBufferAppendSizeInBytes());
   EXPECT_FALSE(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds());
@@ -40,6 +41,7 @@
       impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 101));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 1));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAvoidCopyingArrayBuffer", 1));
+  ASSERT_TRUE(impl.Set("MediaSource.EnableCallingEndedWhenClosed", 1));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSizeForImmediateJob", 103));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 100000));
   ASSERT_TRUE(
@@ -49,6 +51,7 @@
   EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 101);
   EXPECT_TRUE(impl.IsAsynchronousReductionEnabled().value());
   EXPECT_TRUE(impl.IsAvoidCopyingArrayBufferEnabled().value());
+  EXPECT_TRUE(impl.IsCallingEndedWhenClosedEnabled().value());
   EXPECT_EQ(impl.GetMaxSizeForImmediateJob().value(), 103);
   EXPECT_EQ(impl.GetMaxSourceBufferAppendSizeInBytes().value(), 100000);
   EXPECT_EQ(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds().value(),
@@ -63,6 +66,7 @@
       impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", -101));
   ASSERT_FALSE(impl.Set("MediaSource.EnableAsynchronousReduction", 2));
   ASSERT_FALSE(impl.Set("MediaSource.EnableAvoidCopyingArrayBuffer", 2));
+  ASSERT_FALSE(impl.Set("MediaSource.EnableCallingEndedWhenClosed", 2));
   ASSERT_FALSE(impl.Set("MediaSource.MaxSizeForImmediateJob", -103));
   ASSERT_FALSE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 0));
   ASSERT_FALSE(
@@ -72,6 +76,7 @@
   EXPECT_FALSE(impl.GetMinimumProcessorCountToOffloadAlgorithm());
   EXPECT_FALSE(impl.IsAsynchronousReductionEnabled());
   EXPECT_FALSE(impl.IsAvoidCopyingArrayBufferEnabled());
+  EXPECT_FALSE(impl.IsCallingEndedWhenClosedEnabled());
   EXPECT_FALSE(impl.GetMaxSizeForImmediateJob());
   EXPECT_FALSE(impl.GetMaxSourceBufferAppendSizeInBytes());
   EXPECT_FALSE(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds());
@@ -85,6 +90,7 @@
       impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 0));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 0));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAvoidCopyingArrayBuffer", 0));
+  ASSERT_TRUE(impl.Set("MediaSource.EnableCallingEndedWhenClosed", 0));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSizeForImmediateJob", 0));
   // O is an invalid value for "MediaSource.MaxSourceBufferAppendSizeInBytes".
   // O is an invalid value for
@@ -94,6 +100,7 @@
   EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 0);
   EXPECT_FALSE(impl.IsAsynchronousReductionEnabled().value());
   EXPECT_FALSE(impl.IsAvoidCopyingArrayBufferEnabled().value());
+  EXPECT_FALSE(impl.IsCallingEndedWhenClosedEnabled().value());
   EXPECT_EQ(impl.GetMaxSizeForImmediateJob().value(), 0);
 }
 
@@ -105,6 +112,7 @@
       impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 0));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 0));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAvoidCopyingArrayBuffer", 0));
+  ASSERT_TRUE(impl.Set("MediaSource.EnableCallingEndedWhenClosed", 0));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSizeForImmediateJob", 0));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 1));
   ASSERT_TRUE(
@@ -115,6 +123,7 @@
       impl.Set("MediaSource.MinimumProcessorCountToOffloadAlgorithm", 1));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAsynchronousReduction", 1));
   ASSERT_TRUE(impl.Set("MediaSource.EnableAvoidCopyingArrayBuffer", 1));
+  ASSERT_TRUE(impl.Set("MediaSource.EnableCallingEndedWhenClosed", 1));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSizeForImmediateJob", 1));
   ASSERT_TRUE(impl.Set("MediaSource.MaxSourceBufferAppendSizeInBytes", 2));
   ASSERT_TRUE(
@@ -124,6 +133,7 @@
   EXPECT_EQ(impl.GetMinimumProcessorCountToOffloadAlgorithm().value(), 1);
   EXPECT_TRUE(impl.IsAsynchronousReductionEnabled().value());
   EXPECT_TRUE(impl.IsAvoidCopyingArrayBufferEnabled().value());
+  EXPECT_TRUE(impl.IsCallingEndedWhenClosedEnabled().value());
   EXPECT_EQ(impl.GetMaxSizeForImmediateJob().value(), 1);
   EXPECT_EQ(impl.GetMaxSourceBufferAppendSizeInBytes().value(), 2);
   EXPECT_EQ(impl.GetMediaElementTimeupdateEventIntervalInMilliseconds().value(),
diff --git a/cobalt/dom/media_source.cc b/cobalt/dom/media_source.cc
index e3e5223..8871b83 100644
--- a/cobalt/dom/media_source.cc
+++ b/cobalt/dom/media_source.cc
@@ -107,6 +107,15 @@
       false);
 }
 
+// If this function returns true, MediaSource::EndOfStreamAlgorithm() will call
+// SetReadyState(kMediaSourceReadyStateEnded) even if MediaSource object is
+// closed.
+// The default value is false.
+bool IsCallingEndedWhenClosedEnabled(web::EnvironmentSettings* settings) {
+  return GetMediaSettings(settings).IsCallingEndedWhenClosedEnabled().value_or(
+      false);
+}
+
 // If the size of a job that is part of an algorithm is less than or equal to
 // the return value of this function, the implementation will run the job
 // immediately instead of scheduling it to run later to reduce latency.
@@ -289,7 +298,23 @@
 }
 
 void MediaSource::EndOfStreamAlgorithm(MediaSourceEndOfStreamError error) {
-  SetReadyState(kMediaSourceReadyStateEnded);
+  if (IsClosed()) {
+    if (IsCallingEndedWhenClosedEnabled(environment_settings())) {
+      LOG(INFO) << "Setting state to ended when MediaSource object is closed";
+      // Calling the function below here leads to ANR in production, as
+      // EndOfStreamAlgorithm() can be called by SetReadyState().
+      // Calling SetReadyState() nestedly leads to re-entrance of Abort() on
+      // the SourceBuffer algorithm handle, where a mutex gets re-acquired.
+      // Keep this code path here so we have the option to revert it to the
+      // original behavior in production.
+      SetReadyState(kMediaSourceReadyStateEnded);
+    } else {
+      LOG(INFO)
+          << "Skip setting state to ended when MediaSource object is closed";
+    }
+  } else {
+    SetReadyState(kMediaSourceReadyStateEnded);
+  }
 
   PipelineStatus pipeline_status = PIPELINE_OK;
 
diff --git a/cobalt/dom/navigator_licenses_test.cc b/cobalt/dom/navigator_licenses_test.cc
index fade4a7..e5277aa 100644
--- a/cobalt/dom/navigator_licenses_test.cc
+++ b/cobalt/dom/navigator_licenses_test.cc
@@ -23,10 +23,11 @@
 // Tests the Navigator::licenses function for non-empty return.
 TEST(NavigatorLicensesTest, NonEmpty) {
   std::unique_ptr<web::Context> web_context(new web::testing::StubWebContext());
-  web_context->setup_environment_settings(
+  web_context->SetupEnvironmentSettings(
       new dom::testing::StubEnvironmentSettings());
   scoped_refptr<cobalt::dom::Navigator> navigator =
       new cobalt::dom::Navigator(web_context->environment_settings(), nullptr);
+  web_context->SetupFinished();
 
   ASSERT_TRUE(navigator != nullptr);
   EXPECT_FALSE(navigator->licenses().empty());
diff --git a/cobalt/dom/pointer_state.cc b/cobalt/dom/pointer_state.cc
index 619fadf..79f7974 100644
--- a/cobalt/dom/pointer_state.cc
+++ b/cobalt/dom/pointer_state.cc
@@ -15,6 +15,7 @@
 #include "cobalt/dom/pointer_state.h"
 
 #include <algorithm>
+#include <memory>
 #include <utility>
 
 #include "base/trace_event/trace_event.h"
@@ -297,6 +298,43 @@
   client_time_stamps_.erase(pointer_id);
 }
 
+void PointerState::SetPossibleScrollTargets(
+    int32_t pointer_id,
+    std::unique_ptr<PossibleScrollTargets> possible_scroll_targets) {
+  client_possible_scroll_targets_[pointer_id] =
+      std::move(possible_scroll_targets);
+}
+PossibleScrollTargets* PointerState::GetPossibleScrollTargets(
+    int32_t pointer_id) {
+  auto possible_scroll_targets =
+      client_possible_scroll_targets_.find(pointer_id);
+  if (possible_scroll_targets != client_possible_scroll_targets_.end()) {
+    return possible_scroll_targets->second.get();
+  }
+  return nullptr;
+}
+void PointerState::ClearPossibleScrollTargets(int32_t pointer_id) {
+  client_possible_scroll_targets_.erase(pointer_id);
+}
+
+void PointerState::SetClientTransformMatrix(int32_t pointer_id,
+                                            const math::Matrix3F& matrix) {
+  client_matrices_.emplace(pointer_id, matrix);
+}
+
+const math::Matrix3F& PointerState::GetClientTransformMatrix(
+    int32_t pointer_id) {
+  auto matrix_entry = client_matrices_.find(pointer_id);
+  if (matrix_entry != client_matrices_.end()) {
+    return matrix_entry->second;
+  }
+  return identity_matrix_;
+}
+
+void PointerState::ClearMatrix(int32_t pointer_id) {
+  client_matrices_.erase(pointer_id);
+}
+
 void PointerState::SetWasCancelled(int32_t pointer_id) {
   client_cancellations_.insert(pointer_id);
 }
diff --git a/cobalt/dom/pointer_state.h b/cobalt/dom/pointer_state.h
index 5552f9d..1c3e5a2 100644
--- a/cobalt/dom/pointer_state.h
+++ b/cobalt/dom/pointer_state.h
@@ -16,6 +16,7 @@
 #define COBALT_DOM_POINTER_STATE_H_
 
 #include <map>
+#include <memory>
 #include <queue>
 #include <set>
 
@@ -24,6 +25,7 @@
 #include "base/memory/weak_ptr.h"
 #include "cobalt/dom/html_element.h"
 #include "cobalt/dom/pointer_event_init.h"
+#include "cobalt/math/matrix3_f.h"
 #include "cobalt/math/vector2d_f.h"
 #include "cobalt/web/dom_exception.h"
 #include "cobalt/web/event.h"
@@ -31,6 +33,13 @@
 namespace cobalt {
 namespace dom {
 
+struct PossibleScrollTargets {
+  scoped_refptr<dom::HTMLElement> up;
+  scoped_refptr<dom::HTMLElement> down;
+  scoped_refptr<dom::HTMLElement> left;
+  scoped_refptr<dom::HTMLElement> right;
+};
+
 // This class contains various state related to pointer and mouse support.
 class PointerState {
  public:
@@ -85,6 +94,17 @@
   base::Optional<uint64> GetClientTimeStamp(int32_t pointer_id);
   void ClearTimeStamp(int32_t pointer_id);
 
+  void SetPossibleScrollTargets(
+      int32_t pointer_id,
+      std::unique_ptr<PossibleScrollTargets> possible_scroll_targets);
+  PossibleScrollTargets* GetPossibleScrollTargets(int32_t pointer_id);
+  void ClearPossibleScrollTargets(int32_t pointer_id);
+
+  void SetClientTransformMatrix(int32_t pointer_id,
+                                const math::Matrix3F& matrix);
+  const math::Matrix3F& GetClientTransformMatrix(int32_t pointer_id);
+  void ClearMatrix(int32_t pointer_id);
+
   // Tracks whether a certain pointer was cancelled, i.e. if it panned the
   // page viewport.
   // https://www.w3.org/TR/pointerevents1/#the-pointercancel-event
@@ -96,12 +116,12 @@
 
  private:
   // Stores pointer events until they are handled after a layout.
-  std::queue<scoped_refptr<web::Event> > pointer_events_;
+  std::queue<scoped_refptr<web::Event>> pointer_events_;
 
   // This stores the elements with target overrides
   //   https://www.w3.org/TR/2015/REC-pointerevents-20150224/#pointer-capture
-  std::map<int32_t, base::WeakPtr<Element> > target_override_;
-  std::map<int32_t, base::WeakPtr<Element> > pending_target_override_;
+  std::map<int32_t, base::WeakPtr<Element>> target_override_;
+  std::map<int32_t, base::WeakPtr<Element>> pending_target_override_;
 
   // Store the set of active pointers.
   //   https://www.w3.org/TR/2015/REC-pointerevents-20150224/#dfn-active-pointer
@@ -113,7 +133,12 @@
 
   std::map<int32_t, math::Vector2dF> client_coordinates_;
   std::map<int32_t, uint64> client_time_stamps_;
+  std::map<int32_t, std::unique_ptr<PossibleScrollTargets>>
+      client_possible_scroll_targets_;
+  std::map<int32_t, const math::Matrix3F> client_matrices_;
   std::set<int32_t> client_cancellations_;
+
+  const math::Matrix3F identity_matrix_ = math::Matrix3F::Identity();
 };
 
 }  // namespace dom
diff --git a/cobalt/dom/source_buffer_algorithm.cc b/cobalt/dom/source_buffer_algorithm.cc
index a24e51c..b55e9cd 100644
--- a/cobalt/dom/source_buffer_algorithm.cc
+++ b/cobalt/dom/source_buffer_algorithm.cc
@@ -101,6 +101,7 @@
 void SourceBufferAppendAlgorithm::Finalize() {
   TRACE_EVENT1("cobalt::dom", "SourceBufferAppendAlgorithm::Finalize()",
                "succeeded", succeeded_);
+
   if (succeeded_) {
     schedule_event_cb_.Run(base::Tokens::update());
     schedule_event_cb_.Run(base::Tokens::updateend());
@@ -143,6 +144,7 @@
 
 void SourceBufferRemoveAlgorithm::Finalize() {
   TRACE_EVENT0("cobalt::dom", "SourceBufferRemoveAlgorithm::Finalize()");
+
   schedule_event_cb_.Run(base::Tokens::update());
   schedule_event_cb_.Run(base::Tokens::updateend());
   std::move(finalized_cb_).Run();
diff --git a/cobalt/dom/testing/fake_document.h b/cobalt/dom/testing/fake_document.h
index 494da4e..429481f 100644
--- a/cobalt/dom/testing/fake_document.h
+++ b/cobalt/dom/testing/fake_document.h
@@ -19,7 +19,6 @@
 #include <utility>
 
 #include "cobalt/dom/document.h"
-
 #include "cobalt/web/csp_delegate_factory.h"
 
 namespace cobalt {
@@ -29,30 +28,14 @@
 class FakeDocument : public dom::Document {
  public:
   explicit FakeDocument(dom::HTMLElementContext* html_element_context)
-      : dom::Document(html_element_context) {
-    web::WindowOrWorkerGlobalScope::Options options(
-        base::ApplicationState::kApplicationStateStarted);
-    std::unique_ptr<web::CspViolationReporter> violation_reporter(
-        new web::CspViolationReporter(nullptr, options.post_sender));
-    csp_delegate_ = web::CspDelegateFactory::GetInstance()->Create(
-        options.csp_enforcement_mode, std::move(violation_reporter),
-        environment_settings()->creation_url(), options.require_csp,
-        options.csp_policy_changed_callback,
-        options.csp_insecure_allowed_token);
-  }
+      : FakeDocument(html_element_context, dom::Document::Options()) {}
 
   FakeDocument(dom::HTMLElementContext* html_element_context,
-               dom::Document::Options doc_options)
+               const dom::Document::Options& doc_options)
       : dom::Document(html_element_context, doc_options) {
-    web::WindowOrWorkerGlobalScope::Options options(
-        base::ApplicationState::kApplicationStateStarted);
-    std::unique_ptr<web::CspViolationReporter> violation_reporter(
-        new web::CspViolationReporter(nullptr, options.post_sender));
-    csp_delegate_ = web::CspDelegateFactory::GetInstance()->Create(
-        options.csp_enforcement_mode, std::move(violation_reporter),
-        environment_settings()->creation_url(), options.require_csp,
-        options.csp_policy_changed_callback,
-        options.csp_insecure_allowed_token);
+    web::WindowOrWorkerGlobalScope::Options options;
+    csp_delegate_ =
+        web::CspDelegateFactory::Create(nullptr, options.csp_options);
   }
 
   web::CspDelegate* GetCSPDelegate() const override {
diff --git a/cobalt/dom/testing/stub_window.h b/cobalt/dom/testing/stub_window.h
index 34a2d94..41f6bf1 100644
--- a/cobalt/dom/testing/stub_window.h
+++ b/cobalt/dom/testing/stub_window.h
@@ -28,6 +28,7 @@
 #include "cobalt/cssom/viewport_size.h"
 #include "cobalt/dom/captions/system_caption_settings.h"
 #include "cobalt/dom/dom_settings.h"
+#include "cobalt/dom/dom_stat_tracker.h"
 #include "cobalt/dom/local_storage_database.h"
 #include "cobalt/dom/testing/stub_environment_settings.h"
 #include "cobalt/dom/window.h"
@@ -107,6 +108,8 @@
     dom_parser_.reset(
         new dom_parser::Parser(base::Bind(&StubLoadCompleteCallback)));
     dom_stat_tracker_.reset(new dom::DomStatTracker("StubWindow"));
+    web::CspDelegate::Options csp_options;
+    csp_options.header_policy = csp::kCSPOptional;
     window_ = new dom::Window(
         web_context()->environment_settings(), cssom::ViewportSize(1920, 1080),
         base::kApplicationStateStarted, css_parser_.get(), dom_parser_.get(),
@@ -115,15 +118,14 @@
         nullptr, nullptr, nullptr, nullptr,
         web_context()->global_environment()->script_value_factory(), nullptr,
         dom_stat_tracker_.get(), "en", base::Callback<void(const GURL&)>(),
-        base::Bind(&StubLoadCompleteCallback), nullptr,
-        network_bridge::PostSender(), csp::kCSPOptional,
-        web::kCspEnforcementEnable, base::Closure() /* csp_policy_changed */,
-        base::Closure() /* ran_animation_frame_callbacks */,
+        base::Bind(&StubLoadCompleteCallback), nullptr /* cookie_jar */,
+        csp_options, base::Closure() /* ran_animation_frame_callbacks */,
         dom::Window::CloseCallback() /* window_close */,
         base::Closure() /* window_minimize */, on_screen_keyboard_bridge_,
         nullptr /* camera_3d */, dom::Window::OnStartDispatchEventCallback(),
         dom::Window::OnStopDispatchEventCallback(),
         dom::ScreenshotManager::ProvideScreenshotFunctionCallback(),
+        dom::Window::NavItemCallback(),
         nullptr /* synchronous_loader_interrupt */,
         false /* enable_inline_script_warnings */, nullptr /* ui_nav_root */,
         true /* enable_map_to_mesh */, 0 /* csp_insecure_allowed_token */,
@@ -131,9 +133,10 @@
         dom::Window::kClockTypeSystemTime /* clock_type */,
         dom::Window::CacheCallback() /* splash_screen_cache_callback */,
         system_caption_settings_ /* captions */
-        );
+    );
     global_environment()->CreateGlobalObject(
         window_, web_context()->environment_settings());
+    web_context()->SetupFinished();
   }
 
  private:
@@ -142,7 +145,7 @@
 
   void InitializeWebContext() {
     web_context_.reset(new web::testing::StubWebContext());
-    web_context()->setup_environment_settings(
+    web_context()->SetupEnvironmentSettings(
         new dom::testing::StubEnvironmentSettings(options_));
     web_context()->environment_settings()->set_creation_url(
         GURL("about:blank"));
diff --git a/cobalt/dom/window.cc b/cobalt/dom/window.cc
index c5d5ac0..92fe236 100644
--- a/cobalt/dom/window.cc
+++ b/cobalt/dom/window.cc
@@ -107,10 +107,7 @@
     const base::Callback<void(const GURL&)> navigation_callback,
     const loader::Decoder::OnCompleteFunction& load_complete_callback,
     network_bridge::CookieJar* cookie_jar,
-    const network_bridge::PostSender& post_sender,
-    csp::CSPHeaderPolicy require_csp,
-    web::CspEnforcementType csp_enforcement_mode,
-    const base::Closure& csp_policy_changed_callback,
+    const web::CspDelegate::Options& csp_options,
     const base::Closure& ran_animation_frame_callbacks_callback,
     CloseCallback window_close_callback, base::Closure window_minimize_callback,
     OnScreenKeyboardBridge* on_screen_keyboard_bridge,
@@ -119,6 +116,7 @@
     const OnStopDispatchEventCallback& on_stop_dispatch_event_callback,
     const ScreenshotManager::ProvideScreenshotFunctionCallback&
         screenshot_function_callback,
+    const NavItemCallback& cancel_scroll_callback,
     base::WaitableEvent* synchronous_loader_interrupt,
     bool enable_inline_script_warnings,
     const scoped_refptr<ui_navigation::NavItem>& ui_nav_root,
@@ -130,11 +128,9 @@
     // 'window' object EventTargets require special handling for onerror events,
     // see EventTarget constructor for more details.
     : web::WindowOrWorkerGlobalScope(
-          settings, dom_stat_tracker,
+          settings,
           web::WindowOrWorkerGlobalScope::Options(
-              initial_application_state, post_sender, require_csp,
-              csp_enforcement_mode, csp_policy_changed_callback,
-              csp_insecure_allowed_token)),
+              initial_application_state, csp_options, dom_stat_tracker)),
       viewport_size_(view_size),
       is_resize_event_pending_(false),
       is_reporting_script_error_(false),
@@ -178,6 +174,7 @@
                                                      script_value_factory)
                               : NULL),
       splash_screen_cache_callback_(splash_screen_cache_callback),
+      cancel_scroll_callback_(cancel_scroll_callback),
       on_start_dispatch_event_callback_(on_start_dispatch_event_callback),
       on_stop_dispatch_event_callback_(on_stop_dispatch_event_callback),
       screenshot_manager_(settings, screenshot_function_callback),
@@ -213,7 +210,8 @@
     const loader::Decoder::OnCompleteFunction& load_complete_callback) {
   document_loader_.reset(new loader::Loader(
       base::Bind(&loader::FetcherFactory::CreateFetcher,
-                 base::Unretained(fetcher_factory), url, disk_cache::kHTML),
+                 base::Unretained(fetcher_factory), url, /*main_resource=*/true,
+                 disk_cache::kHTML),
       base::Bind(&Parser::ParseDocumentAsync, base::Unretained(dom_parser),
                  document_, base::SourceLocation(url.spec(), 1, 1)),
       load_complete_callback));
@@ -669,6 +667,14 @@
   splash_screen_cache_callback_.Run(content, topic);
 }
 
+void Window::CancelScroll(
+    const scoped_refptr<ui_navigation::NavItem>& nav_item) {
+  if (cancel_scroll_callback_.is_null()) {
+    return;
+  }
+  cancel_scroll_callback_.Run(nav_item);
+}
+
 const scoped_refptr<OnScreenKeyboard>& Window::on_screen_keyboard() const {
   return on_screen_keyboard_;
 }
diff --git a/cobalt/dom/window.h b/cobalt/dom/window.h
index 73688a1..def676b 100644
--- a/cobalt/dom/window.h
+++ b/cobalt/dom/window.h
@@ -123,6 +123,9 @@
   typedef base::Callback<void(const std::string&,
                               const base::Optional<std::string>&)>
       CacheCallback;
+  typedef base::Callback<void(
+      const scoped_refptr<ui_navigation::NavItem>& nav_item)>
+      NavItemCallback;
 
   enum ClockType {
     kClockTypeTestRunner,
@@ -154,10 +157,7 @@
       const base::Callback<void(const GURL&)> navigation_callback,
       const loader::Decoder::OnCompleteFunction& load_complete_callback,
       network_bridge::CookieJar* cookie_jar,
-      const network_bridge::PostSender& post_sender,
-      csp::CSPHeaderPolicy require_csp,
-      web::CspEnforcementType csp_enforcement_mode,
-      const base::Closure& csp_policy_changed_callback,
+      const web::CspDelegate::Options& csp_options,
       const base::Closure& ran_animation_frame_callbacks_callback,
       CloseCallback window_close_callback,
       base::Closure window_minimize_callback,
@@ -168,6 +168,7 @@
       const OnStopDispatchEventCallback& stop_tracking_dispatch_event_callback,
       const ScreenshotManager::ProvideScreenshotFunctionCallback&
           screenshot_function_callback,
+      const NavItemCallback& cancel_scroll_callback,
       base::WaitableEvent* synchronous_loader_interrupt,
       bool enable_inline_script_warnings = false,
       const scoped_refptr<ui_navigation::NavItem>& ui_nav_root = nullptr,
@@ -359,6 +360,8 @@
   void CacheSplashScreen(const std::string& content,
                          const base::Optional<std::string>& topic);
 
+  void CancelScroll(const scoped_refptr<ui_navigation::NavItem>& nav_item);
+
   // Custom on screen keyboard.
   const scoped_refptr<OnScreenKeyboard>& on_screen_keyboard() const;
   void ReleaseOnScreenKeyboard();
@@ -445,6 +448,8 @@
 
   CacheCallback splash_screen_cache_callback_;
 
+  NavItemCallback cancel_scroll_callback_;
+
   OnStartDispatchEventCallback on_start_dispatch_event_callback_;
   OnStopDispatchEventCallback on_stop_dispatch_event_callback_;
 
diff --git a/cobalt/dom_parser/html_decoder.cc b/cobalt/dom_parser/html_decoder.cc
index 01267f3..1e3bc18 100644
--- a/cobalt/dom_parser/html_decoder.cc
+++ b/cobalt/dom_parser/html_decoder.cc
@@ -28,12 +28,12 @@
     const scoped_refptr<dom::Node>& reference_node,
     const int dom_max_element_depth, const base::SourceLocation& input_location,
     const loader::Decoder::OnCompleteFunction& load_complete_callback,
-    const bool should_run_scripts, const csp::CSPHeaderPolicy require_csp)
+    const bool should_run_scripts, const csp::CSPHeaderPolicy csp_header_policy)
     : libxml_html_parser_wrapper_(new LibxmlHTMLParserWrapper(
           document, parent_node, reference_node, dom_max_element_depth,
           input_location, load_complete_callback, should_run_scripts)),
       document_(document),
-      require_csp_(require_csp),
+      csp_header_policy_(csp_header_policy),
       load_complete_callback_(load_complete_callback) {}
 
 HTMLDecoder::~HTMLDecoder() {}
@@ -61,7 +61,7 @@
 
   csp::ResponseHeaders csp_headers(headers);
   if (document_->GetCSPDelegate()->OnReceiveHeaders(csp_headers) ||
-      require_csp_ == csp::kCSPOptional) {
+      csp_header_policy_ == csp::kCSPOptional) {
     return loader::kLoadResponseContinue;
   } else {
     LOG(ERROR) << "Failure receiving Content Security Policy headers "
diff --git a/cobalt/dom_parser/html_decoder.h b/cobalt/dom_parser/html_decoder.h
index ecc5cd7..b6de892 100644
--- a/cobalt/dom_parser/html_decoder.h
+++ b/cobalt/dom_parser/html_decoder.h
@@ -49,7 +49,7 @@
               const base::SourceLocation& input_location,
               const loader::Decoder::OnCompleteFunction& load_complete_callback,
               const bool should_run_scripts,
-              const csp::CSPHeaderPolicy require_csp);
+              const csp::CSPHeaderPolicy csp_header_policy);
 
   ~HTMLDecoder();
 
@@ -73,7 +73,7 @@
   THREAD_CHECKER(thread_checker_);
 
   // If Cobalt user forbids rendering Cobalt without csp headers.
-  const csp::CSPHeaderPolicy require_csp_;
+  const csp::CSPHeaderPolicy csp_header_policy_;
 
   const loader::Decoder::OnCompleteFunction load_complete_callback_;
 
diff --git a/cobalt/dom_parser/parser.cc b/cobalt/dom_parser/parser.cc
index 060886a..72f17b9 100644
--- a/cobalt/dom_parser/parser.cc
+++ b/cobalt/dom_parser/parser.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <memory>
-
 #include "cobalt/dom_parser/parser.h"
 
+#include <memory>
+
 #include "base/logging.h"
 #include "cobalt/dom/document.h"
 #include "cobalt/dom/xml_document.h"
@@ -33,7 +33,7 @@
       new dom::Document(html_element_context);
   HTMLDecoder html_decoder(document, document, NULL, dom_max_element_depth_,
                            input_location, load_complete_callback_, false,
-                           require_csp_);
+                           csp_header_policy_);
   html_decoder.DecodeChunk(input.c_str(), input.length());
   html_decoder.Finish();
   return document;
@@ -60,7 +60,7 @@
     const base::SourceLocation& input_location) {
   HTMLDecoder html_decoder(document, parent_node, reference_node,
                            dom_max_element_depth_, input_location,
-                           load_complete_callback_, false, require_csp_);
+                           load_complete_callback_, false, csp_header_policy_);
   html_decoder.DecodeChunk(input.c_str(), input.length());
   html_decoder.Finish();
 }
@@ -85,7 +85,7 @@
     const loader::Decoder::OnCompleteFunction& load_complete_callback) {
   return std::unique_ptr<loader::Decoder>(new HTMLDecoder(
       document, document, NULL, dom_max_element_depth_, input_location,
-      load_complete_callback, true, require_csp_));
+      load_complete_callback, true, csp_header_policy_));
 }
 
 std::unique_ptr<loader::Decoder> Parser::ParseXMLDocumentAsync(
diff --git a/cobalt/dom_parser/parser.h b/cobalt/dom_parser/parser.h
index e6527fb..637828b 100644
--- a/cobalt/dom_parser/parser.h
+++ b/cobalt/dom_parser/parser.h
@@ -34,18 +34,18 @@
       : dom_max_element_depth_(kDefaultDOMMaxElementDepth),
         ALLOW_THIS_IN_INITIALIZER_LIST(load_complete_callback_(
             base::Bind(&Parser::LoadCompleteCallback, base::Unretained(this)))),
-        require_csp_(csp::kCSPRequired) {}
+        csp_header_policy_(csp::kCSPRequired) {}
   explicit Parser(
       const loader::Decoder::OnCompleteFunction& load_complete_callback)
       : dom_max_element_depth_(kDefaultDOMMaxElementDepth),
         load_complete_callback_(load_complete_callback),
-        require_csp_(csp::kCSPRequired) {}
+        csp_header_policy_(csp::kCSPRequired) {}
   Parser(const int dom_max_element_depth,
          const loader::Decoder::OnCompleteFunction& load_complete_callback,
-         csp::CSPHeaderPolicy require_csp)
+         csp::CSPHeaderPolicy csp_header_policy)
       : dom_max_element_depth_(dom_max_element_depth),
         load_complete_callback_(load_complete_callback),
-        require_csp_(require_csp) {}
+        csp_header_policy_(csp_header_policy) {}
   ~Parser() override {}
 
   // From dom::Parser.
@@ -91,7 +91,7 @@
 
   // Cobalt user can specify if they want to forbid Cobalt rendering without csp
   // headers.
-  csp::CSPHeaderPolicy require_csp_;
+  csp::CSPHeaderPolicy csp_header_policy_;
 
   DISALLOW_COPY_AND_ASSIGN(Parser);
 };
diff --git a/cobalt/fetch/embedded_scripts/fetch.js b/cobalt/fetch/embedded_scripts/fetch.js
index 87435e2..c181f0d 100644
--- a/cobalt/fetch/embedded_scripts/fetch.js
+++ b/cobalt/fetch/embedded_scripts/fetch.js
@@ -11,7 +11,7 @@
 d.split(":");if(d=l.shift().trim())l=l.join(":").trim(),c.append(d,l)});return c}function u(a,b){b||={};this[Q]="default";this[y]="status"in b?b.status:200;if(200>this[y]||599<this[y])throw new ba("Invalid response status");this[ca]=200<=this[y]&&300>this[y];if("statusText"in b){var c=b.statusText;for(var d=0,l=c.length,f;d<l;d++)if(f=c.charCodeAt(d),9!==f&&(32>f||255<f||127===f))throw e("Invalid response status text");}else c="OK";this[R]=c;this[x]=L(b.headers,S);this[C]=b.url||"";if(a&&-1<da.indexOf(this[y]))throw new e("Response body is not allowed with a null body status");
 this[E]=b.is_aborted||!1;this._initBody(a)}if(!h.fetch){var K=h.Array,aa=h.ArrayBuffer,qa=h.Object.create,W=h.Object.defineProperties,k=h.Symbol,Ba=k.iterator,P=h.Map,ba=h.RangeError,e=h.TypeError,v=h.Uint8Array,z=h.Promise,V=h.ReadableStream,ea=h.ReadableStreamTee,ta=h.IsReadableStreamDisturbed,ra=h.IsReadableStreamLocked,r=k("body"),U=k("bodyUsed"),G=k("cache"),H=k("credentials"),A=k("guardCallback"),x=k("headers"),I=k("integrity"),p=k("map"),D=k("method"),t=k("mode"),ca=k("ok"),N=k("redirect"),
 y=k("status"),R=k("statusText"),Q=k("type"),C=k("url"),E=k("is_aborted"),F=k("signal"),la="accept-charset accept-encoding access-control-request-headers access-control-request-method connection content-length cookie cookie2 date dnt expect host keep-alive origin referer te trailer transfer-encoding upgrade via".split(" "),pa=["set-cookie","set-cookie2"],na=["accept","accept-language","content-language"],oa=["application/x-www-form-urlencoded","multipart/form-data","text/plain"],ua="default no-store reload no-cache force-cache only-if-cached".split(" "),
-va=["omit","same-origin","include"],wa="DELETE GET HEAD OPTIONS POST PUT".split(" "),ya=["GET","HEAD","POST"],xa=["same-origin","no-cors","cors"],za=["follow","error","manual"],da=[101,204,205,304],Ca=[301,302,303,307,308],Da="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";"),sa=aa.isView||function(a){return a&&-1<Da.indexOf(Object.prototype.toString.call(a))};
+va=["omit","same-origin","include"],wa="DELETE GET HEAD OPTIONS POST PUT".split(" "),ya=["GET","HEAD","POST"],xa=["same-origin","no-cors","cors","navigate"],za=["follow","error","manual"],da=[101,204,205,304],Ca=[301,302,303,307,308],Da="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";"),sa=aa.isView||function(a){return a&&-1<Da.indexOf(Object.prototype.toString.call(a))};
 n.prototype.append=function(a,b){if(2!==arguments.length)throw e("Invalid parameters to append");a=J(a);b=Y(b);this[A](a,b)||(this[p].has(a)?this[p].set(a,this[p].get(a)+", "+b):this[p].set(a,b))};n.prototype["delete"]=function(a){if(1!==arguments.length)throw e("Invalid parameters to delete");this[A](a,"invalid")||this[p].delete(J(a))};n.prototype.get=function(a){if(1!==arguments.length)throw e("Invalid parameters to get");a=J(a);var b=this[p].get(a);return void 0!==b?b:null};n.prototype.has=function(a){if(1!==
 arguments.length)throw e("Invalid parameters to has");return this[p].has(J(a))};n.prototype.set=function(a,b){if(2!==arguments.length)throw e("Invalid parameters to set");a=J(a);b=Y(b);this[A](a,b)||this[p].set(a,b)};n.prototype.forEach=function(a,b){var c=this;K.from(this[p].entries()).sort().forEach(function(d){a.call(b,d[1],d[0],c)})};n.prototype.keys=function(){return(new P(K.from(this[p].entries()).sort())).keys()};n.prototype.values=function(){return(new P(K.from(this[p].entries()).sort())).values()};
 n.prototype.entries=function(){return(new P(K.from(this[p].entries()).sort())).entries()};n.prototype[Ba]=n.prototype.entries;B.prototype.clone=function(){var a=null;null!==this[r]&&(a=ea(this[r],!0),this[r]=a[0],a=a[1]);return new B(this,{cloneBody:a,signal:this[F]})};W(B.prototype,{cache:{get:function(){return this[G]}},credentials:{get:function(){return this[H]}},headers:{get:function(){return this[x]}},integrity:{get:function(){return this[I]}},method:{get:function(){return this[D]}},mode:{get:function(){return this[t]}},
diff --git a/cobalt/fetch/fetch.js b/cobalt/fetch/fetch.js
index cae8152..5940740 100644
--- a/cobalt/fetch/fetch.js
+++ b/cobalt/fetch/fetch.js
@@ -146,8 +146,11 @@
   const VALID_METHODS_NOCORS = ['GET', 'HEAD', 'POST']
 
   // Modes that are allowed for RequestInit. Although 'navigate' is a valid
-  // request mode, it is not allowed in the RequestInit parameter.
-  const VALID_MODES = ['same-origin', 'no-cors', 'cors']
+  // request mode, it is not allowed in the RequestInit parameter. However,
+  // the request mode 'navigate' needs to be allowed since Request is
+  // polyfilled, so there is no other way to set request mode to 'navigae'
+  // even when it is correct to do so (requesting the main resource).
+  const VALID_MODES = ['same-origin', 'no-cors', 'cors', 'navigate']
 
   // Values that are allowed for Request redirect mode.
   const VALID_REDIRECT_MODES = ['follow', 'error', 'manual']
diff --git a/cobalt/h5vcc/BUILD.gn b/cobalt/h5vcc/BUILD.gn
index c31a775..7ecc1ee 100644
--- a/cobalt/h5vcc/BUILD.gn
+++ b/cobalt/h5vcc/BUILD.gn
@@ -85,6 +85,7 @@
     "//cobalt/trace_event",
     "//cobalt/watchdog",
     "//cobalt/web:dom_exception",
+    "//cobalt/worker",
     "//net",
     "//net:http_server",
     "//starboard",
diff --git a/cobalt/h5vcc/h5vcc_runtime.cc b/cobalt/h5vcc/h5vcc_runtime.cc
index ac392dd..faf56ce 100644
--- a/cobalt/h5vcc/h5vcc_runtime.cc
+++ b/cobalt/h5vcc/h5vcc_runtime.cc
@@ -14,14 +14,17 @@
 
 #include "cobalt/h5vcc/h5vcc_runtime.h"
 
-#include "base/synchronization/lock.h"
+#include <memory>
+#include <utility>
+
 #include "cobalt/base/deep_link_event.h"
 #include "cobalt/base/polymorphic_downcast.h"
 
 namespace cobalt {
 namespace h5vcc {
 H5vccRuntime::H5vccRuntime(base::EventDispatcher* event_dispatcher)
-    : event_dispatcher_(event_dispatcher) {
+    : event_dispatcher_(event_dispatcher),
+      message_loop_(base::MessageLoop::current()) {
   on_deep_link_ = new H5vccDeepLinkEventTarget(
       base::Bind(&H5vccRuntime::GetUnconsumedDeepLink, base::Unretained(this)));
   on_pause_ = new H5vccRuntimeEventTarget;
@@ -29,7 +32,7 @@
 
   DCHECK(event_dispatcher_);
   deep_link_event_callback_ =
-      base::Bind(&H5vccRuntime::OnDeepLinkEvent, base::Unretained(this));
+      base::Bind(&H5vccRuntime::OnEventForDeepLink, base::Unretained(this));
   event_dispatcher_->AddEventCallback(base::DeepLinkEvent::TypeId(),
                                       deep_link_event_callback_);
 }
@@ -40,7 +43,7 @@
 }
 
 std::string H5vccRuntime::initial_deep_link() {
-  base::AutoLock auto_lock(lock_);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (consumed_callback_) {
     std::move(consumed_callback_).Run();
   }
@@ -51,7 +54,7 @@
 }
 
 const std::string& H5vccRuntime::GetUnconsumedDeepLink() {
-  base::AutoLock auto_lock(lock_);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!initial_deep_link_.empty() && consumed_callback_) {
     LOG(INFO) << "Returning stashed unconsumed deep link: "
               << initial_deep_link_;
@@ -81,11 +84,22 @@
   tracer->Trace(on_resume_);
 }
 
-void H5vccRuntime::OnDeepLinkEvent(const base::Event* event) {
-  base::AutoLock auto_lock(lock_);
-  const base::DeepLinkEvent* deep_link_event =
-      base::polymorphic_downcast<const base::DeepLinkEvent*>(event);
-  const std::string& link = deep_link_event->link();
+void H5vccRuntime::OnEventForDeepLink(const base::Event* event) {
+  std::unique_ptr<base::DeepLinkEvent> deep_link_event(
+      new base::DeepLinkEvent(event));
+  if (base::MessageLoop::current() != message_loop_) {
+    message_loop_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&H5vccRuntime::OnDeepLinkEvent, base::Unretained(this),
+                   base::Passed(&deep_link_event)));
+    return;
+  }
+  OnDeepLinkEvent(std::move(deep_link_event));
+}
+
+void H5vccRuntime::OnDeepLinkEvent(std::unique_ptr<base::DeepLinkEvent> event) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  const std::string& link = event->link();
   if (link.empty()) {
     return;
   }
@@ -94,13 +108,13 @@
     // Store the link for later consumption.
     LOG(INFO) << "Stashing deep link: " << link;
     initial_deep_link_ = link;
-    consumed_callback_ = deep_link_event->callback();
+    consumed_callback_ = event->callback();
   } else {
     // Send the link.
     DCHECK(consumed_callback_.is_null());
     LOG(INFO) << "Dispatching deep link event: " << link;
     on_deep_link()->DispatchEvent(link);
-    base::OnceClosure callback(deep_link_event->callback());
+    base::OnceClosure callback(event->callback());
     if (callback) {
       std::move(callback).Run();
     }
diff --git a/cobalt/h5vcc/h5vcc_runtime.h b/cobalt/h5vcc/h5vcc_runtime.h
index 88be673..560543f 100644
--- a/cobalt/h5vcc/h5vcc_runtime.h
+++ b/cobalt/h5vcc/h5vcc_runtime.h
@@ -15,9 +15,12 @@
 #ifndef COBALT_H5VCC_H5VCC_RUNTIME_H_
 #define COBALT_H5VCC_H5VCC_RUNTIME_H_
 
+#include <memory>
 #include <string>
 
 #include "base/callback.h"
+#include "base/threading/thread_checker.h"
+#include "cobalt/base/deep_link_event.h"
 #include "cobalt/base/event_dispatcher.h"
 #include "cobalt/h5vcc/h5vcc_deep_link_event_target.h"
 #include "cobalt/h5vcc/h5vcc_runtime_event_target.h"
@@ -41,7 +44,8 @@
 
  private:
   // Called by the event dispatcher to handle deep link events.
-  void OnDeepLinkEvent(const base::Event* event);
+  void OnEventForDeepLink(const base::Event* event);
+  void OnDeepLinkEvent(std::unique_ptr<base::DeepLinkEvent> event);
 
   // Returns the initial deep link if it's unconsumed.
   const std::string& GetUnconsumedDeepLink();
@@ -59,7 +63,13 @@
   base::EventCallback deep_link_event_callback_;
   base::OnceClosure consumed_callback_;
 
-  base::Lock lock_;
+  // Track the message loop that created this object so deep link events are
+  // handled from the same thread.
+  base::MessageLoop* message_loop_;
+
+  // Thread checker ensures all calls to DOM element are made from the same
+  // thread that it is created in.
+  THREAD_CHECKER(thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(H5vccRuntime);
 };
diff --git a/cobalt/h5vcc/h5vcc_storage.cc b/cobalt/h5vcc/h5vcc_storage.cc
index 775026b..74fb2ca 100644
--- a/cobalt/h5vcc/h5vcc_storage.cc
+++ b/cobalt/h5vcc/h5vcc_storage.cc
@@ -24,6 +24,7 @@
 #include "cobalt/h5vcc/h5vcc_storage.h"
 #include "cobalt/persistent_storage/persistent_settings.h"
 #include "cobalt/storage/storage_manager.h"
+#include "cobalt/worker/service_worker_consts.h"
 #include "net/base/completion_once_callback.h"
 #include "net/disk_cache/cobalt/cobalt_backend_impl.h"
 #include "net/disk_cache/cobalt/resource_type.h"
@@ -68,13 +69,32 @@
   return response;
 }
 
+void DeleteCacheResourceTypeDirectory(disk_cache::ResourceType type) {
+  auto metadata = disk_cache::kTypeMetadata[type];
+  std::vector<char> cache_dir(kSbFileMaxPath + 1, 0);
+  SbSystemGetPath(kSbSystemPathCacheDirectory, cache_dir.data(),
+                  kSbFileMaxPath);
+  base::FilePath cache_type_dir =
+      base::FilePath(cache_dir.data())
+          .Append(FILE_PATH_LITERAL(metadata.directory));
+  starboard::SbFileDeleteRecursive(cache_type_dir.value().data(), true);
+}
+
 void ClearCacheHelper(disk_cache::Backend* backend) {
   backend->DoomAllEntries(base::DoNothing());
+
+
+  for (int type_index = 0; type_index < disk_cache::kTypeCount; type_index++) {
+    DeleteCacheResourceTypeDirectory(
+        static_cast<disk_cache::ResourceType>(type_index));
+  }
 }
 
 void ClearCacheOfTypeHelper(disk_cache::ResourceType type,
                             disk_cache::CobaltBackendImpl* backend) {
   backend->DoomAllEntriesOfType(type, base::DoNothing());
+
+  DeleteCacheResourceTypeDirectory(type);
 }
 
 }  // namespace
@@ -377,6 +397,35 @@
   cobalt::cache::Cache::GetInstance()->DeleteAll();
 }
 
+void H5vccStorage::ClearCacheOfType(int type_index) {
+  if (type_index < 0 || type_index > disk_cache::kTypeCount) {
+    DLOG(INFO)
+        << "Invalid type_index, out of bounds of disk_cache::kTypeMetadata";
+    return;
+  }
+  disk_cache::ResourceType type =
+      static_cast<disk_cache::ResourceType>(type_index);
+  if (ValidatedCacheBackend()) {
+    network_module_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ClearCacheOfTypeHelper, type,
+                              base::Unretained(cache_backend_)));
+  }
+  cobalt::cache::Cache::GetInstance()->Delete(type);
+}
+
+void H5vccStorage::ClearServiceWorkerCache() {
+  ClearCacheOfType(
+      static_cast<int>(disk_cache::ResourceType::kServiceWorkerScript));
+  // Add deletion of service worker persistent settings file
+  std::vector<char> storage_dir(kSbFileMaxPath, 0);
+  SbSystemGetPath(kSbSystemPathCacheDirectory, storage_dir.data(),
+                  kSbFileMaxPath);
+  std::string service_worker_file_path =
+      std::string(storage_dir.data()) + kSbFileSepString +
+      worker::ServiceWorkerConsts::kSettingsJson;
+  SbFileDelete(service_worker_file_path.c_str());
+}
+
 bool H5vccStorage::ValidatedCacheBackend() {
   if (!http_cache_) {
     return false;
diff --git a/cobalt/h5vcc/h5vcc_storage.h b/cobalt/h5vcc/h5vcc_storage.h
index 54b06c8..1ba86e3 100644
--- a/cobalt/h5vcc/h5vcc_storage.h
+++ b/cobalt/h5vcc/h5vcc_storage.h
@@ -66,6 +66,10 @@
 
   void ClearCache();
 
+  void ClearCacheOfType(int type_index);
+
+  void ClearServiceWorkerCache();
+
   DEFINE_WRAPPABLE_TYPE(H5vccStorage);
 
  private:
diff --git a/cobalt/h5vcc/h5vcc_storage.idl b/cobalt/h5vcc/h5vcc_storage.idl
index f1a15d2..9d4b1aa 100644
--- a/cobalt/h5vcc/h5vcc_storage.idl
+++ b/cobalt/h5vcc/h5vcc_storage.idl
@@ -29,4 +29,6 @@
   void disableCache();
 
   void clearCache();
+  void clearCacheOfType(octet type_index);
+  void clearServiceWorkerCache();
 };
diff --git a/cobalt/layout/box.cc b/cobalt/layout/box.cc
index f7dc24c..99f53dc 100644
--- a/cobalt/layout/box.cc
+++ b/cobalt/layout/box.cc
@@ -553,6 +553,14 @@
   return padding_top() + height() + padding_bottom();
 }
 
+RectLayoutUnit Box::GetClampedPaddingBox(bool transform_forms_root) const {
+  auto padding_box_offset = GetPaddingBoxOffsetFromRoot(transform_forms_root);
+  auto clamped_padding_box = GetClampedPaddingBoxSize();
+  return RectLayoutUnit(padding_box_offset.x(), padding_box_offset.y(),
+                        clamped_padding_box.width(),
+                        clamped_padding_box.height());
+}
+
 SizeLayoutUnit Box::GetClampedPaddingBoxSize() const {
   // Padding box size depends on the content and padding areas
   // Its dimensions cannot be negative because the content and padding areas
@@ -2151,54 +2159,34 @@
   return false;
 }
 
-bool Box::ApplyTransformActionToCoordinate(TransformAction action,
-                                           math::Vector2dF* coordinate) const {
+bool Box::ApplyTransformActionToCoordinate(math::Vector2dF* coordinate) const {
   std::vector<math::Vector2dF> coordinate_vector;
   coordinate_vector.push_back(*coordinate);
-  bool result = ApplyTransformActionToCoordinates(action, &coordinate_vector);
+  bool result = ApplyTransformActionToCoordinates(&coordinate_vector);
   *coordinate = coordinate_vector[0];
   return result;
 }
 
 bool Box::ApplyTransformActionToCoordinates(
-    TransformAction action, std::vector<math::Vector2dF>* coordinates) const {
+    std::vector<math::Vector2dF>* coordinates) const {
   const scoped_refptr<cssom::PropertyValue>& transform =
       computed_style()->transform();
   if (transform == cssom::KeywordValue::GetNone()) {
     return true;
   }
 
-  // The border box offset is calculated in two steps because we want to
-  // stop at the second transform and not the first (which is this box).
   Vector2dLayoutUnit containing_block_offset_from_root =
       GetContainingBlockOffsetFromRoot(true /*transform_forms_root*/);
 
-  // The transform rect always includes the offset from the containing block.
-  // However, in the case where the action is entering the transform, the full
-  // offset from the root needs to be included in the transform.
-  Vector2dLayoutUnit transform_rect_offset =
-      margin_box_offset_from_containing_block() +
-      GetBorderBoxOffsetFromMarginBox();
-  if (action == kEnterTransform) {
-    transform_rect_offset += containing_block_offset_from_root;
-  }
+  auto matrix = GetCSSTransformForBoxWithPredefinedOffset(
+      containing_block_offset_from_root);
 
-  // Transform the coordinates.
-  math::Matrix3F matrix = GetCSSTransform(
-      transform.get(), computed_style()->transform_origin().get(),
-      math::RectF(transform_rect_offset.x().toFloat(),
-                  transform_rect_offset.y().toFloat(),
-                  GetBorderBoxWidth().toFloat(),
-                  GetBorderBoxHeight().toFloat()),
-      ComputeUiNavFocusForTransform());
   if (!matrix.IsIdentity()) {
-    if (action == kEnterTransform) {
-      matrix = matrix.Inverse();
-      // The matrix is not invertible. Return that applying the transform
-      // failed.
-      if (matrix.IsZeros()) {
-        return false;
-      }
+    matrix = matrix.Inverse();
+    // The matrix is not invertible. Return that applying the transform
+    // failed.
+    if (matrix.IsZeros()) {
+      return false;
     }
 
     for (std::vector<math::Vector2dF>::iterator coordinate_iter =
@@ -2222,15 +2210,61 @@
            coordinates->begin();
        coordinate_iter != coordinates->end(); ++coordinate_iter) {
     math::Vector2dF& coordinate = *coordinate_iter;
-    if (action == kEnterTransform) {
-      coordinate -= containing_block_offset_from_root_as_float;
-    } else {
-      coordinate += containing_block_offset_from_root_as_float;
-    }
+    coordinate -= containing_block_offset_from_root_as_float;
   }
   return true;
 }
 
+math::Matrix3F Box::GetCSSTransformForBox() const {
+  if (!IsTransformed()) {
+    return math::Matrix3F::Identity();
+  }
+
+  Vector2dLayoutUnit containing_block_offset_from_root =
+      GetContainingBlockOffsetFromRoot(true /*transform_forms_root*/);
+  return GetCSSTransformForBoxWithPredefinedOffset(
+      containing_block_offset_from_root);
+}
+
+math::Matrix3F Box::GetCSSTransformForBoxWithPredefinedOffset(
+    Vector2dLayoutUnit containing_block_offset_from_root) const {
+  if (!IsTransformed()) {
+    return math::Matrix3F::Identity();
+  }
+
+  // The border box offset is calculated in two steps because we want to
+  // stop at the second transform and not the first (which is the containing
+  // block).
+  //
+  // The transform rect always includes the offset from the containing block.
+  // However, in the case where the action is entering the transform, the full
+  // offset from the root needs to be included in the transform.
+  Vector2dLayoutUnit transform_rect_offset =
+      margin_box_offset_from_containing_block() +
+      GetBorderBoxOffsetFromMarginBox() + containing_block_offset_from_root;
+
+  // Transform the coordinates.
+  math::Matrix3F matrix =
+      GetCSSTransform(computed_style()->transform().get(),
+                      computed_style()->transform_origin().get(),
+                      math::RectF(transform_rect_offset.x().toFloat(),
+                                  transform_rect_offset.y().toFloat(),
+                                  GetBorderBoxWidth().toFloat(),
+                                  GetBorderBoxHeight().toFloat()),
+                      ComputeUiNavFocusForTransform());
+
+  return matrix;
+}
+
+bool Box::CoordinateCanTarget(const math::Vector2dF* coordinate) const {
+  if (!cssom::IsOverflowCropped(computed_style())) {
+    return true;
+  }
+  const Vector2dLayoutUnit layout_coordinate(LayoutUnit(coordinate->x()),
+                                             LayoutUnit(coordinate->y()));
+  return IsUnderCoordinate(layout_coordinate);
+}
+
 void Box::AddIntersectionObserverRootsAndTargets(
     BoxIntersectionObserverModule::IntersectionObserverRootVector&& roots,
     BoxIntersectionObserverModule::IntersectionObserverTargetVector&& targets) {
diff --git a/cobalt/layout/box.h b/cobalt/layout/box.h
index 83b4a27..05449cd 100644
--- a/cobalt/layout/box.h
+++ b/cobalt/layout/box.h
@@ -268,6 +268,8 @@
   // Returns the offset from root to this box's containing block.
   Vector2dLayoutUnit GetContainingBlockOffsetFromRoot(
       bool transform_forms_root) const;
+  math::Matrix3F GetCSSTransformForBoxWithPredefinedOffset(
+      Vector2dLayoutUnit containing_block_offset_from_root) const;
 
   // Returns the offset from the containing block (which can be either the
   // containing block's content box or padding box) to its content box.
@@ -413,6 +415,7 @@
   LayoutUnit padding_bottom() const { return padding_insets_.bottom(); }
   LayoutUnit GetPaddingBoxWidth() const;
   LayoutUnit GetPaddingBoxHeight() const;
+  RectLayoutUnit GetClampedPaddingBox(bool transform_forms_root) const;
   SizeLayoutUnit GetClampedPaddingBoxSize() const;
 
   RectLayoutUnit GetPaddingBoxFromMarginBox() const;
@@ -704,10 +707,12 @@
   // Applies the specified transform action to the provided coordinates.
   // Returns false if the transform is not invertible and the action requires
   // it being inverted.
-  bool ApplyTransformActionToCoordinate(TransformAction action,
-                                        math::Vector2dF* coordinate) const;
+  bool ApplyTransformActionToCoordinate(math::Vector2dF* coordinate) const;
   bool ApplyTransformActionToCoordinates(
-      TransformAction action, std::vector<math::Vector2dF>* coordinates) const;
+      std::vector<math::Vector2dF>* coordinates) const;
+
+  bool CoordinateCanTarget(const math::Vector2dF* coordinate) const;
+  math::Matrix3F GetCSSTransformForBox() const;
 
   // Intended to be set to false on the initial containing block, this indicates
   // that when the background color is rendered, it will be blended with what,
diff --git a/cobalt/layout/topmost_event_target.cc b/cobalt/layout/topmost_event_target.cc
index e5b92ad..d7ce92e 100644
--- a/cobalt/layout/topmost_event_target.cc
+++ b/cobalt/layout/topmost_event_target.cc
@@ -14,12 +14,15 @@
 
 #include "cobalt/layout/topmost_event_target.h"
 
+#include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/optional.h"
 #include "base/trace_event/trace_event.h"
 #include "cobalt/base/token.h"
 #include "cobalt/base/tokens.h"
+#include "cobalt/cssom/computed_style_utils.h"
 #include "cobalt/cssom/keyword_value.h"
 #include "cobalt/dom/document.h"
 #include "cobalt/dom/html_element.h"
@@ -32,6 +35,8 @@
 #include "cobalt/dom/pointer_state.h"
 #include "cobalt/dom/ui_event.h"
 #include "cobalt/dom/wheel_event.h"
+#include "cobalt/layout/layout_unit.h"
+#include "cobalt/math/rect_f.h"
 #include "cobalt/math/vector2d.h"
 #include "cobalt/math/vector2d_f.h"
 #include "cobalt/web/event.h"
@@ -79,36 +84,40 @@
   return NULL;
 }
 
-scoped_refptr<dom::HTMLElement> FindFirstElementWithScrollType(
-    scoped_refptr<dom::HTMLElement> target_element,
-    ui_navigation::scroll_engine::ScrollType major_scroll_axis,
-    bool scrolling_right, bool scrolling_down) {
-  auto current_element = target_element;
-  bool scrolling_left = !scrolling_right;
-  bool scrolling_up = !scrolling_down;
-  bool horizontal_scroll_axis =
-      major_scroll_axis == ui_navigation::scroll_engine::ScrollType::Horizontal;
-  bool vertical_scroll_axis =
-      major_scroll_axis == ui_navigation::scroll_engine::ScrollType::Vertical;
+std::unique_ptr<dom::PossibleScrollTargets> FindPossibleScrollTargets(
+    scoped_refptr<dom::Element> target_element) {
+  std::unique_ptr<dom::PossibleScrollTargets> possible_scroll_targets =
+      std::make_unique<dom::PossibleScrollTargets>();
 
-  while (true) {
+  for (auto current_element = target_element; !!current_element;
+       current_element = current_element->parent_element()) {
+    auto current_html_element = current_element->AsHTMLElement();
+    if (!current_html_element) {
+      continue;
+    }
+
+    bool pointer_events_enabled =
+        current_html_element->computed_style()->pointer_events() !=
+        cssom::KeywordValue::GetNone();
+    if (!pointer_events_enabled) {
+      continue;
+    }
+
+    auto current_ui_nav_item = current_html_element->GetUiNavItem();
+    if (!current_ui_nav_item) {
+      continue;
+    }
+
     float scroll_top_lower_bound;
     float scroll_left_lower_bound;
     float scroll_top_upper_bound;
     float scroll_left_upper_bound;
-    float offset_x;
-    float offset_y;
-
-    if (!current_element->parent_element()) {
-      break;
-    }
-    current_element = current_element->parent_element()->AsHTMLElement();
-    auto current_ui_nav_item = current_element->GetUiNavItem();
-    if (!current_ui_nav_item) continue;
-
     current_ui_nav_item->GetBounds(
         &scroll_top_lower_bound, &scroll_left_lower_bound,
         &scroll_top_upper_bound, &scroll_left_upper_bound);
+
+    float offset_x;
+    float offset_y;
     current_ui_nav_item->GetContentOffset(&offset_x, &offset_y);
 
     bool can_scroll_left = scroll_left_lower_bound < offset_x;
@@ -116,175 +125,72 @@
     bool can_scroll_up = scroll_top_lower_bound < offset_y;
     bool can_scroll_down = scroll_top_upper_bound > offset_y;
 
-    if ((scrolling_left && can_scroll_left && horizontal_scroll_axis) ||
-        (scrolling_right && can_scroll_right && horizontal_scroll_axis) ||
-        (scrolling_up && can_scroll_up && vertical_scroll_axis) ||
-        (scrolling_down && can_scroll_down && vertical_scroll_axis)) {
-      return current_element;
+    if (can_scroll_left && !possible_scroll_targets->left) {
+      possible_scroll_targets->left = current_html_element;
     }
+    if (can_scroll_right && !possible_scroll_targets->right) {
+      possible_scroll_targets->right = current_html_element;
+    }
+    if (can_scroll_up && !possible_scroll_targets->up) {
+      possible_scroll_targets->up = current_html_element;
+    }
+    if (can_scroll_down && !possible_scroll_targets->down) {
+      possible_scroll_targets->down = current_html_element;
+    }
+  }
+  return possible_scroll_targets;
+}
+
+scoped_refptr<dom::HTMLElement> FindFirstElementWithScrollType(
+    dom::PossibleScrollTargets* possible_scroll_targets,
+    ui_navigation::scroll_engine::ScrollType major_scroll_axis,
+    bool scrolling_right, bool scrolling_down) {
+  bool scrolling_left = !scrolling_right;
+  bool scrolling_up = !scrolling_down;
+  bool horizontal_scroll_axis =
+      major_scroll_axis == ui_navigation::scroll_engine::ScrollType::Horizontal;
+  bool vertical_scroll_axis =
+      major_scroll_axis == ui_navigation::scroll_engine::ScrollType::Vertical;
+
+  if (scrolling_left && horizontal_scroll_axis) {
+    return possible_scroll_targets->left;
+  } else if (scrolling_right && horizontal_scroll_axis) {
+    return possible_scroll_targets->right;
+  } else if (scrolling_up && vertical_scroll_axis) {
+    return possible_scroll_targets->up;
+  } else if (scrolling_down && vertical_scroll_axis) {
+    return possible_scroll_targets->down;
   }
   return nullptr;
 }
 
-}  // namespace
-void TopmostEventTarget::ConsiderElement(dom::Element* element,
-                                         const math::Vector2dF& coordinate) {
-  if (!element) return;
-  math::Vector2dF element_coordinate(coordinate);
+bool TransformCanBeAppliedToBox(const Box* box, math::Vector2dF* coordinate) {
+  return !box->IsTransformed() ||
+         box->ApplyTransformActionToCoordinate(coordinate);
+}
+
+struct CanTargetBox {
+  const math::Vector2dF* coordinate;
+  explicit CanTargetBox(const math::Vector2dF* coordinate)
+      : coordinate(coordinate) {}
+  bool operator()(const Box* box) const {
+    return box->CoordinateCanTarget(coordinate);
+  }
+};
+
+bool ShouldConsiderElementAndChildren(dom::Element* element,
+                                      math::Vector2dF* coordinate) {
   LayoutBoxes* layout_boxes = GetLayoutBoxesIfNotEmpty(element);
-  if (layout_boxes) {
-    const Box* box = layout_boxes->boxes().front();
-    if (box->computed_style() && box->IsTransformed()) {
-      // Early out if the transform cannot be applied. This can occur if the
-      // transform matrix is not invertible.
-      if (!box->ApplyTransformActionToCoordinate(Box::kEnterTransform,
-                                                 &element_coordinate)) {
-        return;
-      }
-    }
-
-    scoped_refptr<dom::HTMLElement> html_element = element->AsHTMLElement();
-    if (html_element && html_element->CanBeDesignatedByPointerIfDisplayed()) {
-      ConsiderBoxes(html_element, layout_boxes, element_coordinate);
-    }
+  const Boxes boxes = layout_boxes->boxes();
+  const Box* box = boxes.front();
+  if (!box->computed_style()) {
+    return true;
   }
 
-  for (dom::Element* child_element = element->first_element_child();
-       child_element; child_element = child_element->next_element_sibling()) {
-    ConsiderElement(child_element, element_coordinate);
-  }
+  return TransformCanBeAppliedToBox(box, coordinate) &&
+         std::any_of(boxes.begin(), boxes.end(), CanTargetBox(coordinate));
 }
 
-void TopmostEventTarget::ConsiderBoxes(
-    const scoped_refptr<dom::HTMLElement>& html_element,
-    LayoutBoxes* layout_boxes, const math::Vector2dF& coordinate) {
-  const Boxes& boxes = layout_boxes->boxes();
-  Vector2dLayoutUnit layout_coordinate(LayoutUnit(coordinate.x()),
-                                       LayoutUnit(coordinate.y()));
-  for (Boxes::const_iterator box_iterator = boxes.begin();
-       box_iterator != boxes.end(); ++box_iterator) {
-    Box* box = *box_iterator;
-    do {
-      if (box->IsUnderCoordinate(layout_coordinate)) {
-        Box::RenderSequence render_sequence = box->GetRenderSequence();
-        if (Box::IsRenderedLater(render_sequence, render_sequence_)) {
-          html_element_ = html_element;
-          box_ = box;
-          render_sequence_.swap(render_sequence);
-        }
-      }
-      box = box->GetSplitSibling();
-    } while (box != NULL);
-  }
-}
-
-void TopmostEventTarget::CancelScrollsInParentNavItems(
-    scoped_refptr<dom::HTMLElement> target_element) {
-  // Cancel any scrolls in the tree.
-  std::vector<scoped_refptr<ui_navigation::NavItem>> scrolls_to_cancel;
-  auto current_element = target_element;
-  while (true) {
-    if (!current_element->parent_element()) {
-      break;
-    }
-    current_element = current_element->parent_element()->AsHTMLElement();
-    auto current_ui_nav_item = current_element->GetUiNavItem();
-    if (current_ui_nav_item) {
-      scrolls_to_cancel.push_back(current_ui_nav_item);
-    }
-  }
-
-  scroll_engine_->thread()->message_loop()->task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&ui_navigation::scroll_engine::ScrollEngine::
-                     CancelActiveScrollsForNavItems,
-                 base::Unretained(scroll_engine_), scrolls_to_cancel));
-}
-
-void TopmostEventTarget::HandleScrollState(
-    scoped_refptr<dom::HTMLElement> target_element,
-    const dom::PointerEvent* pointer_event, dom::PointerState* pointer_state,
-    dom::PointerEventInit* event_init) {
-  // On pointer down, cancel any scrolls happening for UI nav items above
-  // that element. Additionally, save the pointer coordinates.
-  //
-  // On pointer move, check if we've reached the threshold to start
-  // scrolling. If we have, find the first scroll container we can scroll.
-  // Then send that scroll container, initial pointer event coords, current
-  // pointer event coords, scroll direction.
-  bool pointer_type_is_accepted = pointer_event->pointer_type() == "mouse" ||
-                                  pointer_event->pointer_type() == "pen" ||
-                                  pointer_event->pointer_type() == "touch";
-  if (!scroll_engine_ || !pointer_event || !pointer_type_is_accepted) {
-    return;
-  }
-
-  bool should_clear_pointer_state =
-      pointer_event->type() == base::Tokens::pointerup();
-
-  auto pointer_id = pointer_event->pointer_id();
-  auto pointer_coordinates =
-      math::Vector2dF(pointer_event->client_x(), pointer_event->client_y());
-
-  if (pointer_event->type() == base::Tokens::pointerdown()) {
-    CancelScrollsInParentNavItems(target_element);
-    pointer_state->SetClientCoordinates(pointer_id, pointer_coordinates);
-    pointer_state->SetClientTimeStamp(pointer_id, pointer_event->time_stamp());
-    return;
-  }
-
-  auto initial_coordinates = pointer_state->GetClientCoordinates(pointer_id);
-  auto initial_time_stamp = pointer_state->GetClientTimeStamp(pointer_id);
-  if (pointer_event->type() == base::Tokens::pointermove() &&
-      initial_coordinates.has_value() && initial_time_stamp.has_value()) {
-    cobalt::math::Vector2dF drag_vector =
-        initial_coordinates.value() - pointer_coordinates;
-    float x = drag_vector.x();
-    float y = drag_vector.y();
-
-    if (drag_vector.Length() >=
-        ui_navigation::scroll_engine::kDragDistanceThreshold) {
-      // Get major scroll direction.
-      ui_navigation::scroll_engine::ScrollType scroll_type =
-          std::abs(x) > std::abs(y)
-              ? ui_navigation::scroll_engine::ScrollType::Horizontal
-              : ui_navigation::scroll_engine::ScrollType::Vertical;
-      auto element_to_scroll = FindFirstElementWithScrollType(
-          target_element, scroll_type, x > 0, y > 0);
-      if (!element_to_scroll) {
-        return;
-      }
-
-      const scoped_refptr<dom::Window>& view = event_init->view();
-      element_to_scroll->DispatchEvent(new dom::PointerEvent(
-          base::Tokens::pointercancel(), web::Event::kBubbles,
-          web::Event::kNotCancelable, view, *event_init));
-      element_to_scroll->DispatchEvent(
-          new dom::PointerEvent(base::Tokens::pointerout(), view, *event_init));
-      element_to_scroll->DispatchEvent(new dom::PointerEvent(
-          base::Tokens::pointerleave(), web::Event::kNotBubbles,
-          web::Event::kNotCancelable, view, *event_init));
-      pointer_state->SetWasCancelled(pointer_id);
-
-      should_clear_pointer_state = true;
-      scroll_engine_->thread()->message_loop()->task_runner()->PostTask(
-          FROM_HERE,
-          base::Bind(
-              &ui_navigation::scroll_engine::ScrollEngine::HandleScrollStart,
-              base::Unretained(scroll_engine_),
-              element_to_scroll->GetUiNavItem(), scroll_type, pointer_id,
-              initial_coordinates.value(), initial_time_stamp.value(),
-              pointer_coordinates, pointer_event->time_stamp()));
-    }
-  }
-
-  if (should_clear_pointer_state) {
-    pointer_state->ClearClientCoordinates(pointer_id);
-    pointer_state->ClearTimeStamp(pointer_id);
-  }
-}
-
-namespace {
 // Return the nearest common ancestor of previous_element and target_element
 scoped_refptr<dom::Element> GetNearestCommonAncestor(
     scoped_refptr<dom::HTMLElement> previous_element,
@@ -373,6 +279,15 @@
   }
 }
 
+void SendStateChangeLeaveEvents(
+    bool is_pointer_event, scoped_refptr<dom::HTMLElement> previous_element,
+    dom::PointerEventInit* event_init) {
+  scoped_refptr<dom::HTMLElement> target_element = nullptr;
+  scoped_refptr<dom::Element> nearest_common_ancestor = nullptr;
+  SendStateChangeLeaveEvents(is_pointer_event, previous_element, target_element,
+                             nearest_common_ancestor, event_init);
+}
+
 void SendStateChangeEnterEvents(
     bool is_pointer_event, scoped_refptr<dom::HTMLElement> previous_element,
     scoped_refptr<dom::HTMLElement> target_element,
@@ -495,8 +410,190 @@
     event_init->set_is_primary(pointer_event->is_primary());
   }
 }
+
+void DispatchPointerEventsForScrollStart(
+    scoped_refptr<dom::HTMLElement> element,
+    dom::PointerEventInit* event_init) {
+  const scoped_refptr<dom::Window>& view = event_init->view();
+  element->DispatchEvent(
+      new dom::PointerEvent(base::Tokens::pointercancel(), web::Event::kBubbles,
+                            web::Event::kNotCancelable, view, *event_init));
+  bool is_pointer_event = true;
+  SendStateChangeLeaveEvents(is_pointer_event, element, event_init);
+}
+
+math::Matrix3F GetCompleteTransformMatrix(dom::Element* element) {
+  auto complete_matrix = math::Matrix3F::Identity();
+  auto current_element = element;
+  while (current_element) {
+    LayoutBoxes* layout_boxes = GetLayoutBoxesIfNotEmpty(current_element);
+    const Box* box = layout_boxes->boxes().front();
+    complete_matrix = complete_matrix * box->GetCSSTransformForBox();
+    current_element = current_element->parent_element();
+  }
+  return complete_matrix;
+}
+
 }  // namespace
 
+void TopmostEventTarget::ConsiderElement(dom::Element* element,
+                                         const math::Vector2dF& coordinate) {
+  if (!element) return;
+  math::Vector2dF element_coordinate(coordinate);
+  LayoutBoxes* layout_boxes = GetLayoutBoxesIfNotEmpty(element);
+  if (layout_boxes) {
+    if (!ShouldConsiderElementAndChildren(element, &element_coordinate)) {
+      return;
+    }
+    scoped_refptr<dom::HTMLElement> html_element = element->AsHTMLElement();
+    if (html_element && html_element->CanBeDesignatedByPointerIfDisplayed()) {
+      ConsiderBoxes(html_element, layout_boxes, element_coordinate);
+    }
+  }
+
+  for (dom::Element* child_element = element->first_element_child();
+       child_element; child_element = child_element->next_element_sibling()) {
+    ConsiderElement(child_element, element_coordinate);
+  }
+}
+
+void TopmostEventTarget::ConsiderBoxes(
+    const scoped_refptr<dom::HTMLElement>& html_element,
+    LayoutBoxes* layout_boxes, const math::Vector2dF& coordinate) {
+  const Boxes& boxes = layout_boxes->boxes();
+  Vector2dLayoutUnit layout_coordinate(LayoutUnit(coordinate.x()),
+                                       LayoutUnit(coordinate.y()));
+  for (Boxes::const_iterator box_iterator = boxes.begin();
+       box_iterator != boxes.end(); ++box_iterator) {
+    Box* box = *box_iterator;
+    do {
+      if (box->IsUnderCoordinate(layout_coordinate)) {
+        Box::RenderSequence render_sequence = box->GetRenderSequence();
+        if (Box::IsRenderedLater(render_sequence, render_sequence_)) {
+          html_element_ = html_element;
+          box_ = box;
+          render_sequence_.swap(render_sequence);
+        }
+      }
+      box = box->GetSplitSibling();
+    } while (box != NULL);
+  }
+}
+
+void TopmostEventTarget::CancelScrollsInParentNavItems(
+    scoped_refptr<dom::HTMLElement> target_element) {
+  // Cancel any scrolls in the tree.
+  std::vector<scoped_refptr<ui_navigation::NavItem>> scrolls_to_cancel;
+  auto current_element = target_element;
+  while (true) {
+    if (!current_element->parent_element()) {
+      break;
+    }
+    current_element = current_element->parent_element()->AsHTMLElement();
+    auto current_ui_nav_item = current_element->GetUiNavItem();
+    if (current_ui_nav_item) {
+      scrolls_to_cancel.push_back(current_ui_nav_item);
+    }
+  }
+
+  scroll_engine_->thread()->message_loop()->task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ui_navigation::scroll_engine::ScrollEngine::
+                     CancelActiveScrollsForNavItems,
+                 base::Unretained(scroll_engine_), scrolls_to_cancel));
+}
+
+void TopmostEventTarget::HandleScrollState(
+    scoped_refptr<dom::HTMLElement> target_element,
+    const dom::PointerEvent* pointer_event, dom::PointerState* pointer_state,
+    dom::PointerEventInit* event_init) {
+  // On pointer down, cancel any scrolls happening for UI nav items above
+  // that element. Additionally, save the pointer coordinates.
+  //
+  // On pointer move, check if we've reached the threshold to start
+  // scrolling. If we have, find the first scroll container we can scroll.
+  // Then send that scroll container, initial pointer event coords, current
+  // pointer event coords, scroll direction.
+  bool pointer_type_is_accepted = pointer_event->pointer_type() == "mouse" ||
+                                  pointer_event->pointer_type() == "pen" ||
+                                  pointer_event->pointer_type() == "touch";
+  if (!scroll_engine_ || !pointer_event || !pointer_type_is_accepted) {
+    return;
+  }
+
+  bool should_clear_pointer_state =
+      pointer_event->type() == base::Tokens::pointerup();
+
+  auto pointer_id = pointer_event->pointer_id();
+  auto pointer_coordinates =
+      math::Vector2dF(pointer_event->client_x(), pointer_event->client_y());
+
+  if (pointer_event->type() == base::Tokens::pointerdown()) {
+    CancelScrollsInParentNavItems(target_element);
+
+    auto initial_possible_scroll_targets =
+        FindPossibleScrollTargets(target_element);
+    pointer_state->SetPossibleScrollTargets(
+        pointer_id, std::move(initial_possible_scroll_targets));
+
+    auto transform_matrix = GetCompleteTransformMatrix(target_element.get());
+    pointer_state->SetClientTransformMatrix(pointer_id, transform_matrix);
+    pointer_state->SetClientCoordinates(pointer_id, pointer_coordinates);
+    pointer_state->SetClientTimeStamp(pointer_id, pointer_event->time_stamp());
+    return;
+  }
+
+  auto initial_coordinates = pointer_state->GetClientCoordinates(pointer_id);
+  auto initial_time_stamp = pointer_state->GetClientTimeStamp(pointer_id);
+  auto possible_scroll_targets =
+      pointer_state->GetPossibleScrollTargets(pointer_id);
+  auto initial_transform = pointer_state->GetClientTransformMatrix(pointer_id);
+
+  if (pointer_event->type() == base::Tokens::pointermove() &&
+      initial_coordinates.has_value() && initial_time_stamp.has_value() &&
+      possible_scroll_targets) {
+    cobalt::math::Vector2dF drag_vector =
+        initial_coordinates.value() - pointer_coordinates;
+    float x = drag_vector.x();
+    float y = drag_vector.y();
+
+    if (drag_vector.Length() >=
+        ui_navigation::scroll_engine::kDragDistanceThreshold) {
+      // Get major scroll direction.
+      ui_navigation::scroll_engine::ScrollType scroll_type =
+          std::abs(x) > std::abs(y)
+              ? ui_navigation::scroll_engine::ScrollType::Horizontal
+              : ui_navigation::scroll_engine::ScrollType::Vertical;
+      auto element_to_scroll = FindFirstElementWithScrollType(
+          possible_scroll_targets, scroll_type, x > 0, y > 0);
+      if (!element_to_scroll) {
+        return;
+      }
+
+      DispatchPointerEventsForScrollStart(target_element, event_init);
+      pointer_state->SetWasCancelled(pointer_id);
+
+      should_clear_pointer_state = true;
+      scroll_engine_->thread()->message_loop()->task_runner()->PostTask(
+          FROM_HERE,
+          base::Bind(
+              &ui_navigation::scroll_engine::ScrollEngine::HandleScrollStart,
+              base::Unretained(scroll_engine_),
+              element_to_scroll->GetUiNavItem(), scroll_type, pointer_id,
+              initial_coordinates.value(), initial_time_stamp.value(),
+              pointer_coordinates, pointer_event->time_stamp(),
+              initial_transform));
+    }
+  }
+
+  if (should_clear_pointer_state) {
+    pointer_state->ClearPossibleScrollTargets(pointer_id);
+    pointer_state->ClearClientCoordinates(pointer_id);
+    pointer_state->ClearTimeStamp(pointer_id);
+    pointer_state->ClearMatrix(pointer_id);
+  }
+}
+
 TopmostEventTarget::TopmostEventTarget(
     ui_navigation::scroll_engine::ScrollEngine* scroll_engine)
     : scroll_engine_(scroll_engine) {}
diff --git a/cobalt/layout_tests/testdata/web-platform-tests/service-workers/web_platform_tests.txt b/cobalt/layout_tests/testdata/web-platform-tests/service-workers/web_platform_tests.txt
index c353c7e..686eabe 100644
--- a/cobalt/layout_tests/testdata/web-platform-tests/service-workers/web_platform_tests.txt
+++ b/cobalt/layout_tests/testdata/web-platform-tests/service-workers/web_platform_tests.txt
@@ -1,8 +1,103 @@
 # Service Worker API tests
 
-service-worker/about-blank-replacement.https.html, DISABLE
-service-worker/activate-event-after-install-state-change.https.html, DISABLE
+service-worker/clients-matchall-on-evaluation.https.html, PASS
+service-worker/fetch-event-add-async.https.html, PASS
+service-worker/register-default-scope.https.html, PASS
+service-worker/registration-basic.https.html, PASS
+service-worker/registration-security-error.https.html, PASS
+service-worker/registration-script-url.https.html, PASS
+service-worker/rejections.https.html, PASS
+service-worker/serviceworkerobject-scripturl.https.html, PASS
+service-worker/service-worker-csp-default.https.html, PASS
+service-worker/service-worker-csp-connect.https.html, PASS
+service-worker/service-worker-header.https.html, PASS
+service-worker/service-worker-csp-script.https.html, PASS
+service-worker/Service-Worker-Allowed-header.https.html, PASS
+service-worker/skip-waiting-without-client.https.html, PASS
+service-worker/uncontrolled-page.https.html, PASS
+service-worker/unregister.https.html, PASS
+service-worker/update-missing-import-scripts.https.html, PASS
+service-worker/update-result.https.html, PASS
+
+# Tests pass with memory leakage issue.
+service-worker/update-no-cache-request-headers.https.html, DISABLE
+
+
+# b/234788479 Implement waiting for update worker state tasks in Install algorithm.
 service-worker/activation-after-registration.https.html, DISABLE
+service-worker/activate-event-after-install-state-change.https.html, DISABLE
+service-worker/multiple-update.https.html, DISABLE
+service-worker/register-wait-forever-in-install-worker.https.html, DISABLE
+service-worker/state.https.html, DISABLE
+
+# "Module" type of dedicated worker is supported in Cobalt
+service-worker/dedicated-worker-service-worker-interception.https.html, DISABLE
+service-worker/registration-schedule-job.https.html, DISABLE
+service-worker/registration-scope-module-static-import.https.html, DISABLE
+service-worker/registration-script-module.https.html, DISABLE
+service-worker/update-module-request-mode.https.html, DISABLE
+service-worker/update-registration-with-type.https.html, DISABLE
+
+# Channel API is not supported in Cobalt
+service-worker/clients-matchall-frozen.https.html, DISABLE
+service-worker/extendable-event-waituntil.https.html, DISABLE
+service-worker/immutable-prototype-serviceworker.https.html, DISABLE
+service-worker/indexeddb.https.html, DISABLE
+service-worker/postmessage.https.html, DISABLE
+service-worker/registration-end-to-end.https.html, DISABLE
+service-worker/registration-events.https.html, DISABLE
+
+# Below are manual tests from web-platform-tests without automation.
+service-worker/fetch-event-is-history-backward-navigation-manual.https.html, DISABLE
+service-worker/fetch-event-is-history-forward-navigation-manual.https.html, DISABLE
+service-worker/fetch-event-is-reload-navigation-manual.https.html, DISABLE
+
+# b/265841607 Unhandled rejection with value: object "TypeError"
+service-worker/import-scripts-cross-origin.https.html, DISABLE
+service-worker/import-scripts-mime-types.https.html, DISABLE
+service-worker/import-scripts-redirect.https.html, DISABLE
+service-worker/import-scripts-resource-map.https.html, DISABLE
+service-worker/import-scripts-updated-flag.https.html, DISABLE
+service-worker/same-site-cookies.https.html, DISABLE
+
+# b/265844662
+service-worker/interface-requirements-sw.https.html, DISABLE
+
+# b/265847846
+service-worker/navigate-window.https.html, DISABLE
+
+# b/267230419 Error type incorrect
+service-worker/registration-script.https.html, DISABLE
+
+# broken on Chrome
+service-worker/credentials.https.html, DISABLE
+service-worker/navigation-redirect-body.https.html, DISABLE
+service-worker/navigation-sets-cookie.https.html, DISABLE
+service-worker/registration-mime-types.https.html, DISABLE
+service-worker/registration-scope.https.html, DISABLE
+service-worker/update-bytecheck-cors-import.https.html, DISABLE
+service-worker/update-bytecheck.https.html, DISABLE
+service-worker/referrer-toplevel-script-fetch.https.html, DISABLE
+
+# b/264323329 TIMEOUT
+service-worker/install-event-type.https.html, DISABLE
+service-worker/oninstall-script-error.https.html, DISABLE
+service-worker/onactivate-script-error.https.html, DISABLE
+service-worker/postmessage-blob-url.https.html, DISABLE
+service-worker/unregister-immediately-before-installed.https.html, DISABLE
+service-worker/update-not-allowed.https.html, DISABLE
+
+# b/265981629
+service-worker/registration-service-worker-attributes.https.html, DISABLE
+
+# b/265983449
+service-worker/synced-state.https.html, DISABLE
+
+# websocket is not supported in Cobalt
+service-worker/websocket-in-service-worker.https.html, DISABLE
+
+# iframe is not supported in Cobalt
+service-worker/about-blank-replacement.https.html, DISABLE
 service-worker/activation.https.html, DISABLE
 service-worker/active.https.html, DISABLE
 service-worker/claim-affect-other-registration.https.html, DISABLE
@@ -14,6 +109,7 @@
 service-worker/claim-worker-fetch.https.html, DISABLE
 service-worker/client-id.https.html, DISABLE
 service-worker/client-navigate.https.html, DISABLE
+service-worker/client-url-of-blob-url-worker.https.html, DISABLE
 service-worker/clients-get-client-types.https.html, DISABLE
 service-worker/clients-get-cross-origin.https.html, DISABLE
 service-worker/clients-get.https.html, DISABLE
@@ -21,24 +117,19 @@
 service-worker/clients-matchall-blob-url-worker.https.html, DISABLE
 service-worker/clients-matchall-client-types.https.html, DISABLE
 service-worker/clients-matchall-exact-controller.https.html, DISABLE
-service-worker/clients-matchall-frozen.https.html, DISABLE
 service-worker/clients-matchall.https.html, DISABLE
 service-worker/clients-matchall-include-uncontrolled.https.html, DISABLE
-service-worker/clients-matchall-on-evaluation.https.html, DISABLE
 service-worker/clients-matchall-order.https.html, DISABLE
-service-worker/client-url-of-blob-url-worker.https.html, DISABLE
+service-worker/clients-matchall.https.html, DISABLE
 service-worker/controller-on-disconnect.https.html, DISABLE
 service-worker/controller-on-load.https.html, DISABLE
 service-worker/controller-on-reload.https.html, DISABLE
 service-worker/controller-with-no-fetch-event-handler.https.html, DISABLE
-service-worker/credentials.https.html, DISABLE
 service-worker/data-iframe.html, DISABLE
 service-worker/data-transfer-files.https.html, DISABLE
-service-worker/dedicated-worker-service-worker-interception.https.html, DISABLE
 service-worker/detached-context.https.html, DISABLE
 service-worker/embed-and-object-are-not-intercepted.https.html, DISABLE
 service-worker/extendable-event-async-waituntil.https.html, DISABLE
-service-worker/extendable-event-waituntil.https.html, DISABLE
 service-worker/fetch-audio-tainting.https.html, DISABLE
 service-worker/fetch-canvas-tainting-double-write.https.html, DISABLE
 service-worker/fetch-canvas-tainting-image-cache.https.html, DISABLE
@@ -50,16 +141,12 @@
 service-worker/fetch-cors-xhr.https.html, DISABLE
 service-worker/fetch-csp.https.html, DISABLE
 service-worker/fetch-error.https.html, DISABLE
-service-worker/fetch-event-add-async.https.html, DISABLE
 service-worker/fetch-event-after-navigation-within-page.https.html, DISABLE
 service-worker/fetch-event-async-respond-with.https.html, DISABLE
 service-worker/fetch-event-handled.https.html, DISABLE
 service-worker/fetch-event.https.h2.html, DISABLE
 service-worker/fetch-event.https.html, DISABLE
-service-worker/fetch-event-is-history-backward-navigation-manual.https.html, DISABLE
-service-worker/fetch-event-is-history-forward-navigation-manual.https.html, DISABLE
 service-worker/fetch-event-is-reload-iframe-navigation-manual.https.html, DISABLE
-service-worker/fetch-event-is-reload-navigation-manual.https.html, DISABLE
 service-worker/fetch-event-network-error.https.html, DISABLE
 service-worker/fetch-event-redirect.https.html, DISABLE
 service-worker/fetch-event-referrer-policy.https.html, DISABLE
@@ -97,16 +184,7 @@
 service-worker/global-serviceworker.https.any.js, DISABLE
 service-worker/historical.https.any.js, DISABLE
 service-worker/http-to-https-redirect-and-register.https.html, DISABLE
-service-worker/immutable-prototype-serviceworker.https.html, DISABLE
-service-worker/import-scripts-cross-origin.https.html, DISABLE
-service-worker/import-scripts-mime-types.https.html, DISABLE
-service-worker/import-scripts-redirect.https.html, DISABLE
-service-worker/import-scripts-resource-map.https.html, DISABLE
-service-worker/import-scripts-updated-flag.https.html, DISABLE
-service-worker/indexeddb.https.html, DISABLE
-service-worker/install-event-type.https.html, DISABLE
 service-worker/installing.https.html, DISABLE
-service-worker/interface-requirements-sw.https.html, DISABLE
 service-worker/invalid-blobtype.https.html, DISABLE
 service-worker/invalid-header.https.html, DISABLE
 service-worker/iso-latin1-header.https.html, DISABLE
@@ -115,23 +193,17 @@
 service-worker/multi-globals, DISABLE
 service-worker/multipart-image.https.html, DISABLE
 service-worker/multiple-register.https.html, DISABLE
-service-worker/multiple-update.https.html, DISABLE
-service-worker/navigate-window.https.html, DISABLE
 service-worker/navigation-headers.https.html, DISABLE
 service-worker/navigation-preload, DISABLE
-service-worker/navigation-redirect-body.https.html, DISABLE
 service-worker/navigation-redirect.https.html, DISABLE
 service-worker/navigation-redirect-resolution.https.html, DISABLE
 service-worker/navigation-redirect-to-http.https.html, DISABLE
-service-worker/navigation-sets-cookie.https.html, DISABLE
 service-worker/navigation-timing-extended.https.html, DISABLE
 service-worker/navigation-timing.https.html, DISABLE
 service-worker/nested-blob-url-workers.https.html, DISABLE
 service-worker/next-hop-protocol.https.html, DISABLE
 service-worker/no-dynamic-import.any.js, DISABLE
 service-worker/no-dynamic-import-in-module.any.js, DISABLE
-service-worker/onactivate-script-error.https.html, DISABLE
-service-worker/oninstall-script-error.https.html, DISABLE
 service-worker/opaque-response-preloaded.https.html, DISABLE
 service-worker/opaque-script.https.html, DISABLE
 service-worker/partitioned-claim.tentative.https.html, DISABLE
@@ -139,9 +211,7 @@
 service-worker/partitioned-matchAll.tentative.https.html, DISABLE
 service-worker/partitioned.tentative.https.html, DISABLE
 service-worker/performance-timeline.https.html, DISABLE
-service-worker/postmessage-blob-url.https.html, DISABLE
 service-worker/postmessage-from-waiting-serviceworker.https.html, DISABLE
-service-worker/postmessage.https.html, DISABLE
 service-worker/postmessage-msgport-to-client.https.html, DISABLE
 service-worker/postmessage-to-client.https.html, DISABLE
 service-worker/postmessage-to-client-message-queue.https.html, DISABLE
@@ -149,55 +219,26 @@
 service-worker/redirected-response.https.html, DISABLE
 service-worker/referer.https.html, DISABLE
 service-worker/referrer-policy-header.https.html, DISABLE
-service-worker/referrer-toplevel-script-fetch.https.html, DISABLE
 service-worker/register-closed-window.https.html, DISABLE
-service-worker/register-default-scope.https.html, PASS
 service-worker/register-same-scope-different-script-url.https.html, DISABLE
-service-worker/register-wait-forever-in-install-worker.https.html, DISABLE
-service-worker/registration-basic.https.html, DISABLE
-service-worker/registration-end-to-end.https.html, DISABLE
-service-worker/registration-events.https.html, DISABLE
 service-worker/registration-iframe.https.html, DISABLE
-service-worker/registration-mime-types.https.html, DISABLE
-service-worker/registration-schedule-job.https.html, DISABLE
-service-worker/registration-scope.https.html, DISABLE
-service-worker/registration-scope-module-static-import.https.html, DISABLE
-service-worker/registration-script.https.html, DISABLE
-service-worker/registration-script-module.https.html, DISABLE
-service-worker/registration-script-url.https.html, DISABLE
-service-worker/registration-security-error.https.html, DISABLE
-service-worker/registration-service-worker-attributes.https.html, DISABLE
 service-worker/registration-updateviacache.https.html, DISABLE
-service-worker/rejections.https.html, PASS
 service-worker/request-end-to-end.https.html, DISABLE
 service-worker/resource-timing-bodySize.https.html, DISABLE
 service-worker/resource-timing-cross-origin.https.html, DISABLE
 service-worker/resource-timing-fetch-variants.https.html, DISABLE
 service-worker/resource-timing.sub.https.html, DISABLE
 service-worker/respond-with-body-accessed-response.https.html, DISABLE
-service-worker/same-site-cookies.https.html, DISABLE
 service-worker/sandboxed-iframe-fetch-event.https.html, DISABLE
 service-worker/sandboxed-iframe-navigator-serviceworker.https.html, DISABLE
 service-worker/secure-context.https.html, DISABLE
-service-worker/Service-Worker-Allowed-header.https.html, DISABLE
-service-worker/service-worker-csp-connect.https.html, DISABLE
-service-worker/service-worker-csp-default.https.html, DISABLE
-service-worker/service-worker-csp-script.https.html, DISABLE
-service-worker/service-worker-header.https.html, DISABLE
 service-worker/serviceworker-message-event-historical.https.html, DISABLE
-service-worker/serviceworkerobject-scripturl.https.html, PASS
 service-worker/skip-waiting.https.html, DISABLE
 service-worker/skip-waiting-installed.https.html, DISABLE
 service-worker/skip-waiting-using-registration.https.html, DISABLE
-service-worker/skip-waiting-without-client.https.html, DISABLE
 service-worker/skip-waiting-without-using-registration.https.html, DISABLE
-service-worker/state.https.html, DISABLE
 service-worker/svg-target-reftest.https.html, DISABLE
-service-worker/synced-state.https.html, DISABLE
-service-worker/uncontrolled-page.https.html, DISABLE
 service-worker/unregister-controller.https.html, DISABLE
-service-worker/unregister.https.html, PASS
-service-worker/unregister-immediately-before-installed.https.html, DISABLE
 service-worker/unregister-immediately-during-extendable-events.https.html, DISABLE
 service-worker/unregister-immediately.https.html, DISABLE
 service-worker/unregister-then-register.https.html, DISABLE
@@ -205,27 +246,17 @@
 service-worker/update-after-navigation-fetch-event.https.html, DISABLE
 service-worker/update-after-navigation-redirect.https.html, DISABLE
 service-worker/update-after-oneday.https.html, DISABLE
-service-worker/update-bytecheck-cors-import.https.html, DISABLE
-service-worker/update-bytecheck.https.html, DISABLE
 service-worker/update.https.html, DISABLE
 service-worker/update-import-scripts.https.html, DISABLE
-service-worker/update-missing-import-scripts.https.html, DISABLE
-service-worker/update-module-request-mode.https.html, DISABLE
-service-worker/update-no-cache-request-headers.https.html, DISABLE
-service-worker/update-not-allowed.https.html, DISABLE
 service-worker/pdate-on-navigation.https.html, DISABLE
 service-worker/update-recovery.https.html, DISABLE
-service-worker/update-registration-with-type.https.html, DISABLE
-service-worker/update-result.https.html, DISABLE
 service-worker/waiting.https.html, DISABLE
 service-worker/websocket.https.html, DISABLE
-service-worker/websocket-in-service-worker.https.html, DISABLE
 service-worker/webvtt-cross-origin.https.html, DISABLE
 service-worker/windowclient-navigate.https.html, DISABLE
 service-worker/worker-client-id.https.html, DISABLE
 service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html, DISABLE
 service-worker/worker-interception.https.html, DISABLE
 service-worker/worker-interception-redirect.https.html, DISABLE
-service-worker/xhr-content-length.https.window.js, DISABLE
 service-worker/xhr-response-url.https.html, DISABLE
 service-worker/xsl-base-url.https.html, DISABLE
diff --git a/cobalt/layout_tests/testdata/web-platform-tests/workers/web_platform_tests.txt b/cobalt/layout_tests/testdata/web-platform-tests/workers/web_platform_tests.txt
index 0c20d9a..7845616 100644
--- a/cobalt/layout_tests/testdata/web-platform-tests/workers/web_platform_tests.txt
+++ b/cobalt/layout_tests/testdata/web-platform-tests/workers/web_platform_tests.txt
@@ -5,7 +5,9 @@
 # features that are expected to currently work.
 
 Worker_basic.htm, PASS
-Worker_dispatchEvent_ErrorEvent.htm, PASS
+
+# b/266711887 SIGSEGV
+Worker_dispatchEvent_ErrorEvent.htm, DISABLE
 
 # b/225037465
 Worker_cross_origin_security_err.htm, DISABLE
diff --git a/cobalt/layout_tests/web_platform_tests.cc b/cobalt/layout_tests/web_platform_tests.cc
index 860755a..ac6e3fd 100644
--- a/cobalt/layout_tests/web_platform_tests.cc
+++ b/cobalt/layout_tests/web_platform_tests.cc
@@ -55,21 +55,22 @@
  public:
   CspDelegatePermissive(
       std::unique_ptr<web::CspViolationReporter> violation_reporter,
-      const GURL& url, csp::CSPHeaderPolicy require_csp,
+      const GURL& url, csp::CSPHeaderPolicy csp_header_policy,
       const base::Closure& policy_changed_callback)
-      : web::CspDelegateSecure(std::move(violation_reporter), url, require_csp,
-                               policy_changed_callback) {
+      : web::CspDelegateSecure(std::move(violation_reporter), url,
+                               csp_header_policy, policy_changed_callback) {
     // Lies, but some checks in our parent require this.
     was_header_received_ = true;
   }
 
   static CspDelegate* Create(
       std::unique_ptr<web::CspViolationReporter> violation_reporter,
-      const GURL& url, csp::CSPHeaderPolicy require_csp,
+      const GURL& url, csp::CSPHeaderPolicy csp_header_policy,
       const base::Closure& policy_changed_callback,
       int insecure_allowed_token) {
     return new CspDelegatePermissive(std::move(violation_reporter), url,
-                                     require_csp, policy_changed_callback);
+                                     csp_header_policy,
+                                     policy_changed_callback);
   }
 
   bool OnReceiveHeaders(const csp::ResponseHeaders& headers) override {
@@ -196,6 +197,7 @@
   // Network module
   network::NetworkModule::Options net_options;
   net_options.https_requirement = network::kHTTPSOptional;
+  net_options.ignore_certificate_errors = true;
   std::string custom_proxy =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII("proxy");
   if (!custom_proxy.empty()) net_options.custom_proxy = custom_proxy;
@@ -232,7 +234,8 @@
   // Create Service Worker Registry
   browser::ServiceWorkerRegistry* service_worker_registry =
       new browser::ServiceWorkerRegistry(&web_settings, &network_module,
-                                         new browser::UserAgentPlatformInfo());
+                                         new browser::UserAgentPlatformInfo(),
+                                         url);
   web_module_options.web_options.service_worker_jobs =
       service_worker_registry->service_worker_jobs();
 
diff --git a/cobalt/loader/BUILD.gn b/cobalt/loader/BUILD.gn
index 8d50f70..2db902d 100644
--- a/cobalt/loader/BUILD.gn
+++ b/cobalt/loader/BUILD.gn
@@ -116,6 +116,7 @@
     "//cobalt/renderer/test/png_utils",
     "//cobalt/web",
     "//nb",
+    "//net",
     "//third_party/libjpeg-turbo:libjpeg",
     "//third_party/libpng",
     "//third_party/libwebp",
diff --git a/cobalt/loader/cors_preflight.cc b/cobalt/loader/cors_preflight.cc
index eb3b70a..53e501d 100644
--- a/cobalt/loader/cors_preflight.cc
+++ b/cobalt/loader/cors_preflight.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "cobalt/loader/cors_preflight.h"
+
 #include <algorithm>
 #include <cstring>
 #include <iterator>
@@ -23,7 +25,6 @@
 #include "base/basictypes.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "cobalt/loader/cors_preflight.h"
 #include "starboard/common/string.h"
 
 namespace cobalt {
@@ -412,17 +413,17 @@
   size_t iter = 0;
   if (!response_headers.EnumerateHeader(&iter, kAccessControlAllowOrigin,
                                         &allowed_origin)) {
-    DLOG(WARNING) << "Insecure cross-origin network request returned response "
-                     "with no Access-Control-Allow-Origin header. Request "
-                     "aborted.";
+    LOG(WARNING) << "Insecure cross-origin network request returned response "
+                    "with no Access-Control-Allow-Origin header. Request "
+                    "aborted: ";
     return false;
   }
   DCHECK(iter);
   if (response_headers.EnumerateHeader(&iter, kAccessControlAllowOrigin,
                                        &empty_container)) {
-    DLOG(WARNING) << "Insecure cross-origin network request returned response "
-                     "with multiple Access-Control-Allow-Origin headers. "
-                     "Behavior disallowed and request aborted";
+    LOG(WARNING) << "Insecure cross-origin network request returned response "
+                    "with multiple Access-Control-Allow-Origin headers. "
+                    "Behavior disallowed and request aborted: ";
     return false;
   }
   // 3. If request's credentials mode is not "include" and origin is `*`, return
@@ -432,13 +433,14 @@
   }
   // 2. If origin is null or failure, return failure.
   if (allowed_origin.empty()) {
+    LOG(WARNING) << "CORS check failed: Origin is null or failure.";
     return false;
   }
   // 4. If request's origin, serialized and UTF-8 encoded, is not origin, return
   //    failure.
   if (allowed_origin != serialized_origin) {
-    DLOG(WARNING) << "Network request origin is not allowed by server's "
-                     "Access-Control-Allow-Origin header, request aborted.";
+    LOG(WARNING) << "Network request origin is not allowed by server's "
+                    "Access-Control-Allow-Origin header, request aborted.";
     return false;
   }
   // 5. If request's credentials mode is not "include", return success.
@@ -451,7 +453,7 @@
                                            &allow_credentials)) {
     // 7. If credentials is `true`, return success.
     if (allow_credentials != "true") {
-      DLOG(WARNING)
+      LOG(WARNING)
           << "Network request failed because request want to include credential"
              "but server disallow it.";
       return false;
@@ -459,6 +461,7 @@
       return true;
     }
   }
+  LOG(WARNING) << "CORS check failed.";
   return false;
 }
 
diff --git a/cobalt/loader/fetch_interceptor_coordinator.cc b/cobalt/loader/fetch_interceptor_coordinator.cc
index fc2e8e8..a7599fc 100644
--- a/cobalt/loader/fetch_interceptor_coordinator.cc
+++ b/cobalt/loader/fetch_interceptor_coordinator.cc
@@ -37,27 +37,39 @@
 
 
 void FetchInterceptorCoordinator::TryIntercept(
-    const GURL& url,
-    std::unique_ptr<base::OnceCallback<void(std::unique_ptr<std::string>)>>
-        callback,
-    std::unique_ptr<base::OnceCallback<void(const net::LoadTimingInfo&)>>
+    const GURL& url, bool main_resource,
+    const net::HttpRequestHeaders& request_headers,
+    scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+    base::OnceCallback<void(std::unique_ptr<std::string>)> callback,
+    base::OnceCallback<void(const net::LoadTimingInfo&)>
         report_load_timing_info,
-    std::unique_ptr<base::OnceClosure> fallback) {
+    base::OnceClosure fallback) {
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#handle-fetch
-  // Steps 17 to 23
-  // TODO: add should skip event handling
-  // (https://w3c.github.io/ServiceWorker/#should-skip-event).
-  // TODO: determine |shouldSoftUpdate| and if true run soft update in parallel
-  // (https://w3c.github.io/ServiceWorker/#soft-update).
+
   if (!fetch_interceptor_) {
-    std::move(*fallback).Run();
+    std::move(fallback).Run();
     return;
   }
+  // Steps 17 to 23
+  // TODO: add should skip event handling
+  // (https://www.w3.org/TR/2022/CRD-service-workers-20220712/#should-skip-event).
+
+  // 18. Let shouldSoftUpdate be true if any of the following are true, and
+  //     false otherwise:
+  //      . request is a non-subresource request.
+  // Note: check if destination is: "document", "embed", "frame", "iframe",
+  // "object", "report", "serviceworker", "sharedworker", or "worker".
+  //
+  //      . request is a subresource request and registration is stale.
+  // Note: check if destination is "audio", "audioworklet", "font", "image",
+  // "manifest", "paintworklet", "script", "style", "track", "video", "xslt"
+
   // TODO: test interception once registered service workers are persisted.
   //       Consider moving the interception out of the ServiceWorkerGlobalScope
   //       to avoid a race condition. Fetches should be able to be intercepted
   //       by an active, registered, service worker.
-  fetch_interceptor_->StartFetch(url, std::move(callback),
+  fetch_interceptor_->StartFetch(url, main_resource, request_headers,
+                                 callback_task_runner, std::move(callback),
                                  std::move(report_load_timing_info),
                                  std::move(fallback));
 }
diff --git a/cobalt/loader/fetch_interceptor_coordinator.h b/cobalt/loader/fetch_interceptor_coordinator.h
index 13eb373..b266807 100644
--- a/cobalt/loader/fetch_interceptor_coordinator.h
+++ b/cobalt/loader/fetch_interceptor_coordinator.h
@@ -19,7 +19,9 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/single_thread_task_runner.h"
 #include "net/base/load_timing_info.h"
+#include "net/http/http_request_headers.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -33,12 +35,13 @@
 class FetchInterceptor {
  public:
   virtual void StartFetch(
-      const GURL& url,
-      std::unique_ptr<base::OnceCallback<void(std::unique_ptr<std::string>)>>
-          callback,
-      std::unique_ptr<base::OnceCallback<void(const net::LoadTimingInfo&)>>
+      const GURL& url, bool main_resource,
+      const net::HttpRequestHeaders& request_headers,
+      scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+      base::OnceCallback<void(std::unique_ptr<std::string>)> callback,
+      base::OnceCallback<void(const net::LoadTimingInfo&)>
           report_load_timing_info,
-      std::unique_ptr<base::OnceClosure> fallback) = 0;
+      base::OnceClosure fallback) = 0;
 };
 
 // NetFetcher is for fetching data from the network.
@@ -53,12 +56,13 @@
   void Clear() { fetch_interceptor_ = nullptr; }
 
   void TryIntercept(
-      const GURL& url,
-      std::unique_ptr<base::OnceCallback<void(std::unique_ptr<std::string>)>>
-          callback,
-      std::unique_ptr<base::OnceCallback<void(const net::LoadTimingInfo&)>>
+      const GURL& url, bool main_resource,
+      const net::HttpRequestHeaders& request_headers,
+      scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+      base::OnceCallback<void(std::unique_ptr<std::string>)> callback,
+      base::OnceCallback<void(const net::LoadTimingInfo&)>
           report_load_timing_info,
-      std::unique_ptr<base::OnceClosure> fallback);
+      base::OnceClosure fallback);
 
  private:
   friend struct base::DefaultSingletonTraits<FetchInterceptorCoordinator>;
diff --git a/cobalt/loader/fetcher_cache.cc b/cobalt/loader/fetcher_cache.cc
index 9b0244f..8d6b707 100644
--- a/cobalt/loader/fetcher_cache.cc
+++ b/cobalt/loader/fetcher_cache.cc
@@ -14,6 +14,8 @@
 
 #include "cobalt/loader/fetcher_cache.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
@@ -300,8 +302,15 @@
   if (data->size() <= capacity_) {
     auto entry = new CacheEntry(headers, last_url_origin,
                                 did_fail_from_transient_error, data);
+
+    bool inserted = cache_entries_.insert(std::make_pair(url, entry)).second;
+    if (!inserted) {
+      // The resource is already cached.
+      delete entry;
+      return;
+    }
+
     total_size_ += entry->capacity();
-    cache_entries_.insert(std::make_pair(url, entry));
     while (total_size_ > capacity_) {
       DCHECK(!cache_entries_.empty());
       total_size_ -= cache_entries_.begin()->second->capacity();
diff --git a/cobalt/loader/fetcher_factory.cc b/cobalt/loader/fetcher_factory.cc
index d938046..89322cd 100644
--- a/cobalt/loader/fetcher_factory.cc
+++ b/cobalt/loader/fetcher_factory.cc
@@ -84,15 +84,17 @@
       read_cache_callback_(read_cache_callback) {}
 
 std::unique_ptr<Fetcher> FetcherFactory::CreateFetcher(
-    const GURL& url, const disk_cache::ResourceType type,
+    const GURL& url, bool main_resource, const disk_cache::ResourceType type,
     Fetcher::Handler* handler) {
-  return CreateSecureFetcher(url, csp::SecurityCallback(), kNoCORSMode,
-                             Origin(), type, net::HttpRequestHeaders(),
+  return CreateSecureFetcher(url, main_resource, csp::SecurityCallback(),
+                             kNoCORSMode, Origin(), type,
+                             net::HttpRequestHeaders(),
                              /*skip_fetch_intercept=*/false, handler);
 }
 
 std::unique_ptr<Fetcher> FetcherFactory::CreateSecureFetcher(
-    const GURL& url, const csp::SecurityCallback& url_security_callback,
+    const GURL& url, bool main_resource,
+    const csp::SecurityCallback& url_security_callback,
     RequestMode request_mode, const Origin& origin,
     const disk_cache::ResourceType type, net::HttpRequestHeaders headers,
     bool skip_fetch_intercept, Fetcher::Handler* handler) {
@@ -112,8 +114,8 @@
     options.headers = std::move(headers);
     options.skip_fetch_intercept = skip_fetch_intercept;
     return std::unique_ptr<Fetcher>(
-        new NetFetcher(url, url_security_callback, handler, network_module_,
-                       options, request_mode, origin));
+        new NetFetcher(url, main_resource, url_security_callback, handler,
+                       network_module_, options, request_mode, origin));
   }
 
   if (url.SchemeIs("blob") && !blob_resolver_.is_null()) {
diff --git a/cobalt/loader/fetcher_factory.h b/cobalt/loader/fetcher_factory.h
index cb46a6a..7cff2d8 100644
--- a/cobalt/loader/fetcher_factory.h
+++ b/cobalt/loader/fetcher_factory.h
@@ -50,12 +50,13 @@
           base::Callback<int(const std::string&, std::unique_ptr<char[]>*)>());
 
   // Creates a fetcher. Returns NULL if the creation fails.
-  std::unique_ptr<Fetcher> CreateFetcher(const GURL& url,
+  std::unique_ptr<Fetcher> CreateFetcher(const GURL& url, bool main_resource,
                                          const disk_cache::ResourceType type,
                                          Fetcher::Handler* handler);
 
   std::unique_ptr<Fetcher> CreateSecureFetcher(
-      const GURL& url, const csp::SecurityCallback& url_security_callback,
+      const GURL& url, bool main_resource,
+      const csp::SecurityCallback& url_security_callback,
       RequestMode request_mode, const Origin& origin,
       const disk_cache::ResourceType type, net::HttpRequestHeaders headers,
       bool skip_fetch_intercept, Fetcher::Handler* handler);
diff --git a/cobalt/loader/fetcher_factory_test.cc b/cobalt/loader/fetcher_factory_test.cc
index 9767e69..1f579db 100644
--- a/cobalt/loader/fetcher_factory_test.cc
+++ b/cobalt/loader/fetcher_factory_test.cc
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "cobalt/loader/fetcher_factory.h"
+
 #include <memory>
 #include <string>
 
 #include "base/optional.h"
 #include "base/run_loop.h"
-#include "cobalt/loader/fetcher_factory.h"
 #include "cobalt/loader/file_fetcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -83,7 +84,8 @@
   StubFetcherHandler stub_fetcher_handler(&run_loop);
 
   fetcher_ = fetcher_factory_.CreateFetcher(
-      GURL("invalid-url"), disk_cache::kOther, &stub_fetcher_handler);
+      GURL("invalid-url"), /*main_resource=*/false, disk_cache::kOther,
+      &stub_fetcher_handler);
   EXPECT_TRUE(fetcher_);
 
   run_loop.Run();
@@ -95,8 +97,9 @@
   base::RunLoop run_loop;
   StubFetcherHandler stub_fetcher_handler(&run_loop);
 
-  fetcher_ = fetcher_factory_.CreateFetcher(
-      GURL("file:///"), disk_cache::kOther, &stub_fetcher_handler);
+  fetcher_ =
+      fetcher_factory_.CreateFetcher(GURL("file:///"), /*main_resource=*/false,
+                                     disk_cache::kOther, &stub_fetcher_handler);
   EXPECT_TRUE(fetcher_);
 
   run_loop.Run();
@@ -109,7 +112,8 @@
   StubFetcherHandler stub_fetcher_handler(&run_loop);
 
   fetcher_ = fetcher_factory_.CreateFetcher(
-      GURL("file://file.txt"), disk_cache::kOther, &stub_fetcher_handler);
+      GURL("file://file.txt"), /*main_resource=*/false, disk_cache::kOther,
+      &stub_fetcher_handler);
   EXPECT_TRUE(fetcher_);
 
   run_loop.Run();
@@ -124,14 +128,14 @@
   base::RunLoop run_loop;
   StubFetcherHandler stub_fetcher_handler(&run_loop);
 
-  fetcher_ =
-      fetcher_factory_.CreateFetcher(GURL("file:///nonempty-url-1"),
-                                     disk_cache::kOther, &stub_fetcher_handler);
+  fetcher_ = fetcher_factory_.CreateFetcher(
+      GURL("file:///nonempty-url-1"), /*main_resource=*/false,
+      disk_cache::kOther, &stub_fetcher_handler);
   EXPECT_TRUE(fetcher_);
 
-  fetcher_ =
-      fetcher_factory_.CreateFetcher(GURL("file:///nonempty-url-2"),
-                                     disk_cache::kOther, &stub_fetcher_handler);
+  fetcher_ = fetcher_factory_.CreateFetcher(
+      GURL("file:///nonempty-url-2"), /*main_resource=*/false,
+      disk_cache::kOther, &stub_fetcher_handler);
   EXPECT_TRUE(fetcher_);
   run_loop.Run();
   EXPECT_EQ(fetcher_.get(), stub_fetcher_handler.fetcher());
diff --git a/cobalt/loader/net_fetcher.cc b/cobalt/loader/net_fetcher.cc
index 5d96aee..7f43139 100644
--- a/cobalt/loader/net_fetcher.cc
+++ b/cobalt/loader/net_fetcher.cc
@@ -91,7 +91,7 @@
 
 }  // namespace
 
-NetFetcher::NetFetcher(const GURL& url,
+NetFetcher::NetFetcher(const GURL& url, bool main_resource,
                        const csp::SecurityCallback& security_callback,
                        Handler* handler,
                        const network::NetworkModule* network_module,
@@ -105,7 +105,9 @@
       origin_(origin),
       request_script_(options.resource_type == disk_cache::kUncompiledScript),
       task_runner_(base::MessageLoop::current()->task_runner()),
-      skip_fetch_intercept_(options.skip_fetch_intercept) {
+      skip_fetch_intercept_(options.skip_fetch_intercept),
+      will_destroy_current_message_loop_(false),
+      main_resource_(main_resource) {
   url_fetcher_ = net::URLFetcher::Create(url, options.request_method, this);
   if (!options.headers.IsEmpty()) {
     url_fetcher_->SetExtraRequestHeaders(options.headers.ToString());
@@ -138,6 +140,11 @@
   // while a loader is still being constructed.
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE, start_callback_.callback());
+  base::MessageLoop::current()->AddDestructionObserver(this);
+}
+
+void NetFetcher::WillDestroyCurrentMessageLoop() {
+  will_destroy_current_message_loop_.store(true);
 }
 
 void NetFetcher::Start() {
@@ -152,16 +159,11 @@
       return;
     }
     FetchInterceptorCoordinator::GetInstance()->TryIntercept(
-        original_url,
-        std::make_unique<
-            base::OnceCallback<void(std::unique_ptr<std::string>)>>(
-            base::BindOnce(&NetFetcher::OnFetchIntercepted,
-                           base::Unretained(this))),
-        std::make_unique<base::OnceCallback<void(const net::LoadTimingInfo&)>>(
-            base::BindOnce(&NetFetcher::ReportLoadTimingInfo,
-                           base::Unretained(this))),
-        std::make_unique<base::OnceClosure>(base::BindOnce(
-            &net::URLFetcher::Start, base::Unretained(url_fetcher_.get()))));
+        original_url, main_resource_, url_fetcher_->GetRequestHeaders(),
+        task_runner_,
+        base::BindOnce(&NetFetcher::OnFetchIntercepted, AsWeakPtr()),
+        base::BindOnce(&NetFetcher::ReportLoadTimingInfo, AsWeakPtr()),
+        base::BindOnce(&NetFetcher::InterceptFallback, AsWeakPtr()));
 
   } else {
     std::string msg(base::StringPrintf("URL %s rejected by security policy.",
@@ -170,7 +172,12 @@
   }
 }
 
+void NetFetcher::InterceptFallback() { url_fetcher_->Start(); }
+
 void NetFetcher::OnFetchIntercepted(std::unique_ptr<std::string> body) {
+  if (will_destroy_current_message_loop_.load()) {
+    return;
+  }
   if (task_runner_ != base::MessageLoop::current()->task_runner()) {
     task_runner_->PostTask(
         FROM_HERE, base::BindOnce(&NetFetcher::OnFetchIntercepted,
@@ -307,6 +314,9 @@
 NetFetcher::~NetFetcher() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   start_callback_.Cancel();
+  if (!will_destroy_current_message_loop_.load()) {
+    base::MessageLoop::current()->RemoveDestructionObserver(this);
+  }
 }
 
 NetFetcher::ReturnWrapper NetFetcher::HandleError(const std::string& message) {
diff --git a/cobalt/loader/net_fetcher.h b/cobalt/loader/net_fetcher.h
index 3a6d3d8..f88baab 100644
--- a/cobalt/loader/net_fetcher.h
+++ b/cobalt/loader/net_fetcher.h
@@ -30,13 +30,17 @@
 #include "net/http/http_request_headers.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "starboard/atomic.h"
 #include "url/gurl.h"
 
 namespace cobalt {
 namespace loader {
 
 // NetFetcher is for fetching data from the network.
-class NetFetcher : public Fetcher, public net::URLFetcherDelegate {
+class NetFetcher : public Fetcher,
+                   public net::URLFetcherDelegate,
+                   public base::SupportsWeakPtr<NetFetcher>,
+                   public base::MessageLoopCurrent::DestructionObserver {
  public:
   struct Options {
    public:
@@ -50,8 +54,9 @@
     bool skip_fetch_intercept;
   };
 
-  NetFetcher(const GURL& url, const csp::SecurityCallback& security_callback,
-             Handler* handler, const network::NetworkModule* network_module,
+  NetFetcher(const GURL& url, bool main_resource,
+             const csp::SecurityCallback& security_callback, Handler* handler,
+             const network::NetworkModule* network_module,
              const Options& options, RequestMode request_mode,
              const Origin& origin);
   ~NetFetcher() override;
@@ -64,6 +69,9 @@
                                   int64_t current_network_bytes) override;
   void ReportLoadTimingInfo(const net::LoadTimingInfo& timing_info) override;
 
+  // base::MessageLoopCurrent::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
   void OnFetchIntercepted(std::unique_ptr<std::string> body);
 
   net::URLFetcher* url_fetcher() const {
@@ -79,6 +87,7 @@
   }
 
   void Start();
+  void InterceptFallback();
 
   // Empty struct to ensure the caller of |HandleError()| knows that |this|
   // may have been destroyed and handles it appropriately.
@@ -122,6 +131,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
   bool skip_fetch_intercept_;
+  starboard::atomic_bool will_destroy_current_message_loop_;
+  bool main_resource_;
 
   DISALLOW_COPY_AND_ASSIGN(NetFetcher);
 };
diff --git a/cobalt/loader/script_loader_factory.cc b/cobalt/loader/script_loader_factory.cc
index 97d096d..080b4a5 100644
--- a/cobalt/loader/script_loader_factory.cc
+++ b/cobalt/loader/script_loader_factory.cc
@@ -76,10 +76,10 @@
     bool skip_fetch_intercept) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  return base::Bind(&FetcherFactory::CreateSecureFetcher,
-                    base::Unretained(fetcher_factory_), url,
-                    url_security_callback, request_mode, origin, type,
-                    std::move(headers), skip_fetch_intercept);
+  return base::Bind(
+      &FetcherFactory::CreateSecureFetcher, base::Unretained(fetcher_factory_),
+      url, /*main_resource=*/false, url_security_callback, request_mode, origin,
+      type, std::move(headers), skip_fetch_intercept);
 }
 
 void ScriptLoaderFactory::OnLoaderCreated(Loader* loader) {
diff --git a/cobalt/media/BUILD.gn b/cobalt/media/BUILD.gn
index 1b27130..df2a214 100644
--- a/cobalt/media/BUILD.gn
+++ b/cobalt/media/BUILD.gn
@@ -28,6 +28,8 @@
   sources = [
     "base/audio_bus.cc",
     "base/audio_bus.h",
+    "base/cval_stats.cc",
+    "base/cval_stats.h",
     "base/data_source.cc",
     "base/data_source.h",
     "base/decode_target_provider.h",
@@ -111,6 +113,7 @@
   testonly = true
 
   sources = [
+    "base/cval_stats_test.cc",
     "file_data_source_test.cc",
     "progressive/demuxer_extension_wrapper_test.cc",
     "progressive/mock_data_source_reader.h",
diff --git a/cobalt/media/base/cval_stats.cc b/cobalt/media/base/cval_stats.cc
new file mode 100644
index 0000000..9ee4acf
--- /dev/null
+++ b/cobalt/media/base/cval_stats.cc
@@ -0,0 +1,129 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/media/base/cval_stats.h"
+
+#include <numeric>
+
+namespace cobalt {
+namespace media {
+
+CValContainer::CValContainer(std::string name,
+                             int max_samples_before_calculation)
+    : cval_name_{name},
+      max_samples_before_calculation_{max_samples_before_calculation},
+      latest_{"Media." + name + ".Latest", 0, "Latest sample in microseconds."},
+      average_{"Media." + name + ".Average", 0,
+               "Average sample in microseconds."},
+      maximum_{"Media." + name + ".Maximum", 0,
+               "Maximum sample in microseconds."},
+      median_{"Media." + name + ".Median", 0, "Median sample in microseconds."},
+      minimum_{"Media." + name + ".Minimum", 0,
+               "Minimum sample in microseconds."} {}
+
+void CValContainer::UpdateCVal(SbTime event_timing) {
+  latest_ = event_timing;
+  accumulated_sample_count_++;
+
+  if (!first_sample_added_) {
+    minimum_ = event_timing;
+    maximum_ = event_timing;
+    first_sample_added_ = true;
+  }
+
+  samples_[sample_write_index_] = event_timing;
+  sample_write_index_ = (sample_write_index_ + 1) % kMaxSamples;
+
+  if (accumulated_sample_count_ % max_samples_before_calculation_ == 0) {
+    std::vector<SbTime> copy;
+    int copy_size = std::min(accumulated_sample_count_, kMaxSamples);
+    copy.reserve(copy_size);
+    copy.assign(samples_, samples_ + copy_size);
+    std::sort(copy.begin(), copy.end());
+    if (copy.size() % 2 == 0) {
+      median_ = (copy[copy.size() / 2 - 1] + copy[copy.size() / 2]) / 2;
+    } else {
+      median_ = copy[copy.size() / 2];
+    }
+
+    minimum_ = std::min(minimum_.value(), copy[0]);
+    maximum_ = std::max(maximum_.value(), copy[copy.size() - 1]);
+
+    auto local_average = std::accumulate(copy.begin(), copy.end(), 0);
+    average_ += (local_average - average_.value()) / accumulated_sample_count_;
+  }
+}
+
+CValStats::CValStats() {
+  cval_containers_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(MediaTiming::SbPlayerCreate),
+      std::forward_as_tuple("SbPlayerCreateTime",
+                            kMediaDefaultMaxSamplesBeforeCalculation));
+  cval_containers_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(MediaTiming::SbPlayerDestroy),
+      std::forward_as_tuple("SbPlayerDestructionTime",
+                            kMediaDefaultMaxSamplesBeforeCalculation));
+  cval_containers_.emplace(
+      std::piecewise_construct,
+      std::forward_as_tuple(MediaTiming::SbPlayerWriteSamples),
+      std::forward_as_tuple("SbPlayerWriteSamplesTime",
+                            kMediaHighFrequencyMaxSamplesBeforeCalculation));
+}
+
+void CValStats::StartTimer(MediaTiming event_type,
+                           std::string pipeline_identifier) {
+  if (!enabled_) return;
+
+  running_timers_[std::make_pair(event_type, pipeline_identifier)] =
+      SbTimeGetMonotonicNow();
+}
+
+void CValStats::StopTimer(MediaTiming event_type,
+                          std::string pipeline_identifier) {
+  if (!enabled_) return;
+
+  auto key = std::make_pair(event_type, pipeline_identifier);
+  DCHECK(running_timers_.find(key) != running_timers_.end());
+
+  SbTime time_taken = SbTimeGetMonotonicNow() - running_timers_[key];
+  auto cval_container = cval_containers_.find(event_type);
+  if (cval_container != cval_containers_.end()) {
+    cval_container->second.UpdateCVal(time_taken);
+  }
+}
+
+// for testing only
+size_t CValStats::GetBufferIndexForTest() {
+  DCHECK(cval_containers_.size() > 0);
+  auto cval_container = cval_containers_.find(MediaTiming::SbPlayerCreate);
+  if (cval_container != cval_containers_.end()) {
+    return cval_container->second.GetSampleIndex();
+  }
+  return 0;
+}
+
+// for testing only
+size_t CValStats::GetBufferSampleSizeForTest() {
+  DCHECK(cval_containers_.size() > 0);
+  auto cval_container = cval_containers_.find(MediaTiming::SbPlayerCreate);
+  if (cval_container != cval_containers_.end()) {
+    return cval_container->second.GetNumberSamples();
+  }
+  return 0;
+}
+
+}  // namespace media
+}  // namespace cobalt
diff --git a/cobalt/media/base/cval_stats.h b/cobalt/media/base/cval_stats.h
new file mode 100644
index 0000000..2ae3099
--- /dev/null
+++ b/cobalt/media/base/cval_stats.h
@@ -0,0 +1,101 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_MEDIA_BASE_CVAL_STATS_H_
+#define COBALT_MEDIA_BASE_CVAL_STATS_H_
+
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "cobalt/base/c_val.h"
+
+
+namespace cobalt {
+namespace media {
+
+enum class MediaTiming {
+  SbPlayerCreate,
+  SbPlayerDestroy,
+  SbPlayerWriteSamples
+};
+
+// size of the sample array
+constexpr size_t kMaxSamples = 100;
+// number of samples taken before we trigger historical calculations
+constexpr int kMediaDefaultMaxSamplesBeforeCalculation = 5;
+constexpr int kMediaHighFrequencyMaxSamplesBeforeCalculation = 25;
+
+class CValContainer {
+ public:
+  CValContainer(std::string name, int max_samples_before_calculation);
+  ~CValContainer() = default;
+
+  void StartTimer();
+  void StopTimer();
+  void UpdateCVal(SbTime event_time);
+
+  // for testing only
+  size_t GetSampleIndex() { return sample_write_index_; }
+  size_t GetNumberSamples() {
+    return std::min(accumulated_sample_count_, kMaxSamples);
+  }
+
+ public:
+  int max_samples_before_calculation_{0};
+  std::string cval_name_;
+
+ private:
+  base::CVal<SbTime, base::CValPublic> latest_;
+  base::CVal<SbTime, base::CValPublic> average_;
+  base::CVal<SbTime, base::CValPublic> maximum_;
+  base::CVal<SbTime, base::CValPublic> median_;
+  base::CVal<SbTime, base::CValPublic> minimum_;
+
+  SbTime samples_[kMaxSamples];
+  size_t sample_write_index_{0};
+  size_t accumulated_sample_count_{0};
+  bool first_sample_added_{false};
+
+  SbTime latest_time_start_{0};
+  SbTime latest_time_stop_{0};
+};
+
+class CValStats {
+ public:
+  CValStats();
+  ~CValStats() = default;
+
+  void StartTimer(MediaTiming event_type, std::string pipeline_identifier);
+  void StopTimer(MediaTiming event_type, std::string pipeline_identifier);
+  void Enable(bool enabled) { enabled_ = enabled; }
+
+  // just for testing
+  size_t GetBufferIndexForTest();
+  size_t GetBufferSampleSizeForTest();
+
+ private:
+  std::map<MediaTiming, CValContainer> cval_containers_;
+  std::map<std::pair<MediaTiming, std::string>, SbTime> running_timers_;
+
+  bool enabled_{false};
+};
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_BASE_CVAL_STATS_H_
diff --git a/cobalt/media/base/cval_stats_test.cc b/cobalt/media/base/cval_stats_test.cc
new file mode 100644
index 0000000..673e20c
--- /dev/null
+++ b/cobalt/media/base/cval_stats_test.cc
@@ -0,0 +1,190 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <set>
+#include <string>
+
+#include "cobalt/media/base/cval_stats.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+const char kCValnameLatest[] = "Media.SbPlayerCreateTime.Latest";
+const char kCValnameAverage[] = "Media.SbPlayerCreateTime.Average";
+const char kCValnameMaximum[] = "Media.SbPlayerCreateTime.Maximum";
+const char kCValnameMedian[] = "Media.SbPlayerCreateTime.Median";
+const char kCValnameMinimum[] = "Media.SbPlayerCreateTime.Minimum";
+
+const char kPipelineIdentifier[] = "test_pipeline";
+
+constexpr int kSleepTimeMs = 50;
+
+namespace cobalt {
+namespace media {
+
+namespace {
+void sleep_ms(int ms) {
+#ifdef _WIN32
+  Sleep(ms);
+#else
+  usleep(ms);
+#endif
+}
+}  // namespace
+
+TEST(MediaCValStatsTest, InitiallyEmpty) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  std::set<std::string> cval_names = cvm->GetOrderedCValNames();
+  std::set<std::string>::size_type size = cval_names.size();
+  EXPECT_EQ(size, 0);
+}
+
+TEST(MediaCValStatsTest, CValStatsCreation) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+  std::set<std::string> cval_names = cvm->GetOrderedCValNames();
+  std::set<std::string>::size_type size = cval_names.size();
+  EXPECT_EQ(size, 15);
+}
+
+TEST(MediaCValStatsTest, NothingRecorded) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  sleep_ms(kSleepTimeMs);
+  cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+
+  base::Optional<std::string> result =
+      cvm->GetValueAsPrettyString(kCValnameLatest);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(*result, "0");
+}
+
+TEST(MediaCValStatsTest, EnableRecording) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.Enable(true);
+
+  cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  sleep_ms(kSleepTimeMs);
+  cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+
+  base::Optional<std::string> result =
+      cvm->GetValueAsPrettyString(kCValnameLatest);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+
+  result = cvm->GetValueAsPrettyString(kCValnameMinimum);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+
+  result = cvm->GetValueAsPrettyString(kCValnameMaximum);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+}
+
+TEST(MediaCValStatsTest, DontGenerateHistoricalData) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.Enable(true);
+
+  for (int i = 0; i < kMediaDefaultMaxSamplesBeforeCalculation - 1; i++) {
+    cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+    sleep_ms(kSleepTimeMs);
+    cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  }
+
+  base::Optional<std::string> result =
+      cvm->GetValueAsPrettyString(kCValnameLatest);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+
+  result = cvm->GetValueAsPrettyString(kCValnameAverage);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(*result, "0");
+
+  result = cvm->GetValueAsPrettyString(kCValnameMedian);
+  EXPECT_TRUE(result);
+  EXPECT_EQ(*result, "0");
+}
+
+TEST(MediaCValStatsTest, GenerateHistoricalData) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.Enable(true);
+
+  for (int i = 0; i < kMediaDefaultMaxSamplesBeforeCalculation; i++) {
+    cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+    sleep_ms(kSleepTimeMs);
+    cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  }
+
+  base::Optional<std::string> result =
+      cvm->GetValueAsPrettyString(kCValnameAverage);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+
+  result = cvm->GetValueAsPrettyString(kCValnameMedian);
+  EXPECT_TRUE(result);
+  EXPECT_NE(*result, "0");
+}
+
+TEST(MediaCValStatsTest, CircularBufferDontWrapIndex) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.Enable(true);
+
+  for (int i = 0; i < kMaxSamples - 1; i++) {
+    cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+    cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  }
+
+  EXPECT_EQ(cval_stats_.GetBufferIndexForTest(), 99);
+}
+
+
+TEST(MediaCValStatsTest, CircularBufferWrapIndex) {
+  base::CValManager* cvm = base::CValManager::GetInstance();
+  EXPECT_TRUE(cvm);
+  CValStats cval_stats_;
+
+  cval_stats_.Enable(true);
+
+  for (int i = 0; i < kMaxSamples + 5; i++) {
+    cval_stats_.StartTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+    cval_stats_.StopTimer(MediaTiming::SbPlayerCreate, kPipelineIdentifier);
+  }
+
+  EXPECT_EQ(cval_stats_.GetBufferIndexForTest(), 5);
+}
+
+}  // namespace media
+}  // namespace cobalt
diff --git a/cobalt/media/base/drm_system.cc b/cobalt/media/base/drm_system.cc
index d44e583..f92f1a7 100644
--- a/cobalt/media/base/drm_system.cc
+++ b/cobalt/media/base/drm_system.cc
@@ -101,7 +101,11 @@
 DrmSystem::~DrmSystem() {
   ON_INSTANCE_RELEASED(DrmSystem);
 
-  SbDrmDestroySystem(wrapped_drm_system_);
+  if (is_valid()) {
+    SbDrmDestroySystem(wrapped_drm_system_);
+  } else {
+    LOG(WARNING) << "Attempting to close invalid SbDrmSystem";
+  }
 }
 
 std::unique_ptr<DrmSystem::Session> DrmSystem::CreateSession(
@@ -114,6 +118,8 @@
 
 bool DrmSystem::IsServerCertificateUpdatable() {
   DCHECK(message_loop_->BelongsToCurrentThread());
+  DCHECK(is_valid());
+
   if (SbDrmIsServerCertificateUpdatable(wrapped_drm_system_)) {
     LOG(INFO) << "SbDrmSystem (" << wrapped_drm_system_
               << ") supports server certificate update";
@@ -129,12 +135,22 @@
     ServerCertificateUpdatedCallback server_certificate_updated_callback) {
   DCHECK(message_loop_->BelongsToCurrentThread());
   DCHECK(IsServerCertificateUpdatable());
+  DCHECK(is_valid());
+
+  if (!certificate) {
+    LOG(ERROR) << "Updating server with NULL certificate";
+    return;
+  }
 
   LOG(INFO) << "Updating server certificate of drm system ("
             << wrapped_drm_system_
             << "), certificate size: " << certificate_size;
 
   int ticket = next_ticket_++;
+  if (!SbDrmTicketIsValid(ticket)) {
+    LOG(ERROR) << "Updating server with invalid ticket";
+    return;
+  }
   ticket_to_server_certificate_updated_map_.insert(
       std::make_pair(ticket, server_certificate_updated_callback));
   SbDrmUpdateServerCertificate(wrapped_drm_system_, ticket, certificate,
@@ -166,6 +182,12 @@
     const SessionUpdateRequestDidNotGenerateCallback&
         session_update_request_did_not_generate_callback) {
   DCHECK(message_loop_->BelongsToCurrentThread());
+  DCHECK(is_valid());
+
+  if (!init_data) {
+    LOG(ERROR) << "Generate session update request with invalid init_data";
+    return;
+  }
 
   // Store the context of the call.
   SessionUpdateRequest session_update_request;
@@ -175,6 +197,12 @@
   session_update_request.did_not_generate_callback =
       session_update_request_did_not_generate_callback;
   int ticket = next_ticket_++;
+
+  if (!SbDrmTicketIsValid(ticket)) {
+    LOG(ERROR) << "Generate session update request with invalid ticket";
+    return;
+  }
+
   ticket_to_session_update_request_map_.insert(
       std::make_pair(ticket, session_update_request));
 
@@ -192,12 +220,19 @@
     const SessionUpdatedCallback& session_updated_callback,
     const SessionDidNotUpdateCallback& session_did_not_update_callback) {
   DCHECK(message_loop_->BelongsToCurrentThread());
+  DCHECK(is_valid());
 
   // Store the context of the call.
   SessionUpdate session_update;
   session_update.updated_callback = session_updated_callback;
   session_update.did_not_update_callback = session_did_not_update_callback;
   int ticket = next_ticket_++;
+
+  if (!SbDrmTicketIsValid(ticket)) {
+    LOG(ERROR) << "Update session with invalid ticket";
+    return;
+  }
+
   ticket_to_session_update_map_.insert(std::make_pair(ticket, session_update));
 
   LOG(INFO) << "Update session of drm system (" << wrapped_drm_system_
@@ -210,6 +245,7 @@
 
 void DrmSystem::CloseSession(const std::string& session_id) {
   DCHECK(message_loop_->BelongsToCurrentThread());
+  DCHECK(is_valid());
 
   LOG(INFO) << "Close session of drm system (" << wrapped_drm_system_
             << "), session id: " << session_id;
diff --git a/cobalt/media/base/playback_statistics.cc b/cobalt/media/base/playback_statistics.cc
index babd725..f8c62be 100644
--- a/cobalt/media/base/playback_statistics.cc
+++ b/cobalt/media/base/playback_statistics.cc
@@ -130,7 +130,11 @@
                        "The status of the media pipeline."),
       error_message_(base::StringPrintf("Media.Pipeline.%s.ErrorMessage",
                                         pipeline_identifier.c_str()),
-                     "", "The error message of the media pipeline error.") {}
+                     "", "The error message of the media pipeline error."),
+      current_video_codec_(
+          base::StringPrintf("Media.Pipeline.%s.CurrentCodec",
+                             pipeline_identifier.c_str()),
+          "", "The currently configured Codec in VideoDecoderConfig.") {}
 
 PlaybackStatistics::~PlaybackStatistics() {
   if (has_active_instance_) {
@@ -165,6 +169,7 @@
 
   video_width_ = video_config.natural_size().width();
   video_height_ = video_config.natural_size().height();
+  current_video_codec_ = GetCodecName(video_config.codec());
 
   const auto width = static_cast<SbAtomic32>(video_width_);
   const auto height = static_cast<SbAtomic32>(video_height_);
diff --git a/cobalt/media/base/playback_statistics.h b/cobalt/media/base/playback_statistics.h
index 220d472..44330ed 100644
--- a/cobalt/media/base/playback_statistics.h
+++ b/cobalt/media/base/playback_statistics.h
@@ -58,6 +58,7 @@
   base::CVal<bool> is_video_eos_written_;
   base::CVal<PipelineStatus> pipeline_status_;
   base::CVal<std::string> error_message_;
+  base::CVal<std::string> current_video_codec_;
   bool has_active_instance_ = false;
   bool is_first_audio_buffer_written_ = false;
   bool is_first_video_buffer_written_ = false;
diff --git a/cobalt/media/base/sbplayer_bridge.cc b/cobalt/media/base/sbplayer_bridge.cc
index 6598dc8..10674e3 100644
--- a/cobalt/media/base/sbplayer_bridge.cc
+++ b/cobalt/media/base/sbplayer_bridge.cc
@@ -107,7 +107,8 @@
     bool prefer_decode_to_texture,
     const OnEncryptedMediaInitDataEncounteredCB&
         on_encrypted_media_init_data_encountered_cb,
-    DecodeTargetProvider* const decode_target_provider)
+    DecodeTargetProvider* const decode_target_provider,
+    std::string pipeline_identifier)
     : url_(url),
       sbplayer_interface_(interface),
       task_runner_(task_runner),
@@ -120,6 +121,8 @@
       on_encrypted_media_init_data_encountered_cb_(
           on_encrypted_media_init_data_encountered_cb),
       decode_target_provider_(decode_target_provider),
+      cval_stats_(&interface->cval_stats_),
+      pipeline_identifier_(pipeline_identifier),
       is_url_based_(true) {
   DCHECK(host_);
   DCHECK(set_bounds_helper_);
@@ -146,7 +149,7 @@
     SbPlayerSetBoundsHelper* set_bounds_helper, bool allow_resume_after_suspend,
     bool prefer_decode_to_texture,
     DecodeTargetProvider* const decode_target_provider,
-    const std::string& max_video_capabilities)
+    const std::string& max_video_capabilities, std::string pipeline_identifier)
     : sbplayer_interface_(interface),
       task_runner_(task_runner),
       get_decode_target_graphics_context_provider_func_(
@@ -161,7 +164,9 @@
       audio_config_(audio_config),
       video_config_(video_config),
       decode_target_provider_(decode_target_provider),
-      max_video_capabilities_(max_video_capabilities)
+      max_video_capabilities_(max_video_capabilities),
+      cval_stats_(&interface->cval_stats_),
+      pipeline_identifier_(pipeline_identifier)
 #if SB_HAS(PLAYER_WITH_URL)
       ,
       is_url_based_(false)
@@ -206,7 +211,9 @@
   decode_target_provider_->ResetGetCurrentSbDecodeTargetFunction();
 
   if (SbPlayerIsValid(player_)) {
+    cval_stats_->StartTimer(MediaTiming::SbPlayerDestroy, pipeline_identifier_);
     sbplayer_interface_->Destroy(player_);
+    cval_stats_->StopTimer(MediaTiming::SbPlayerDestroy, pipeline_identifier_);
   }
 }
 
@@ -477,7 +484,9 @@
       DecodeTargetProvider::kOutputModeInvalid);
   decode_target_provider_->ResetGetCurrentSbDecodeTargetFunction();
 
+  cval_stats_->StartTimer(MediaTiming::SbPlayerDestroy, pipeline_identifier_);
   sbplayer_interface_->Destroy(player_);
+  cval_stats_->StopTimer(MediaTiming::SbPlayerDestroy, pipeline_identifier_);
 
   player_ = kSbPlayerInvalid;
 }
@@ -558,10 +567,12 @@
 
   player_creation_time_ = SbTimeGetMonotonicNow();
 
+  cval_stats_->StartTimer(MediaTiming::SbPlayerCreate, pipeline_identifier_);
   player_ = sbplayer_interface_->CreateUrlPlayer(
       url.c_str(), window_, &SbPlayerBridge::PlayerStatusCB,
       &SbPlayerBridge::EncryptedMediaInitDataEncounteredCB,
       &SbPlayerBridge::PlayerErrorCB, this);
+  cval_stats_->StopTimer(MediaTiming::SbPlayerCreate, pipeline_identifier_);
   DCHECK(SbPlayerIsValid(player_));
 
   if (output_mode_ == kSbPlayerOutputModeDecodeToTexture) {
@@ -608,11 +619,13 @@
   creation_param.output_mode = output_mode_;
   DCHECK_EQ(sbplayer_interface_->GetPreferredOutputMode(&creation_param),
             output_mode_);
+  cval_stats_->StartTimer(MediaTiming::SbPlayerCreate, pipeline_identifier_);
   player_ = sbplayer_interface_->Create(
       window_, &creation_param, &SbPlayerBridge::DeallocateSampleCB,
       &SbPlayerBridge::DecoderStatusCB, &SbPlayerBridge::PlayerStatusCB,
       &SbPlayerBridge::PlayerErrorCB, this,
       get_decode_target_graphics_context_provider_func_.Run());
+  cval_stats_->StopTimer(MediaTiming::SbPlayerCreate, pipeline_identifier_);
 
   is_creating_player_ = false;
 
@@ -693,9 +706,13 @@
         }
 
         DCHECK(!gathered_sbplayer_sample_infos.empty());
+        cval_stats_->StartTimer(MediaTiming::SbPlayerWriteSamples,
+                                pipeline_identifier_);
         sbplayer_interface_->WriteSample(player_, sample_type,
                                          gathered_sbplayer_sample_infos.data(),
                                          gathered_sbplayer_sample_infos.size());
+        cval_stats_->StopTimer(MediaTiming::SbPlayerWriteSamples,
+                               pipeline_identifier_);
       } else {
         sbplayer_interface_->WriteEndOfStream(
             player_, DemuxerStreamTypeToSbMediaType(type));
@@ -765,9 +782,13 @@
   }
 
   if (!gathered_sbplayer_sample_infos.empty()) {
+    cval_stats_->StartTimer(MediaTiming::SbPlayerWriteSamples,
+                            pipeline_identifier_);
     sbplayer_interface_->WriteSample(player_, sample_type,
                                      gathered_sbplayer_sample_infos.data(),
                                      gathered_sbplayer_sample_infos.size());
+    cval_stats_->StopTimer(MediaTiming::SbPlayerWriteSamples,
+                           pipeline_identifier_);
   }
 }
 
diff --git a/cobalt/media/base/sbplayer_bridge.h b/cobalt/media/base/sbplayer_bridge.h
index 1ea4cf6..efb6ea8 100644
--- a/cobalt/media/base/sbplayer_bridge.h
+++ b/cobalt/media/base/sbplayer_bridge.h
@@ -24,6 +24,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
+#include "cobalt/media/base/cval_stats.h"
 #include "cobalt/media/base/decode_target_provider.h"
 #include "cobalt/media/base/decoder_buffer_cache.h"
 #include "cobalt/media/base/sbplayer_interface.h"
@@ -74,7 +75,8 @@
                  bool allow_resume_after_suspend, bool prefer_decode_to_texture,
                  const OnEncryptedMediaInitDataEncounteredCB&
                      encrypted_media_init_data_encountered_cb,
-                 DecodeTargetProvider* const decode_target_provider);
+                 DecodeTargetProvider* const decode_target_provider,
+                 std::string pipeline_identifier);
 #endif  // SB_HAS(PLAYER_WITH_URL)
   // Create a SbPlayerBridge with normal player
   SbPlayerBridge(SbPlayerInterface* interface,
@@ -89,7 +91,8 @@
                  SbPlayerSetBoundsHelper* set_bounds_helper,
                  bool allow_resume_after_suspend, bool prefer_decode_to_texture,
                  DecodeTargetProvider* const decode_target_provider,
-                 const std::string& max_video_capabilities);
+                 const std::string& max_video_capabilities,
+                 std::string pipeline_identifier);
 
   ~SbPlayerBridge();
 
@@ -307,6 +310,9 @@
   // Used for Gathered Sample Write.
   bool pending_audio_eos_buffer_ = false;
   bool pending_video_eos_buffer_ = false;
+
+  CValStats* cval_stats_;
+  std::string pipeline_identifier_;
 };
 
 }  // namespace media
diff --git a/cobalt/media/base/sbplayer_interface.h b/cobalt/media/base/sbplayer_interface.h
index d240e0b..e79c1e6 100644
--- a/cobalt/media/base/sbplayer_interface.h
+++ b/cobalt/media/base/sbplayer_interface.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_MEDIA_BASE_SBPLAYER_INTERFACE_H_
 #define COBALT_MEDIA_BASE_SBPLAYER_INTERFACE_H_
 
+#include "cobalt/media/base/cval_stats.h"
 #include "starboard/player.h"
 
 #if SB_HAS(PLAYER_WITH_URL)
@@ -66,6 +67,12 @@
   virtual void GetUrlPlayerExtraInfo(
       SbPlayer player, SbUrlPlayerExtraInfo* out_url_player_info) = 0;
 #endif  // SB_HAS(PLAYER_WITH_URL)
+
+  // disabled by default, but can be enabled via h5vcc setting.
+  void EnableCValStats(bool should_enable) {
+    cval_stats_.Enable(should_enable);
+  }
+  CValStats cval_stats_;
 };
 
 class DefaultSbPlayerInterface final : public SbPlayerInterface {
diff --git a/cobalt/media/base/sbplayer_pipeline.cc b/cobalt/media/base/sbplayer_pipeline.cc
index 0d69a83..261af02 100644
--- a/cobalt/media/base/sbplayer_pipeline.cc
+++ b/cobalt/media/base/sbplayer_pipeline.cc
@@ -927,7 +927,8 @@
         sbplayer_interface_, task_runner_, source_url, window_, this,
         set_bounds_helper_.get(), allow_resume_after_suspend_,
         *decode_to_texture_output_mode_,
-        on_encrypted_media_init_data_encountered_cb_, decode_target_provider_));
+        on_encrypted_media_init_data_encountered_cb_, decode_target_provider_,
+        pipeline_identifier_));
     if (player_bridge_->IsValid()) {
       SetPlaybackRateTask(playback_rate_);
       SetVolumeTask(volume_);
@@ -1032,7 +1033,7 @@
         audio_mime_type, video_config, video_mime_type, window_, drm_system,
         this, set_bounds_helper_.get(), allow_resume_after_suspend_,
         *decode_to_texture_output_mode_, decode_target_provider_,
-        max_video_capabilities_));
+        max_video_capabilities_, pipeline_identifier_));
     if (player_bridge_->IsValid()) {
       SetPlaybackRateTask(playback_rate_);
       SetVolumeTask(volume_);
@@ -1405,6 +1406,10 @@
 void SbPlayerPipeline::UpdateDecoderConfig(DemuxerStream* stream) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
+  if (!player_bridge_) {
+    return;
+  }
+
   if (stream->type() == DemuxerStream::AUDIO) {
     const AudioDecoderConfig& decoder_config = stream->audio_decoder_config();
     player_bridge_->UpdateAudioConfig(decoder_config, stream->mime_type());
@@ -1492,7 +1497,17 @@
 
   window_ = window;
 
-  if (player_bridge_) {
+  bool resumable = true;
+  bool resume_to_background_mode = !SbWindowIsValid(window_);
+  bool is_audioless = !HasAudio();
+  if (resume_to_background_mode && is_audioless) {
+    // Avoid resuming an audioless video to background mode. SbPlayerBridge will
+    // try to create an SbPlayer with only the video stream disabled, and may
+    // crash in this case as SbPlayerCreate() will fail without an audio or
+    // video stream.
+    resumable = false;
+  }
+  if (player_bridge_ && resumable) {
     player_bridge_->Resume(window);
     if (!player_bridge_->IsValid()) {
       std::string error_message;
@@ -1509,8 +1524,6 @@
                   "SbPlayerPipeline::ResumeTask failed to create a valid "
                   "SbPlayerBridge - " +
                       time_information + " \'" + error_message + "\'");
-      done_event->Signal();
-      return;
     }
   }
 
diff --git a/cobalt/media/media_module.cc b/cobalt/media/media_module.cc
index 6159298..95965a5 100644
--- a/cobalt/media/media_module.cc
+++ b/cobalt/media/media_module.cc
@@ -189,6 +189,11 @@
     LOG(INFO) << (allow_batched_sample_write_ ? "Enabling" : "Disabling")
               << " batched sample write.";
     return true;
+  } else if (name == "EnableMetrics") {
+    sbplayer_interface_->EnableCValStats(value);
+    LOG(INFO) << (value ? "Enabling" : "Disabling")
+              << " media metrics collection.";
+    return true;
   }
   return false;
 }
diff --git a/cobalt/media/player/web_media_player_impl.cc b/cobalt/media/player/web_media_player_impl.cc
index 1844a6a..8073366 100644
--- a/cobalt/media/player/web_media_player_impl.cc
+++ b/cobalt/media/player/web_media_player_impl.cc
@@ -17,6 +17,7 @@
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/trace_event/trace_event.h"
 #include "cobalt/base/instance_counter.h"
@@ -641,9 +642,14 @@
   if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing) {
     // Any error that occurs before reaching ReadyStateHaveMetadata should
     // be considered a format error.
-    SetNetworkError(WebMediaPlayer::kNetworkStateFormatError,
-                    message.empty() ? "Ready state have nothing."
-                                    : "Ready state have nothing: " + message);
+    SetNetworkError(
+        WebMediaPlayer::kNetworkStateFormatError,
+        message.empty()
+            ? base::StringPrintf("Ready state have nothing. Error: (%d)",
+                                 static_cast<int>(error))
+            : base::StringPrintf(
+                  "Ready state have nothing: Error: (%d), Message: %s",
+                  static_cast<int>(error), message.c_str()));
     return;
   }
 
diff --git a/cobalt/media/testing/BUILD.gn b/cobalt/media/testing/BUILD.gn
index 43f1bbd..0e0529c 100644
--- a/cobalt/media/testing/BUILD.gn
+++ b/cobalt/media/testing/BUILD.gn
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import("//cobalt/media/testing/data/sha_files.gni")
+import("//cobalt/media/testing/data/sha1_files.gni")
 
 action("cobalt_media_download_test_data") {
   install_content = true
@@ -20,11 +20,11 @@
   script = "//tools/download_from_gcs.py"
 
   sha_sources = []
-  foreach(sha_file, sha1_files) {
+  foreach(sha1_file, sha1_files) {
     sha_sources += [ string_join("/",
                                  [
                                    "data",
-                                   sha_file,
+                                   sha1_file,
                                  ]) ]
   }
 
diff --git a/cobalt/media/testing/data/sha_files.gni b/cobalt/media/testing/data/sha1_files.gni
similarity index 100%
rename from cobalt/media/testing/data/sha_files.gni
rename to cobalt/media/testing/data/sha1_files.gni
diff --git a/cobalt/network/BUILD.gn b/cobalt/network/BUILD.gn
index 4af6239..bbfa1cb 100644
--- a/cobalt/network/BUILD.gn
+++ b/cobalt/network/BUILD.gn
@@ -123,7 +123,6 @@
     "//cobalt/content/ssl/certs/4b718d9b.0",
     "//cobalt/content/ssl/certs/4bfab552.0",
     "//cobalt/content/ssl/certs/4f316efb.0",
-    "//cobalt/content/ssl/certs/5273a94c.0",
     "//cobalt/content/ssl/certs/5443e9e3.0",
     "//cobalt/content/ssl/certs/54657681.0",
     "//cobalt/content/ssl/certs/57bcb2da.0",
diff --git a/cobalt/persistent_storage/persistent_settings.cc b/cobalt/persistent_storage/persistent_settings.cc
index c5d92e4..c4db368 100644
--- a/cobalt/persistent_storage/persistent_settings.cc
+++ b/cobalt/persistent_storage/persistent_settings.cc
@@ -48,10 +48,9 @@
   if (!thread_.Start()) return;
   DCHECK(message_loop());
 
-  std::vector<char> storage_dir(kSbFileMaxPath + 1, 0);
+  std::vector<char> storage_dir(kSbFileMaxPath, 0);
   SbSystemGetPath(kSbSystemPathCacheDirectory, storage_dir.data(),
                   kSbFileMaxPath);
-
   persistent_settings_file_ =
       std::string(storage_dir.data()) + kSbFileSepString + file_name;
   LOG(INFO) << "Persistent settings file path: " << persistent_settings_file_;
@@ -142,7 +141,6 @@
   auto persistent_settings = pref_store_->GetValues();
   const base::Value* result = persistent_settings->FindKey(key);
   if (result && result->is_bool()) return result->GetBool();
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return default_setting;
 }
 
@@ -152,7 +150,6 @@
   auto persistent_settings = pref_store_->GetValues();
   const base::Value* result = persistent_settings->FindKey(key);
   if (result && result->is_int()) return result->GetInt();
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return default_setting;
 }
 
@@ -162,7 +159,6 @@
   auto persistent_settings = pref_store_->GetValues();
   const base::Value* result = persistent_settings->FindKey(key);
   if (result && result->is_double()) return result->GetDouble();
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return default_setting;
 }
 
@@ -172,7 +168,6 @@
   auto persistent_settings = pref_store_->GetValues();
   const base::Value* result = persistent_settings->FindKey(key);
   if (result && result->is_string()) return result->GetString();
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return default_setting;
 }
 
@@ -184,7 +179,6 @@
   if (result && result->is_list()) {
     return std::move(result->TakeList());
   }
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return std::vector<base::Value>();
 }
 
@@ -202,7 +196,6 @@
     }
     return dict;
   }
-  LOG(INFO) << "Persistent setting does not exist: " << key;
   return dict;
 }
 
diff --git a/cobalt/renderer/BUILD.gn b/cobalt/renderer/BUILD.gn
index 21a89fc..2b4ac9d 100644
--- a/cobalt/renderer/BUILD.gn
+++ b/cobalt/renderer/BUILD.gn
@@ -426,6 +426,8 @@
     "rasterizer/testdata/SimpleTextIn40PtFont-expected.png",
     "rasterizer/testdata/SimpleTextIn500PtFont-expected.png",
     "rasterizer/testdata/SimpleTextIn80PtFont-expected.png",
+    "rasterizer/testdata/SimpleTextInEthiopic-expected.png",
+    "rasterizer/testdata/SimpleTextInEthiopicBold-expected.png",
     "rasterizer/testdata/SimpleTextInRed40PtChineseFont-expected.png",
     "rasterizer/testdata/SimpleTextInRed40PtFont-expected.png",
     "rasterizer/testdata/SimpleTextInRed40PtThaiFont-expected.png",
diff --git a/cobalt/renderer/rasterizer/pixel_test.cc b/cobalt/renderer/rasterizer/pixel_test.cc
index 20fedaf..51cc164 100644
--- a/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/cobalt/renderer/rasterizer/pixel_test.cc
@@ -105,9 +105,9 @@
 using cobalt::render_tree::ImageData;
 using cobalt::render_tree::ImageDataDescriptor;
 using cobalt::render_tree::ImageNode;
+using cobalt::render_tree::LinearGradientBrush;
 using cobalt::render_tree::LottieAnimation;
 using cobalt::render_tree::LottieNode;
-using cobalt::render_tree::LinearGradientBrush;
 using cobalt::render_tree::MapToMeshFilter;
 using cobalt::render_tree::MatrixTransform3DNode;
 using cobalt::render_tree::MatrixTransformNode;
@@ -1182,6 +1182,19 @@
                                        ColorRGBA(0, 0, 0, 1.0)));
 }
 
+TEST_F(PixelTest, SimpleTextInEthiopic) {
+  TestTree(CreateTextNodeWithinSurface(
+      GetResourceProvider(), "ብመንፅ", FontStyle(), 40, ColorRGBA(0, 0, 0, 1.0),
+      std::vector<Shadow>(), "Noto Sans Ethiopic"));
+}
+
+TEST_F(PixelTest, SimpleTextInEthiopicBold) {
+  FontStyle font_style(FontStyle::kBoldWeight, FontStyle::kUprightSlant);
+  TestTree(CreateTextNodeWithinSurface(
+      GetResourceProvider(), "ብመንፅ", font_style, 40, ColorRGBA(0, 0, 0, 1.0),
+      std::vector<Shadow>(), "Noto Sans Ethiopic"));
+}
+
 TEST_F(PixelTest, SimpleTextInRed40PtFont) {
   TestTree(CreateTextNodeWithinSurface(GetResourceProvider(), "Cobalt",
                                        FontStyle(), 40,
diff --git a/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopic-expected.png b/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopic-expected.png
new file mode 100644
index 0000000..45e4a97
--- /dev/null
+++ b/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopic-expected.png
Binary files differ
diff --git a/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopicBold-expected.png b/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopicBold-expected.png
new file mode 100644
index 0000000..eb85815
--- /dev/null
+++ b/cobalt/renderer/rasterizer/testdata/SimpleTextInEthiopicBold-expected.png
Binary files differ
diff --git a/cobalt/script/v8c/v8c_array_buffer.cc b/cobalt/script/v8c/v8c_array_buffer.cc
index 939ea56..838784b 100644
--- a/cobalt/script/v8c/v8c_array_buffer.cc
+++ b/cobalt/script/v8c/v8c_array_buffer.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <memory>
-
 #include "cobalt/script/v8c/v8c_array_buffer.h"
 
+#include <memory>
+
 #include "cobalt/base/polymorphic_downcast.h"
 #include "starboard/memory.h"
 
@@ -39,7 +39,15 @@
   if (byte_length_ == new_byte_length) {
     return;
   }
-  data_ = static_cast<uint8_t*>(SbMemoryReallocate(data_, new_byte_length));
+  // Calling reallocate with size 0 and a non-null pointer causes memory leaks
+  // on many platforms, since it may return nullptr while also not deallocating
+  // the previously allocated memory.
+  if (data_ != nullptr && new_byte_length == 0) {
+    SbMemoryDeallocate(data_);
+    data_ = nullptr;
+  } else {
+    data_ = static_cast<uint8_t*>(SbMemoryReallocate(data_, new_byte_length));
+  }
   byte_length_ = new_byte_length;
 }
 
diff --git a/cobalt/site/docs/development/setup-android.md b/cobalt/site/docs/development/setup-android.md
index 0382b42..2a5f0b1 100644
--- a/cobalt/site/docs/development/setup-android.md
+++ b/cobalt/site/docs/development/setup-android.md
@@ -209,7 +209,7 @@
 
 The test target itself (e.g. nplb) just builds an .so file (e.g. libnplb.so). To
 run that on a device, it needs to be packaged into an APK, which is done by the
-associated "deploy" target (e.g. nplb_deploy). The Starboard test runner does
+associated "install" target (e.g. nplb_install). The Starboard test runner does
 all this for you, so just use that to build and run tests. For example, to
 build and run "devel" NPLB on an ARM64 device, from the top-level directory:
 
diff --git a/cobalt/site/docs/development/setup-linux.md b/cobalt/site/docs/development/setup-linux.md
index 190cac0..78ecf3f 100644
--- a/cobalt/site/docs/development/setup-linux.md
+++ b/cobalt/site/docs/development/setup-linux.md
@@ -22,7 +22,7 @@
         pkgconf ninja-build bison yasm binutils clang libgles2-mesa-dev \
         mesa-common-dev libpulse-dev libavresample-dev libasound2-dev \
         libxrender-dev libxcomposite-dev libxml2-dev curl git \
-        python3.8-venv
+        python3.8-venv libxi-dev
     ```
 
 1.  Install Node.js via `nvm`:
@@ -72,7 +72,7 @@
     export PYTHONPATH="/fullpathto/cobalt:${PYTHONPATH}"
     ```
 
-    You should also run the above command in your termainal so it's available
+    You should also run the above command in your terminal so it's available
     immediately, rather than when you next login.
 
 ### Set up Developer Tools
@@ -104,6 +104,12 @@
     $ git checkout -b <my-branch-name> origin/master
     ```
 
+1.  Download clang++:
+
+    ```
+    $ ./starboard/tools/download_clang.sh
+    ```
+
 ## Build and Run Cobalt
 
 1.  Build the code running the following command in the top-level `cobalt`
diff --git a/cobalt/site/docs/gen/cobalt/doc/lifecycle.md b/cobalt/site/docs/gen/cobalt/doc/lifecycle.md
index 6b22ee0..d945ff1 100644
--- a/cobalt/site/docs/gen/cobalt/doc/lifecycle.md
+++ b/cobalt/site/docs/gen/cobalt/doc/lifecycle.md
@@ -88,7 +88,7 @@
 
 ### Deprecated `SbSystemRequest` functions.
 
-The `SbSytemRequest` functions are declared in `src/starboard/system.h`
+The `SbSystemRequest` functions are declared in `src/starboard/system.h`
 
 * The `SbSystemRequestPause` event is renamed to `SbSystemRequestBlur`
 * The `SbSystemRequestUnpause` event is renamed to `SbSystemRequestFocus`
diff --git a/cobalt/speech/sandbox/audio_loader.cc b/cobalt/speech/sandbox/audio_loader.cc
index da35a2c..f41aea0 100644
--- a/cobalt/speech/sandbox/audio_loader.cc
+++ b/cobalt/speech/sandbox/audio_loader.cc
@@ -100,7 +100,7 @@
   loader_ = base::WrapUnique(new loader::Loader(
       base::Bind(&loader::FetcherFactory::CreateFetcher,
                  base::Unretained(fetcher_factory_.get()), url,
-                 disk_cache::kOther),
+                 /*main_resource=*/false, disk_cache::kOther),
       base::Bind(&DummyDecoder::Create, base::Bind(&AudioLoader::OnLoadingDone,
                                                    base::Unretained(this))),
       base::Bind(&AudioLoader::OnLoadingError, base::Unretained(this))));
diff --git a/cobalt/speech/url_fetcher_fake.h b/cobalt/speech/url_fetcher_fake.h
index aa2bc08..7b6d3cb 100644
--- a/cobalt/speech/url_fetcher_fake.h
+++ b/cobalt/speech/url_fetcher_fake.h
@@ -19,7 +19,9 @@
 
 #if defined(ENABLE_FAKE_MICROPHONE)
 
+#include <memory>
 #include <string>
+#include <utility>
 
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
@@ -103,6 +105,9 @@
   void SetAutomaticallyRetryOnNetworkChanges(int max_retries) override {
     NOTREACHED();
   }
+  const net::HttpRequestHeaders& GetRequestHeaders() const override {
+    return extra_request_headers_;
+  }
   net::HttpResponseHeaders* GetResponseHeaders() const override {
     NOTREACHED();
     return NULL;
@@ -158,6 +163,7 @@
   base::Optional<base::RepeatingTimer> download_timer_;
   net::ProxyServer proxy_server_;
   std::unique_ptr<net::URLFetcherResponseWriter> response_data_writer_;
+  net::HttpRequestHeaders extra_request_headers_;
   THREAD_CHECKER(thread_checker_);
 };
 
diff --git a/cobalt/test/document_loader.h b/cobalt/test/document_loader.h
index 6e6b7da..6d23802 100644
--- a/cobalt/test/document_loader.h
+++ b/cobalt/test/document_loader.h
@@ -83,7 +83,8 @@
     document_->AddObserver(this);
     document_loader_.reset(new loader::Loader(
         base::Bind(&loader::FetcherFactory::CreateFetcher,
-                   base::Unretained(&fetcher_factory_), url, disk_cache::kHTML),
+                   base::Unretained(&fetcher_factory_), url,
+                   /*main_resource=*/true, disk_cache::kHTML),
         base::Bind(&dom_parser::Parser::ParseDocumentAsync,
                    base::Unretained(dom_parser_.get()), document_,
                    base::SourceLocation(url.spec(), 1, 1)),
diff --git a/cobalt/test/run_all_unittests.cc b/cobalt/test/run_all_unittests.cc
index 63cde2f..1395d0c 100644
--- a/cobalt/test/run_all_unittests.cc
+++ b/cobalt/test/run_all_unittests.cc
@@ -29,6 +29,11 @@
   base::PathService::RegisterProvider(&cobalt::PathProvider,
                                       cobalt::paths::PATH_COBALT_START,
                                       cobalt::paths::PATH_COBALT_END);
+
+  // Copy the Starboard thread name to the PlatformThread name.
+  char thread_name[128] = {'\0'};
+  SbThreadGetName(thread_name, 127);
+  base::PlatformThread::SetName(thread_name);
   return test_suite.Run();
 }
 }  // namespace
diff --git a/cobalt/tools/automated_testing/cobalt_runner.py b/cobalt/tools/automated_testing/cobalt_runner.py
index b0de327..43928dd 100644
--- a/cobalt/tools/automated_testing/cobalt_runner.py
+++ b/cobalt/tools/automated_testing/cobalt_runner.py
@@ -56,6 +56,7 @@
 WEBDRIVER_HTTP_TIMEOUT_SECONDS = 2 * 60
 COBALT_EXIT_TIMEOUT_SECONDS = 5
 PAGE_LOAD_WAIT_SECONDS = 30
+POLL_UNTIL_WAIT_SECONDS = 30
 WINDOWDRIVER_CREATED_TIMEOUT_SECONDS = 45
 WEBMODULE_LOADED_TIMEOUT_SECONDS = 45
 FIND_ELEMENT_RETRY_LIMIT = 20
@@ -331,13 +332,25 @@
 
   def _StartWebdriver(self, port):
     host, webdriver_port = self.launcher.GetHostAndPortGivenPort(port)
-    url = f'http://{host}:{webdriver_port}/'
+    self.webdriver_url = f'http://{host}:{webdriver_port}/'
     self.webdriver = self.selenium_webdriver_module.Remote(
-        url, COBALT_WEBDRIVER_CAPABILITIES)
+        self.webdriver_url, COBALT_WEBDRIVER_CAPABILITIES)
     self.webdriver.command_executor.set_timeout(WEBDRIVER_HTTP_TIMEOUT_SECONDS)
     logging.info('Selenium Connected')
     self.test_script_started.set()
 
+  def ReconnectWebDriver(self):
+    logging.warning('ReconnectWebDriver\n\n\n\n')
+    if self.webdriver:
+      self.webdriver.quit()
+    if self.webdriver_url:
+      self.webdriver = self.selenium_webdriver_module.Remote(
+          self.webdriver_url, COBALT_WEBDRIVER_CAPABILITIES)
+    if self.webdriver:
+      self.webdriver.command_executor.set_timeout(
+          WEBDRIVER_HTTP_TIMEOUT_SECONDS)
+      logging.info('Selenium Reconnected')
+
   def WaitForStart(self):
     """Waits for the webdriver client to attach to Cobalt."""
     startup_timeout_seconds = self.launcher.GetStartupTimeout()
@@ -444,15 +457,14 @@
 
     Args:
       css_selector: A CSS selector
-      expected_num: The expected number of the selector type to be found.
 
     Raises:
       Underlying WebDriver exceptions
     """
     start_time = time.time()
     while (not self.FindElements(css_selector) and
-           (time.time() - start_time < PAGE_LOAD_WAIT_SECONDS)):
-      time.sleep(1)
+           (time.time() - start_time < POLL_UNTIL_WAIT_SECONDS)):
+      time.sleep(0.5)
     if expected_num:
       self.FindElements(css_selector, expected_num)
 
diff --git a/cobalt/ui_navigation/nav_item.cc b/cobalt/ui_navigation/nav_item.cc
index 8795d59..21874ac 100644
--- a/cobalt/ui_navigation/nav_item.cc
+++ b/cobalt/ui_navigation/nav_item.cc
@@ -87,7 +87,9 @@
     reinterpret_cast<intptr_t>(kNativeItemInvalid));
 
 NativeCallbacks NavItem::s_callbacks_ = {
-    &NavItem::OnBlur, &NavItem::OnFocus, &NavItem::OnScroll,
+    &NavItem::OnBlur,
+    &NavItem::OnFocus,
+    &NavItem::OnScroll,
 };
 
 NavItem::NavItem(NativeItemType type, const base::Closure& onblur_callback,
@@ -111,10 +113,9 @@
 }
 
 NavItem::~NavItem() {
+  SetEnabled(false);
+
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
-  DCHECK(state_ == kStatePendingDelete);
-  DCHECK(SbAtomicNoBarrier_LoadPtr(&s_focused_nav_item_) !=
-         reinterpret_cast<intptr_t>(nav_item_));
   g_pending_updates->emplace_back(
       nav_item_, base::Bind(GetInterface().destroy_item, nav_item_));
   if (--g_nav_item_count == 0) {
diff --git a/cobalt/ui_navigation/scroll_engine/BUILD.gn b/cobalt/ui_navigation/scroll_engine/BUILD.gn
index 485dbea..0c3cd62 100644
--- a/cobalt/ui_navigation/scroll_engine/BUILD.gn
+++ b/cobalt/ui_navigation/scroll_engine/BUILD.gn
@@ -15,6 +15,8 @@
 static_library("scroll_engine") {
   has_pedantic_warnings = true
   sources = [
+    "free_scrolling_nav_item.cc",
+    "free_scrolling_nav_item.h",
     "scroll_engine.cc",
     "scroll_engine.h",
   ]
diff --git a/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.cc b/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.cc
new file mode 100644
index 0000000..29eb3ae
--- /dev/null
+++ b/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.cc
@@ -0,0 +1,70 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace cobalt {
+namespace ui_navigation {
+namespace scroll_engine {
+
+FreeScrollingNavItem::FreeScrollingNavItem(scoped_refptr<NavItem> nav_item,
+                                           math::Vector2dF initial_offset,
+                                           math::Vector2dF target_offset,
+                                           base::TimeDelta animation_duration,
+                                           float animation_slope)
+    : nav_item_(nav_item),
+      initial_offset_(initial_offset),
+      target_offset_(target_offset),
+      animation_duration_(animation_duration) {
+  initial_change_ = base::Time::Now();
+
+  // Constants are derived from the ease-in-out curve definition here:
+  // https://www.w3.org/TR/2023/CRD-css-easing-1-20230213/#typedef-cubic-bezier-easing-function
+  animation_function_ =
+      base::WrapRefCounted(new cssom::CubicBezierTimingFunction(
+          0.42f, 0.42f * animation_slope, 0.58f, 1.f));
+}
+
+float FreeScrollingNavItem::GetFractionOfCurrentProgress() {
+  if (animation_duration_.is_zero()) {
+    return 1.f;
+  }
+
+  auto now = base::Time::Now();
+  auto time_delta = now - initial_change_;
+  auto fraction_of_progress =
+      time_delta.InMillisecondsF() / animation_duration_.InMillisecondsF();
+  return std::min<float>(static_cast<float>(fraction_of_progress), 1.f);
+}
+
+bool FreeScrollingNavItem::AnimationIsComplete() {
+  auto fraction_of_current_progress = GetFractionOfCurrentProgress();
+  return fraction_of_current_progress >= 1.f;
+}
+
+math::Vector2dF FreeScrollingNavItem::GetCurrentOffset() {
+  auto fraction_of_current_progress = GetFractionOfCurrentProgress();
+  float progress = animation_function_->Evaluate(fraction_of_current_progress);
+  auto distance_delta = target_offset_ - initial_offset_;
+  distance_delta.Scale(progress);
+  return initial_offset_ + distance_delta;
+}
+
+}  // namespace scroll_engine
+}  // namespace ui_navigation
+}  // namespace cobalt
diff --git a/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.h b/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.h
new file mode 100644
index 0000000..cbd8592
--- /dev/null
+++ b/cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.h
@@ -0,0 +1,53 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_UI_NAVIGATION_SCROLL_ENGINE_FREE_SCROLLING_NAV_ITEM_H_
+#define COBALT_UI_NAVIGATION_SCROLL_ENGINE_FREE_SCROLLING_NAV_ITEM_H_
+
+#include "cobalt/cssom/timing_function.h"
+#include "cobalt/math/vector2d_f.h"
+#include "cobalt/ui_navigation/nav_item.h"
+
+namespace cobalt {
+namespace ui_navigation {
+namespace scroll_engine {
+
+class FreeScrollingNavItem {
+ public:
+  FreeScrollingNavItem(scoped_refptr<NavItem> nav_item,
+                       math::Vector2dF initial_offset,
+                       math::Vector2dF target_offset,
+                       base::TimeDelta animation_duration,
+                       float animation_slope);
+
+ public:
+  scoped_refptr<NavItem> nav_item() { return nav_item_; }
+  float GetFractionOfCurrentProgress();
+  bool AnimationIsComplete();
+  math::Vector2dF GetCurrentOffset();
+
+ private:
+  scoped_refptr<NavItem> nav_item_;
+  math::Vector2dF initial_offset_;
+  math::Vector2dF target_offset_;
+  scoped_refptr<cssom::CubicBezierTimingFunction> animation_function_;
+  base::TimeDelta animation_duration_;
+  base::Time initial_change_;
+};
+
+}  // namespace scroll_engine
+}  // namespace ui_navigation
+}  // namespace cobalt
+
+#endif  // COBALT_UI_NAVIGATION_SCROLL_ENGINE_FREE_SCROLLING_NAV_ITEM_H_
diff --git a/cobalt/ui_navigation/scroll_engine/scroll_engine.cc b/cobalt/ui_navigation/scroll_engine/scroll_engine.cc
index bd5495c..4c14f73 100644
--- a/cobalt/ui_navigation/scroll_engine/scroll_engine.cc
+++ b/cobalt/ui_navigation/scroll_engine/scroll_engine.cc
@@ -16,7 +16,9 @@
 
 #include <algorithm>
 
+#include "base/logging.h"
 #include "cobalt/dom/pointer_event.h"
+#include "cobalt/math/clamp.h"
 
 namespace cobalt {
 namespace ui_navigation {
@@ -24,7 +26,7 @@
 
 namespace {
 
-const base::TimeDelta kFreeScrollDuration =
+const base::TimeDelta kMaxFreeScrollDuration =
     base::TimeDelta::FromMilliseconds(700);
 
 void BoundValuesByNavItemBounds(scoped_refptr<ui_navigation::NavItem> nav_item,
@@ -91,10 +93,97 @@
   nav_item->SetContentOffset(offset_x, offset_y);
 }
 
+float GetMaxAbsoluteDimension(math::Vector2dF vector) {
+  return std::abs(vector.x()) >= std::abs(vector.y()) ? vector.x() : vector.y();
+}
+
+math::Vector2dF GetVelocityInMilliseconds(
+    EventPositionWithTimeStamp previous_event,
+    EventPositionWithTimeStamp current_event) {
+  auto time_delta = current_event.time_stamp - previous_event.time_stamp;
+  auto distance_delta = current_event.position - previous_event.position;
+
+  // Don't recognize infinite velocity.
+  if (time_delta.is_zero()) {
+    return math::Vector2dF(0, 0);
+  }
+
+  distance_delta.Scale(static_cast<float>(1.f / time_delta.InMilliseconds()));
+  return distance_delta;
+}
+
+math::Vector2dF GetNewTarget(EventPositionWithTimeStamp previous_event,
+                             EventPositionWithTimeStamp current_event) {
+  auto velocity = GetVelocityInMilliseconds(previous_event, current_event);
+  velocity.Scale(kMaxFreeScrollDuration.InMilliseconds());
+  velocity.Scale(-1);
+  return current_event.position + velocity;
+}
+
+math::Vector2dF GetNewDelta(EventPositionWithTimeStamp previous_event,
+                            EventPositionWithTimeStamp current_event) {
+  auto new_target = GetNewTarget(previous_event, current_event);
+  return new_target - current_event.position;
+}
+
+base::TimeDelta GetAnimationDurationTimeBound(
+    EventPositionWithTimeStamp previous_event,
+    EventPositionWithTimeStamp current_event) {
+  const float time_bound_multiplier = 2.5f;
+  auto time_delta = current_event.time_stamp - previous_event.time_stamp;
+  return time_delta * time_bound_multiplier;
+}
+
+base::TimeDelta GetAnimationDurationEaseInOutBound(
+    EventPositionWithTimeStamp previous_event,
+    EventPositionWithTimeStamp current_event) {
+  auto new_delta = GetNewDelta(previous_event, current_event);
+  auto duration = std::sqrt(std::abs(GetMaxAbsoluteDimension(new_delta)));
+  return base::TimeDelta::FromMillisecondsD(duration);
+}
+
+base::TimeDelta GetAnimationDuration(EventPositionWithTimeStamp previous_event,
+                                     EventPositionWithTimeStamp current_event) {
+  // TODO(b/265864360): Duration should be calculated as it is in the comment
+  //                    below, but it seems to always be too small. Re-evaluate
+  //                    once something workable is in.
+  // auto duration_time_bound =
+  //     GetAnimationDurationTimeBound(previous_event, current_event);
+  // auto ease_in_out_bound =
+  //     GetAnimationDurationEaseInOutBound(previous_event, current_event);
+  // auto min_bound = duration_time_bound < ease_in_out_bound ?
+  // duration_time_bound
+  //                                                          :
+  //                                                          ease_in_out_bound;
+  // return min_bound < kMaxFreeScrollDuration ? min_bound
+  //                                           : kMaxFreeScrollDuration;
+  return kMaxFreeScrollDuration;
+}
+
+float GetAnimationSlope(EventPositionWithTimeStamp previous_event,
+                        EventPositionWithTimeStamp current_event) {
+  auto animation_duration = GetAnimationDuration(previous_event, current_event);
+  auto time_delta = previous_event.time_stamp - current_event.time_stamp;
+  if (time_delta.is_zero()) {
+    return 0.f;
+  }
+  auto slope = std::abs(animation_duration / time_delta);
+  float cubic_bezier_ease_in_out_x1 = 0.42f;
+  return math::Clamp(static_cast<float>(slope) * cubic_bezier_ease_in_out_x1,
+                     0.f, 1.f);
+}
+
+math::Matrix3F CalculateActiveTransform(math::Matrix3F initial_transform) {
+  auto active_transform = initial_transform.Inverse();
+  if (active_transform.IsZeros()) {
+    return math::Matrix3F::Identity();
+  }
+  return active_transform;
+}
+
 }  // namespace
 
-ScrollEngine::ScrollEngine()
-    : timing_function_(cssom::TimingFunction::GetEaseInOut()) {}
+ScrollEngine::ScrollEngine() : active_transform_(math::Matrix3F::Identity()) {}
 ScrollEngine::~ScrollEngine() { free_scroll_timer_.Stop(); }
 
 void ScrollEngine::MaybeFreeScrollActiveNavItem() {
@@ -105,34 +194,25 @@
     return;
   }
 
-  auto previous_event = previous_events_.back();
-  auto current_event = previous_events_.front();
-  math::Vector2dF distance_delta =
-      previous_event.position - current_event.position;
-  // TODO(andrewsavage): See if we need this
-  // if (distance_delta.Length() < kFreeScrollThreshold) {
-  //   return;
-  // }
+  auto current_event = previous_events_.back();
+  auto previous_event = previous_events_.front();
 
-  // Get the average velocity for the entire run
-  math::Vector2dF average_velocity = distance_delta;
-  average_velocity.Scale(1.0f / static_cast<float>(current_event.time_stamp -
-                                                   previous_event.time_stamp));
-  average_velocity.Scale(0.5);
-
-  // Get the distance
-  average_velocity.Scale(kFreeScrollDuration.ToSbTime());
+  auto new_delta = GetNewDelta(previous_event, current_event);
+  base::TimeDelta animation_duration =
+      GetAnimationDuration(previous_event, current_event);
+  float animation_slope = GetAnimationSlope(previous_event, current_event);
 
   float initial_offset_x;
   float initial_offset_y;
   active_item_->GetContentOffset(&initial_offset_x, &initial_offset_y);
   math::Vector2dF initial_offset(initial_offset_x, initial_offset_y);
 
-  math::Vector2dF target_offset = initial_offset + average_velocity;
+  math::Vector2dF target_offset = initial_offset + new_delta;
   target_offset = BoundValuesByNavItemBounds(active_item_, target_offset);
 
   nav_items_with_decaying_scroll_.push_back(
-      FreeScrollingNavItem(active_item_, initial_offset, target_offset));
+      FreeScrollingNavItem(active_item_, initial_offset, target_offset,
+                           animation_duration, animation_slope));
   if (!free_scroll_timer_.IsRunning()) {
     free_scroll_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(5),
                              this,
@@ -159,15 +239,22 @@
     return;
   }
 
+  auto transformed_point =
+      active_transform_ * math::PointF(pointer_event->x(), pointer_event->y());
   auto current_coordinates =
-      math::Vector2dF(pointer_event->x(), pointer_event->y());
+      math::Vector2dF(transformed_point.x(), transformed_point.y());
+  auto current_time = base::Time::FromJsTime(pointer_event->time_stamp());
   if (previous_events_.size() != 2) {
     // This is an error.
-    previous_events_.push(EventPositionWithTimeStamp(
-        current_coordinates, pointer_event->time_stamp()));
+    previous_events_.push(
+        EventPositionWithTimeStamp(current_coordinates, current_time));
     return;
   }
 
+  previous_events_.pop();
+  previous_events_.push(
+      EventPositionWithTimeStamp(current_coordinates, current_time));
+
   auto drag_vector = previous_events_.front().position - current_coordinates;
   if (active_scroll_type_ == ScrollType::Horizontal) {
     drag_vector.set_y(0.0f);
@@ -175,10 +262,6 @@
     drag_vector.set_x(0.0f);
   }
 
-  previous_events_.push(EventPositionWithTimeStamp(
-      current_coordinates, pointer_event->time_stamp()));
-  previous_events_.pop();
-
   active_velocity_ = drag_vector;
 
   ScrollNavItemWithVector(active_item_, drag_vector);
@@ -227,8 +310,23 @@
     scoped_refptr<ui_navigation::NavItem> scroll_container,
     ScrollType scroll_type, int32_t pointer_id,
     math::Vector2dF initial_coordinates, uint64 initial_time_stamp,
-    math::Vector2dF current_coordinates, uint64 current_time_stamp) {
+    math::Vector2dF current_coordinates, uint64 current_time_stamp,
+    const math::Matrix3F& initial_transform) {
   DCHECK(base::MessageLoop::current() == scroll_engine_.message_loop());
+  active_transform_ = CalculateActiveTransform(initial_transform);
+  auto initial_point =
+      active_transform_ *
+      math::PointF(initial_coordinates.x(), initial_coordinates.y());
+  auto current_point =
+      active_transform_ *
+      math::PointF(current_coordinates.x(), current_coordinates.y());
+  initial_coordinates.SetVector(initial_point.x(), initial_point.y());
+  current_coordinates.SetVector(current_point.x(), current_point.y());
+
+  if (active_item_) {
+    events_to_handle_.erase(pointer_id);
+    return;
+  }
 
   auto drag_vector = initial_coordinates - current_coordinates;
   if (ShouldFreeScroll(scroll_container, drag_vector)) {
@@ -243,10 +341,10 @@
     drag_vector.set_x(0.0f);
   }
 
-  previous_events_.push(
-      EventPositionWithTimeStamp(initial_coordinates, initial_time_stamp));
-  previous_events_.push(
-      EventPositionWithTimeStamp(current_coordinates, current_time_stamp));
+  previous_events_.push(EventPositionWithTimeStamp(
+      initial_coordinates, base::Time::FromJsTime(initial_time_stamp)));
+  previous_events_.push(EventPositionWithTimeStamp(
+      current_coordinates, base::Time::FromJsTime(current_time_stamp)));
 
   active_velocity_ = drag_vector;
   ScrollNavItemWithVector(active_item_, drag_vector);
@@ -254,6 +352,7 @@
   auto event_to_handle = events_to_handle_.find(pointer_id);
   if (event_to_handle != events_to_handle_.end()) {
     HandlePointerEventForActiveItem(event_to_handle->second);
+    events_to_handle_.erase(pointer_id);
   }
 }
 
@@ -265,7 +364,7 @@
     for (std::vector<FreeScrollingNavItem>::iterator it =
              nav_items_with_decaying_scroll_.begin();
          it != nav_items_with_decaying_scroll_.end();) {
-      if (it->nav_item.get() == scroll_to_cancel.get()) {
+      if (it->nav_item().get() == scroll_to_cancel.get()) {
         it = nav_items_with_decaying_scroll_.erase(it);
       } else {
         it++;
@@ -281,21 +380,14 @@
     free_scroll_timer_.Stop();
     return;
   }
+
   for (std::vector<FreeScrollingNavItem>::iterator it =
            nav_items_with_decaying_scroll_.begin();
        it != nav_items_with_decaying_scroll_.end();) {
-    auto now = base::Time::Now();
-    auto update_delta = now - it->last_change;
-    float fraction_of_time =
-        std::max<float>(update_delta / kFreeScrollDuration, 1.0);
-    float progress = timing_function_->Evaluate(fraction_of_time);
-    math::Vector2dF current_offset = it->target_offset - it->initial_offset;
-    current_offset.Scale(progress);
-    current_offset += it->initial_offset;
-    it->nav_item->SetContentOffset(current_offset.x(), current_offset.y());
-    it->last_change = now;
+    auto current_offset = it->GetCurrentOffset();
+    it->nav_item()->SetContentOffset(current_offset.x(), current_offset.y());
 
-    if (fraction_of_time == 1.0) {
+    if (it->AnimationIsComplete()) {
       it = nav_items_with_decaying_scroll_.erase(it);
     } else {
       it++;
diff --git a/cobalt/ui_navigation/scroll_engine/scroll_engine.h b/cobalt/ui_navigation/scroll_engine/scroll_engine.h
index 2399457..93e1e33 100644
--- a/cobalt/ui_navigation/scroll_engine/scroll_engine.h
+++ b/cobalt/ui_navigation/scroll_engine/scroll_engine.h
@@ -27,6 +27,7 @@
 #include "cobalt/dom/pointer_event_init.h"
 #include "cobalt/math/vector2d_f.h"
 #include "cobalt/ui_navigation/nav_item.h"
+#include "cobalt/ui_navigation/scroll_engine/free_scrolling_nav_item.h"
 
 namespace cobalt {
 namespace ui_navigation {
@@ -42,6 +43,13 @@
   Free,
 } ScrollType;
 
+struct EventPositionWithTimeStamp {
+  EventPositionWithTimeStamp(math::Vector2dF position, base::Time time_stamp)
+      : position(position), time_stamp(time_stamp) {}
+  math::Vector2dF position;
+  base::Time time_stamp;
+};
+
 class ScrollEngine {
  public:
   ScrollEngine();
@@ -53,7 +61,8 @@
                          math::Vector2dF initial_coordinates,
                          uint64 initial_time_stamp,
                          math::Vector2dF current_coordinates,
-                         uint64 current_time_stamp);
+                         uint64 current_time_stamp,
+                         const math::Matrix3F& initial_transform);
   void CancelActiveScrollsForNavItems(
       std::vector<scoped_refptr<ui_navigation::NavItem>> scrolls_to_cancel);
 
@@ -68,32 +77,11 @@
   base::Thread scroll_engine_{"ScrollEngineThread"};
   base::RepeatingTimer free_scroll_timer_;
 
-  struct EventPositionWithTimeStamp {
-    EventPositionWithTimeStamp(math::Vector2dF position, uint64 time_stamp)
-        : position(position), time_stamp(time_stamp) {}
-    math::Vector2dF position;
-    uint64 time_stamp;
-  };
-
-  struct FreeScrollingNavItem {
-    FreeScrollingNavItem(scoped_refptr<NavItem> nav_item,
-                         math::Vector2dF initial_offset,
-                         math::Vector2dF target_offset)
-        : nav_item(nav_item),
-          initial_offset(initial_offset),
-          target_offset(target_offset),
-          last_change(base::Time::Now()) {}
-    scoped_refptr<NavItem> nav_item;
-    math::Vector2dF initial_offset;
-    math::Vector2dF target_offset;
-    base::Time last_change;
-  };
-
   std::queue<EventPositionWithTimeStamp> previous_events_;
-  const scoped_refptr<cssom::TimingFunction>& timing_function_;
 
   scoped_refptr<NavItem> active_item_;
   math::Vector2dF active_velocity_;
+  math::Matrix3F active_transform_;
   ScrollType active_scroll_type_ = ScrollType::Unknown;
   std::map<uint32_t, scoped_refptr<dom::PointerEvent>> events_to_handle_;
   std::vector<FreeScrollingNavItem> nav_items_with_decaying_scroll_;
diff --git a/cobalt/updater/configurator.cc b/cobalt/updater/configurator.cc
index ea03435..ce891e6 100644
--- a/cobalt/updater/configurator.cc
+++ b/cobalt/updater/configurator.cc
@@ -248,6 +248,7 @@
 }
 
 void Configurator::SetChannel(const std::string& updater_channel) {
+  LOG(INFO) << "Configurator::SetChannel updater_channel=" << updater_channel;
   base::AutoLock auto_lock(updater_channel_lock_);
   updater_channel_ = updater_channel;
 }
diff --git a/cobalt/updater/version_manifest/BUILD.gn b/cobalt/updater/version_manifest/BUILD.gn
new file mode 100644
index 0000000..fc727ec
--- /dev/null
+++ b/cobalt/updater/version_manifest/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2022 The Cobalt Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+copy("copy_version_manifest") {
+  install_content = true
+  sources = [ "manifest.json" ]
+  outputs = [ "$root_out_dir/manifest.json" ]
+}
diff --git a/cobalt/updater/version_manifest/manifest.json b/cobalt/updater/version_manifest/manifest.json
new file mode 100644
index 0000000..fd8f610
--- /dev/null
+++ b/cobalt/updater/version_manifest/manifest.json
@@ -0,0 +1,6 @@
+{
+    "manifest_version": 2,
+    "name": "Cobalt",
+    "description": "Cobalt",
+    "version": "1.0.0"
+}
diff --git a/cobalt/version.h b/cobalt/version.h
index bc6859b..a191328 100644
--- a/cobalt/version.h
+++ b/cobalt/version.h
@@ -35,6 +35,6 @@
 //                  release is cut.
 //.
 
-#define COBALT_VERSION "23.lts.3"
+#define COBALT_VERSION "23.lts.4"
 
 #endif  // COBALT_VERSION_H_
diff --git a/cobalt/web/BUILD.gn b/cobalt/web/BUILD.gn
index c722217..122f57c 100644
--- a/cobalt/web/BUILD.gn
+++ b/cobalt/web/BUILD.gn
@@ -173,6 +173,8 @@
 
   sources = [
     "blob_test.cc",
+    "cache_storage_test.cc",
+    "cache_utils_test.cc",
     "crypto_test.cc",
     "csp_delegate_test.cc",
     "custom_event_test.cc",
diff --git a/cobalt/web/agent.cc b/cobalt/web/agent.cc
index 7edf26e..0d2722e 100644
--- a/cobalt/web/agent.cc
+++ b/cobalt/web/agent.cc
@@ -94,16 +94,28 @@
   }
 
   const std::string& name() const final { return name_; };
-  void setup_environment_settings(
+  void SetupEnvironmentSettings(
       EnvironmentSettings* environment_settings) final {
     for (auto& observer : environment_settings_change_observers_) {
       observer.OnEnvironmentSettingsChanged(!!environment_settings);
     }
     environment_settings_.reset(environment_settings);
-    if (environment_settings_) environment_settings_->set_context(this);
+    if (environment_settings_) {
+      environment_settings_->set_context(this);
+    }
+  }
+
+  void SetupFinished() {
+    if (service_worker_jobs_) {
+      service_worker_jobs_->RegisterWebContext(this);
+    }
+    if (service_worker_jobs_) {
+      service_worker_jobs_->SetActiveWorker(environment_settings_.get());
+    }
   }
 
   EnvironmentSettings* environment_settings() const final {
+    DCHECK(environment_settings_);
     DCHECK_EQ(environment_settings_->context(), this);
     return environment_settings_.get();
   }
@@ -145,9 +157,6 @@
   void set_active_service_worker(
       const scoped_refptr<worker::ServiceWorkerObject>& worker) final {
     active_service_worker_ = worker;
-    // Also hold a reference to the registration that contains this worker.
-    containing_service_worker_registration_ =
-        worker ? worker->containing_service_worker_registration() : nullptr;
   }
   const scoped_refptr<worker::ServiceWorkerObject>& active_service_worker()
       const final {
@@ -220,8 +229,6 @@
   // Note: When a service worker is unregistered from the last client, this will
   // hold the last reference until the current page is unloaded.
   scoped_refptr<worker::ServiceWorkerObject> active_service_worker_;
-  scoped_refptr<worker::ServiceWorkerRegistrationObject>
-      containing_service_worker_registration_;
 
   base::ObserverList<Context::EnvironmentSettingsChangeObserver>::Unchecked
       environment_settings_change_observers_;
@@ -286,7 +293,7 @@
         script::GlobalEnvironment::ReportErrorCallback());
   }
 
-  setup_environment_settings(nullptr);
+  SetupEnvironmentSettings(nullptr);
   environment_settings_change_observers_.Clear();
   blob_registry_.reset();
   script_runner_.reset();
@@ -554,9 +561,6 @@
                               base::MessageLoop* message_loop) {
   auto* context = new Impl(name, options);
   context->set_message_loop(message_loop);
-  if (options.service_worker_jobs) {
-    options.service_worker_jobs->RegisterWebContext(context);
-  }
   return context;
 }
 
diff --git a/cobalt/web/cache.cc b/cobalt/web/cache.cc
index f9143a9..3a85cf3 100644
--- a/cobalt/web/cache.cc
+++ b/cobalt/web/cache.cc
@@ -115,6 +115,18 @@
     OnDone(/*success=*/false);
     return;
   }
+  status_text_ = request->response_headers()->GetStatusText();
+  response_code_ = request->response_headers()->response_code();
+  size_t iter = 0;
+  std::string name;
+  std::string value;
+  while (
+      request->response_headers()->EnumerateHeaderLines(&iter, &name, &value)) {
+    base::ListValue header;
+    header.GetList().emplace_back(name);
+    header.GetList().emplace_back(value);
+    headers_.GetList().push_back(std::move(header));
+  }
   int initial_capacity = request->response_headers()->HasHeader(
                              net::HttpRequestHeaders::kContentLength)
                              ? request->response_headers()->GetContentLength()
@@ -141,41 +153,45 @@
 script::HandlePromiseAny Cache::Match(
     script::EnvironmentSettings* environment_settings,
     const script::ValueHandleHolder& request) {
-  script::HandlePromiseAny promise =
-      get_script_value_factory(environment_settings)
-          ->CreateBasicPromise<script::Any>();
-  auto promise_reference =
-      std::make_unique<script::ValuePromiseAny::Reference>(this, promise);
+  auto* isolate = get_isolate(environment_settings);
+  script::v8c::EntryScope entry_scope(isolate);
+  auto resolver =
+      v8::Promise::Resolver::New(isolate->GetCurrentContext()).ToLocalChecked();
+  std::vector<v8::TracedGlobal<v8::Value>*> traced_globals;
+  base::OnceClosure cleanup_traced;
+  cache_utils::Trace(isolate, {resolver}, traced_globals, cleanup_traced);
+  auto traced_resolver = traced_globals[0]->As<v8::Promise::Resolver>();
   auto context = get_context(environment_settings);
   context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](script::EnvironmentSettings* environment_settings, uint32_t key,
-             std::unique_ptr<script::ValuePromiseAny::Reference>
-                 promise_reference) {
-            auto global_environment =
-                get_global_environment(environment_settings);
-            auto* isolate = global_environment->isolate();
+             v8::TracedGlobal<v8::Promise::Resolver> traced_resolver,
+             base::OnceClosure cleanup_traced) {
+            base::ScopedClosureRunner finally(std::move(cleanup_traced));
+            auto* isolate = get_isolate(environment_settings);
             auto cached =
                 cache::Cache::GetInstance()->Retrieve(kResourceType, key);
-            if (!cached) {
-              promise_reference->value().Resolve(
-                  cache_utils::GetUndefined(environment_settings));
+            auto metadata =
+                cache::Cache::GetInstance()->Metadata(kResourceType, key);
+            script::v8c::EntryScope entry_scope(isolate);
+            auto resolver = traced_resolver.Get(isolate);
+            if (!cached || !metadata || !metadata->FindKey("options")) {
+              cache_utils::Resolve(resolver);
               return;
             }
-            script::v8c::EntryScope entry_scope(isolate);
-            auto response = cache_utils::CreateResponse(environment_settings,
-                                                        std::move(cached));
+            auto response = cache_utils::CreateResponse(
+                isolate, *cached, *(metadata->FindKey("options")));
             if (!response) {
-              promise_reference->value().Reject();
-            } else {
-              promise_reference->value().Resolve(script::Any(response.value()));
+              cache_utils::Reject(resolver);
+              return;
             }
+            cache_utils::Resolve(resolver, response.value());
           },
           environment_settings,
-          cache_utils::GetKey(environment_settings, request),
-          std::move(promise_reference)));
-  return promise;
+          cache_utils::GetKey(environment_settings->base_url(), request),
+          traced_resolver, std::move(cleanup_traced)));
+  return cache_utils::FromResolver(resolver);
 }
 
 void Cache::PerformAdd(
@@ -185,7 +201,7 @@
   auto* global_environment = get_global_environment(environment_settings);
   auto* isolate = global_environment->isolate();
   script::v8c::EntryScope entry_scope(isolate);
-  uint32_t key = cache_utils::GetKey(environment_settings,
+  uint32_t key = cache_utils::GetKey(environment_settings->base_url(),
                                      request_reference->referenced_value());
   if (fetchers_.find(key) != fetchers_.end()) {
     base::AutoLock auto_lock(*(fetchers_[key]->lock()));
@@ -201,7 +217,7 @@
   auto* context = get_context(environment_settings);
   fetchers_[key] = std::make_unique<Cache::Fetcher>(
       context->network_module(),
-      GURL(cache_utils::GetUrl(environment_settings,
+      GURL(cache_utils::GetUrl(environment_settings->base_url(),
                                request_reference->referenced_value())),
       base::BindOnce(&Cache::OnFetchCompleted, base::Unretained(this), key));
 }
@@ -209,13 +225,16 @@
 script::HandlePromiseVoid Cache::Add(
     script::EnvironmentSettings* environment_settings,
     const script::ValueHandleHolder& request) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   auto request_reference =
-      std::make_unique<script::ValueHandleHolder::Reference>(this, request);
+      std::make_unique<script::ValueHandleHolder::Reference>(global_wrappable,
+                                                             request);
   script::HandlePromiseVoid promise =
       get_script_value_factory(environment_settings)
           ->CreateBasicPromise<void>();
   auto promise_reference =
-      std::make_unique<script::ValuePromiseVoid::Reference>(this, promise);
+      std::make_unique<script::ValuePromiseVoid::Reference>(global_wrappable,
+                                                            promise);
   auto context = get_context(environment_settings);
   context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
@@ -229,19 +248,38 @@
     script::EnvironmentSettings* environment_settings,
     const script::ValueHandleHolder& request,
     const script::ValueHandleHolder& response) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   auto request_reference =
-      std::make_unique<script::ValueHandleHolder::Reference>(this, request);
+      std::make_unique<script::ValueHandleHolder::Reference>(global_wrappable,
+                                                             request);
   auto response_reference =
-      std::make_unique<script::ValueHandleHolder::Reference>(this, response);
+      std::make_unique<script::ValueHandleHolder::Reference>(global_wrappable,
+                                                             response);
   script::HandlePromiseVoid promise =
       get_script_value_factory(environment_settings)
           ->CreateBasicPromise<void>();
   auto promise_reference =
-      std::make_unique<script::ValuePromiseVoid::Reference>(this, promise);
+      std::make_unique<script::ValuePromiseVoid::Reference>(global_wrappable,
+                                                            promise);
 
-  auto context = get_context(environment_settings);
-  base::SequencedTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
+  auto* global_environment = get_global_environment(environment_settings);
+  auto* isolate = global_environment->isolate();
+  auto context = isolate->GetCurrentContext();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto v8_response =
+      GetV8Value(response_reference->referenced_value()).As<v8::Object>();
+  auto body_used = cache_utils::Get(v8_response, "bodyUsed");
+  if (!body_used || body_used->As<v8::Boolean>()->Value()) {
+    promise_reference->value().Reject(script::kTypeError);
+    return promise;
+  }
+  auto array_buffer_promise = cache_utils::Call(v8_response, "arrayBuffer");
+  if (!array_buffer_promise) {
+    promise_reference->value().Reject();
+    return promise;
+  }
+  cache_utils::Then(
+      array_buffer_promise.value(),
       base::BindOnce(
           [](script::EnvironmentSettings* environment_settings,
              std::unique_ptr<script::ValueHandleHolder::Reference>
@@ -249,131 +287,30 @@
              std::unique_ptr<script::ValueHandleHolder::Reference>
                  response_reference,
              std::unique_ptr<script::ValuePromiseVoid::Reference>
-                 promise_reference) {
-
-            auto* global_environment =
-                get_global_environment(environment_settings);
-            auto* isolate = global_environment->isolate();
-            script::v8c::EntryScope entry_scope(isolate);
-            auto context = global_environment->context();
-            auto maybe_body_used = cache_utils::TryGet(
-                context, GetV8Value(response_reference->referenced_value()),
-                "bodyUsed");
-            if (maybe_body_used.IsEmpty() ||
-                maybe_body_used.ToLocalChecked().As<v8::Boolean>()->Value()) {
-              promise_reference->value().Reject(script::kTypeError);
-              return;
-            }
-            auto maybe_text_function = cache_utils::TryGet(
-                context, GetV8Value(response_reference->referenced_value()),
-                "text");
-            if (maybe_text_function.IsEmpty()) {
+                 promise_reference,
+             v8::Local<v8::Promise> array_buffer_promise)
+              -> base::Optional<v8::Local<v8::Promise>> {
+            uint32_t key =
+                cache_utils::GetKey(environment_settings->base_url(),
+                                    request_reference->referenced_value());
+            std::string url =
+                cache_utils::GetUrl(environment_settings->base_url(),
+                                    request_reference->referenced_value());
+            auto options = cache_utils::ExtractResponseOptions(
+                cache_utils::ToV8Value(response_reference->referenced_value()));
+            if (!options) {
               promise_reference->value().Reject();
-              return;
+              return base::nullopt;
             }
-            auto text_function = maybe_text_function.ToLocalChecked();
-            v8::Local<v8::Value> text_result;
-            auto response_context =
-                script::GetIsolate(response_reference->referenced_value())
-                    ->GetCurrentContext();
-            if (text_function.IsEmpty() || !text_function->IsFunction() ||
-                !(text_function.As<v8::Function>()
-                      ->Call(response_context,
-                             GetV8Value(response_reference->referenced_value()),
-                             /*argc=*/0,
-                             /*argv=*/nullptr)
-                      .ToLocal(&text_result))) {
-              promise_reference->value().Reject();
-              return;
-            }
-            std::string url = cache_utils::GetUrl(
-                environment_settings, request_reference->referenced_value());
-            auto data = v8::Object::New(isolate);
-            cache_utils::Set(context, data, "environment_settings",
-                             v8::External::New(isolate, environment_settings));
-            cache_utils::Set(
-                context, data, "promise_reference",
-                v8::External::New(isolate, promise_reference.release()));
-            cache_utils::Set(
-                context, data, "request_reference",
-                v8::External::New(isolate, request_reference.release()));
-            auto then_callback =
-                v8::Function::New(
-                    context,
-                    [](const v8::FunctionCallbackInfo<v8::Value>& info) {
-                      auto* isolate = info.GetIsolate();
-                      auto context = info.GetIsolate()->GetCurrentContext();
-                      auto* environment_settings =
-                          static_cast<script::EnvironmentSettings*>(
-                              cache_utils::Get(context, info.Data(),
-                                               "environment_settings")
-                                  .As<v8::External>()
-                                  ->Value());
-                      std::unique_ptr<script::ValueHandleHolder::Reference>
-                      request_reference(
-                          static_cast<script::ValueHandleHolder::Reference*>(
-                              cache_utils::Get(context, info.Data(),
-                                               "request_reference")
-                                  .As<v8::External>()
-                                  ->Value()));
-                      std::unique_ptr<script::ValuePromiseVoid::Reference>
-                      promise_reference(
-                          static_cast<script::ValuePromiseVoid::Reference*>(
-                              cache_utils::Get(context, info.Data(),
-                                               "promise_reference")
-                                  .As<v8::External>()
-                                  ->Value()));
-                      uint32_t key = cache_utils::GetKey(
-                          environment_settings,
-                          request_reference->referenced_value());
-                      std::string url = cache_utils::GetUrl(
-                          environment_settings,
-                          request_reference->referenced_value());
-                      std::string body;
-                      FromJSValue(info.GetIsolate(), info[0],
-                                  script::v8c::kNoConversionFlags, nullptr,
-                                  &body);
-                      auto* begin =
-                          reinterpret_cast<const uint8_t*>(body.data());
-                      auto data = std::make_unique<std::vector<uint8_t>>(
-                          begin, begin + body.size());
-                      cache::Cache::GetInstance()->Store(
-                          kResourceType, key, *data, base::Value(url));
-                      promise_reference->value().Resolve();
-                    },
-                    data)
-                    .ToLocalChecked();
-            if (text_result.As<v8::Promise>()
-                    ->Then(context, then_callback)
-                    .IsEmpty()) {
-              promise_reference->value().Reject();
-              return;
-            }
-            auto catch_callback =
-                v8::Function::New(
-                    context,
-                    [](const v8::FunctionCallbackInfo<v8::Value>& info) {
-                      auto* isolate = info.GetIsolate();
-                      auto context = info.GetIsolate()->GetCurrentContext();
-                      std::unique_ptr<script::ValuePromiseVoid::Reference>
-                      promise_reference(
-                          static_cast<script::ValuePromiseVoid::Reference*>(
-                              cache_utils::Get(context, info.Data(),
-                                               "promise_reference")
-                                  .As<v8::External>()
-                                  ->Value()));
-                      promise_reference->value().Reject();
-                    },
-                    data)
-                    .ToLocalChecked();
-            if (text_result.As<v8::Promise>()
-                    ->Catch(context, catch_callback)
-                    .IsEmpty()) {
-              promise_reference->value().Reject();
-              return;
-            }
-            // Run |response.text()| promise.
-            isolate->PerformMicrotaskCheckpoint();
+            base::DictionaryValue metadata;
+            metadata.SetKey("url", base::Value(url));
+            metadata.SetKey("options", std::move(options.value()));
+            cache::Cache::GetInstance()->Store(
+                kResourceType, key,
+                cache_utils::ToUint8Vector(array_buffer_promise->Result()),
+                std::move(metadata));
+            promise_reference->value().Resolve();
+            return base::nullopt;
           },
           environment_settings, std::move(request_reference),
           std::move(response_reference), std::move(promise_reference)));
@@ -383,13 +320,16 @@
 script::HandlePromiseBool Cache::Delete(
     script::EnvironmentSettings* environment_settings,
     const script::ValueHandleHolder& request) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   script::HandlePromiseBool promise =
       get_script_value_factory(environment_settings)
           ->CreateBasicPromise<bool>();
   auto request_reference =
-      std::make_unique<script::ValueHandleHolder::Reference>(this, request);
+      std::make_unique<script::ValueHandleHolder::Reference>(global_wrappable,
+                                                             request);
   auto promise_reference =
-      std::make_unique<script::ValuePromiseBool::Reference>(this, promise);
+      std::make_unique<script::ValuePromiseBool::Reference>(global_wrappable,
+                                                            promise);
   auto context = get_context(environment_settings);
   context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
@@ -406,7 +346,7 @@
             promise_reference->value().Resolve(
                 cache::Cache::GetInstance()->Delete(
                     kResourceType, cache_utils::GetKey(
-                                       environment_settings,
+                                       environment_settings->base_url(),
                                        request_reference->referenced_value())));
           },
           environment_settings, std::move(request_reference),
@@ -416,11 +356,12 @@
 
 script::HandlePromiseAny Cache::Keys(
     script::EnvironmentSettings* environment_settings) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   script::HandlePromiseAny promise =
       get_script_value_factory(environment_settings)
           ->CreateBasicPromise<script::Any>();
-  auto promise_reference =
-      std::make_unique<script::ValuePromiseAny::Reference>(this, promise);
+  auto promise_reference = std::make_unique<script::ValuePromiseAny::Reference>(
+      global_wrappable, promise);
   auto context = get_context(environment_settings);
   context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
@@ -433,17 +374,22 @@
             auto* isolate = global_environment->isolate();
             script::v8c::EntryScope entry_scope(isolate);
             std::vector<v8::Local<v8::Value>> requests;
-            for (uint32_t key :
-                 cache::Cache::GetInstance()->KeysWithMetadata(kResourceType)) {
-              std::unique_ptr<base::Value> url =
+            auto keys =
+                cache::Cache::GetInstance()->KeysWithMetadata(kResourceType);
+            for (uint32_t key : keys) {
+              auto metadata =
                   cache::Cache::GetInstance()->Metadata(kResourceType, key);
-              if (url && url->is_string()) {
-                base::Optional<script::Any> request =
-                    cache_utils::CreateRequest(environment_settings,
-                                               url->GetString());
-                if (request) {
-                  requests.push_back(GetV8Value(*(request->GetScriptValue())));
-                }
+              if (!metadata) {
+                continue;
+              }
+              auto url = metadata->FindKey("url");
+              if (!url) {
+                continue;
+              }
+              base::Optional<v8::Local<v8::Value>> request =
+                  cache_utils::CreateRequest(isolate, url->GetString());
+              if (request) {
+                requests.push_back(std::move(request.value()));
               }
             }
             promise_reference->value().Resolve(
@@ -467,7 +413,9 @@
 void Cache::OnFetchCompletedMainThread(uint32_t key, bool success) {
   auto* fetcher = fetchers_[key].get();
   auto* promises = &(fetch_contexts_[key].first);
-  if (!success) {
+  int status = fetcher->response_code();
+  // |status| of 200-299 excluding 206 "Partial Content" should be cached.
+  if (!success || status == 206 || status < 200 || status > 299) {
     {
       base::AutoLock auto_lock(*fetcher->lock());
       while (promises->size() > 0) {
@@ -480,17 +428,27 @@
     return;
   }
   {
-    cache::Cache::GetInstance()->Store(kResourceType, key,
-                                       fetcher->BufferToVector(),
-                                       base::Value(fetcher->url().spec()));
-    if (fetcher->mime_type() == "text/javascript") {
-      auto* environment_settings = fetch_contexts_[key].second;
-      auto* global_environment = get_global_environment(environment_settings);
-      auto* isolate = global_environment->isolate();
-      script::v8c::EntryScope entry_scope(isolate);
-      global_environment->Compile(script::SourceCode::CreateSourceCode(
-          fetcher->BufferToString(), base::SourceLocation(__FILE__, 1, 1)));
-    }
+    base::DictionaryValue metadata;
+    metadata.SetKey("url", base::Value(fetcher->url().spec()));
+    base::DictionaryValue options;
+    options.SetKey("status", base::Value(status));
+    options.SetKey("statusText", base::Value(fetcher->status_text()));
+    options.SetKey("headers", std::move(fetcher->headers()));
+    metadata.SetKey("options", std::move(options));
+
+    cache::Cache::GetInstance()->Store(
+        kResourceType, key, fetcher->BufferToVector(), std::move(metadata));
+  }
+  if (fetcher->mime_type() == "text/javascript") {
+    auto* environment_settings = fetch_contexts_[key].second;
+    auto* global_environment = get_global_environment(environment_settings);
+    auto* isolate = global_environment->isolate();
+    script::v8c::EntryScope entry_scope(isolate);
+    // TODO: compile async or maybe don't cache if compile fails.
+    global_environment->Compile(script::SourceCode::CreateSourceCode(
+        fetcher->BufferToString(), base::SourceLocation(__FILE__, 1, 1)));
+  }
+  {
     base::AutoLock auto_lock(*fetcher->lock());
     while (promises->size() > 0) {
       promises->back()->value().Resolve();
diff --git a/cobalt/web/cache.h b/cobalt/web/cache.h
index ee09fb7..02e5c88 100644
--- a/cobalt/web/cache.h
+++ b/cobalt/web/cache.h
@@ -72,6 +72,9 @@
 
     const std::string& mime_type() const { return mime_type_; }
     GURL url() const { return url_; }
+    int response_code() const { return response_code_; }
+    const std::string& status_text() const { return status_text_; }
+    base::ListValue headers() { return std::move(headers_); }
     base::Lock* lock() const { return &lock_; }
     std::vector<uint8_t> BufferToVector() const;
     std::string BufferToString() const;
@@ -89,6 +92,9 @@
     std::string mime_type_;
     scoped_refptr<net::GrowableIOBuffer> buffer_;
     int buffer_size_;
+    int response_code_;
+    base::ListValue headers_;
+    std::string status_text_;
     mutable base::Lock lock_;
   };
 
diff --git a/cobalt/web/cache_storage.cc b/cobalt/web/cache_storage.cc
index 222b617..d110a02 100644
--- a/cobalt/web/cache_storage.cc
+++ b/cobalt/web/cache_storage.cc
@@ -51,6 +51,7 @@
 script::HandlePromiseWrappable CacheStorage::Open(
     script::EnvironmentSettings* environment_settings,
     const std::string& cache_name) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   script::HandlePromiseWrappable promise =
       get_script_value_factory(environment_settings)
           ->CreateInterfacePromise<scoped_refptr<Cache>>();
@@ -59,18 +60,20 @@
       FROM_HERE,
       base::BindOnce(&CacheStorage::PerformOpen, base::Unretained(this),
                      std::make_unique<script::ValuePromiseWrappable::Reference>(
-                         this, promise)));
+                         global_wrappable, promise)));
   return promise;
 }
 
 script::HandlePromiseBool CacheStorage::Delete(
     script::EnvironmentSettings* environment_settings,
     const std::string& cache_name) {
+  auto* global_wrappable = get_global_wrappable(environment_settings);
   script::HandlePromiseBool promise =
       get_script_value_factory(environment_settings)
           ->CreateBasicPromise<bool>();
   auto promise_reference =
-      std::make_unique<script::ValuePromiseBool::Reference>(this, promise);
+      std::make_unique<script::ValuePromiseBool::Reference>(global_wrappable,
+                                                            promise);
   auto* context = get_context(environment_settings);
   context->message_loop()->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(
diff --git a/cobalt/web/cache_storage_test.cc b/cobalt/web/cache_storage_test.cc
new file mode 100644
index 0000000..8d9a5d7
--- /dev/null
+++ b/cobalt/web/cache_storage_test.cc
@@ -0,0 +1,138 @@
+// Copyright 2022 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/script/v8c/entry_scope.h"
+#include "cobalt/web/cache_utils.h"
+#include "cobalt/web/testing/test_with_javascript.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace web {
+
+namespace {
+
+class GetGlobalScopeTypeIdWindow : public ::testing::Test {
+ public:
+  base::TypeId GetGlobalScopeTypeId() const {
+    return base::GetTypeId<dom::Window>();
+  }
+};
+
+class CacheStorageTest
+    : public testing::TestWithJavaScriptBase<GetGlobalScopeTypeIdWindow> {};
+
+v8::Local<v8::Value> Await(base::Optional<v8::Local<v8::Value>> promise_value) {
+  EXPECT_TRUE(promise_value.has_value());
+  EXPECT_TRUE(promise_value.value()->IsPromise());
+  auto promise = promise_value->As<v8::Promise>();
+  auto* isolate = promise->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto e = std::make_unique<base::WaitableEvent>();
+  auto result_promise = promise->Then(
+      context,
+      v8::Function::New(context,
+                        [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+                          static_cast<base::WaitableEvent*>(
+                              info.Data().As<v8::External>()->Value())
+                              ->Signal();
+                        },
+                        v8::External::New(isolate, e.get()))
+          .ToLocalChecked());
+  EXPECT_TRUE(!result_promise.IsEmpty());
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  // Ensure promise is scheduled to be resolved.
+  isolate->PerformMicrotaskCheckpoint();
+  e->Wait();
+  EXPECT_TRUE(promise->State() == v8::Promise::PromiseState::kFulfilled);
+  return promise->Result();
+}
+
+base::Value MakeHeader(const std::string& name, const std::string& value) {
+  base::ListValue header;
+  header.GetList().emplace_back(name);
+  header.GetList().emplace_back(value);
+  return std::move(header);
+}
+
+std::vector<uint8_t> ToVector(const std::string& data) {
+  auto* begin = reinterpret_cast<const uint8_t*>(data.data());
+  auto* end = begin + data.size();
+  return std::vector<uint8_t>(begin, end);
+}
+
+}  // namespace
+
+TEST_F(CacheStorageTest, Work) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+
+  auto delete_result =
+      Await(cache_utils::Evaluate(isolate, "caches.delete('test');"));
+  EXPECT_TRUE(delete_result->IsBoolean() &&
+              delete_result.As<v8::Boolean>()->Value());
+
+  auto v8_cache = Await(cache_utils::Evaluate(isolate, "caches.open('test');"));
+  EXPECT_FALSE(v8_cache.IsEmpty());
+  EXPECT_FALSE(v8_cache->IsNullOrUndefined());
+  EXPECT_TRUE(v8_cache->IsObject());
+
+  std::string url = "https://www.example.com/1";
+  auto request = cache_utils::CreateRequest(isolate, url).value();
+  base::DictionaryValue options;
+  options.SetKey("status", base::Value(200));
+  options.SetKey("statusText", base::Value("OK"));
+  base::ListValue headers;
+  headers.GetList().push_back(MakeHeader("a", "1"));
+  options.SetKey("headers", std::move(headers));
+
+  std::string body = "abcde";
+  auto response =
+      cache_utils::CreateResponse(isolate, ToVector(body), options).value();
+  auto v8_put_result =
+      Await(cache_utils::Call(v8_cache, "put", {request, response}));
+  EXPECT_TRUE(v8_put_result->IsUndefined());
+
+  auto v8_match_result = Await(cache_utils::Call(v8_cache, "match", {request}));
+  EXPECT_EQ(200, cache_utils::FromNumber(
+                     cache_utils::Get(v8_match_result, "status").value()));
+  EXPECT_EQ("OK", cache_utils::GetString(v8_match_result, "statusText"));
+  EXPECT_EQ(
+      "1", cache_utils::FromV8String(
+               isolate, cache_utils::Call(v8_match_result, "headers.get",
+                                          {cache_utils::V8String(isolate, "a")})
+                            .value()));
+  auto match_result_options =
+      cache_utils::ExtractResponseOptions(v8_match_result).value();
+  EXPECT_EQ(200, cache_utils::Get(match_result_options, "status")->GetInt());
+  EXPECT_EQ("OK",
+            cache_utils::Get(match_result_options, "statusText")->GetString());
+  EXPECT_EQ(1, match_result_options.FindKey("headers")->GetList().size());
+  EXPECT_EQ("a",
+            cache_utils::Get(match_result_options, "headers.0.0")->GetString());
+  EXPECT_EQ("1",
+            cache_utils::Get(match_result_options, "headers.0.1")->GetString());
+  EXPECT_EQ(body,
+            cache_utils::FromV8String(
+                isolate, Await(cache_utils::Call(v8_match_result, "text"))));
+
+  auto v8_keys_result = Await(cache_utils::Call(v8_cache, "keys"));
+  EXPECT_TRUE(v8_keys_result->IsArray());
+  auto keys = v8_keys_result.As<v8::Array>();
+  EXPECT_EQ(1, keys->Length());
+  EXPECT_EQ(url, cache_utils::GetString(keys, "0.url"));
+}
+
+}  // namespace web
+}  // namespace cobalt
diff --git a/cobalt/web/cache_utils.cc b/cobalt/web/cache_utils.cc
index 92fc5a2..cb40bf1 100644
--- a/cobalt/web/cache_utils.cc
+++ b/cobalt/web/cache_utils.cc
@@ -14,156 +14,505 @@
 
 #include "cobalt/web/cache_utils.h"
 
-#include "cobalt/cache/cache.h"
+#include <algorithm>
+#include <utility>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_split.h"
 #include "cobalt/script/v8c/conversion_helpers.h"
+#include "cobalt/script/v8c/native_promise.h"
 #include "cobalt/web/environment_settings_helper.h"
+#include "starboard/common/murmurhash2.h"
 
 namespace cobalt {
 namespace web {
 namespace cache_utils {
 
 v8::Local<v8::String> V8String(v8::Isolate* isolate, const std::string& s) {
-  return v8::String::NewFromUtf8(isolate, s.c_str()).ToLocalChecked();
+  return v8::String::NewFromUtf8(isolate, s.c_str())
+      .FromMaybe(v8::String::Empty(isolate));
 }
 
-v8::MaybeLocal<v8::Value> TryGet(v8::Local<v8::Context> context,
-                                 v8::Local<v8::Value> object,
-                                 const std::string& key) {
-  if (!object->IsObject()) {
-    return v8::MaybeLocal<v8::Value>();
+std::string FromV8String(v8::Isolate* isolate, v8::Local<v8::Value> value) {
+  if (!value->IsString()) {
+    return "";
   }
-  auto* isolate = context->GetIsolate();
-  return object.As<v8::Object>()->Get(context, V8String(isolate, key));
+  auto v8_string = value.As<v8::String>();
+  std::string result;
+  FromJSValue(isolate, v8_string, script::v8c::kNoConversionFlags, nullptr,
+              &result);
+  return result;
 }
 
-v8::Local<v8::Value> Get(v8::Local<v8::Context> context,
-                         v8::Local<v8::Value> object, const std::string& key) {
-  return TryGet(context, object, key).ToLocalChecked();
+base::Optional<v8::Local<v8::Value>> Parse(v8::Isolate* isolate,
+                                           const std::string& json) {
+  return Evaluate(isolate, "{ const obj = " + json + "; obj; }");
 }
 
-bool Set(v8::Local<v8::Context> context, v8::Local<v8::Value> object,
-         const std::string& key, v8::Local<v8::Value> value) {
-  if (!object->IsObject()) {
-    return false;
-  }
-  auto* isolate = context->GetIsolate();
-  auto result =
-      object.As<v8::Object>()->Set(context, V8String(isolate, key), value);
-  return !result.IsNothing();
+base::Optional<v8::Local<v8::Value>> BaseToV8(v8::Isolate* isolate,
+                                              const base::Value& value) {
+  auto json = std::make_unique<std::string>();
+  base::JSONWriter::WriteWithOptions(
+      value, base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES, json.get());
+  return Parse(isolate, *json);
 }
 
-v8::MaybeLocal<v8::Value> TryCall(v8::Local<v8::Context> context,
-                                  v8::Local<v8::Value> object,
-                                  const std::string& key, int argc,
-                                  v8::Local<v8::Value> argv[]) {
-  v8::Local<v8::Value> function;
-  if (!cache_utils::TryGet(context, object, key).ToLocal(&function) ||
-      function.IsEmpty() || !function->IsFunction()) {
-    return v8::MaybeLocal<v8::Value>();
-  }
-  auto object_context =
-      object.As<v8::Object>()->GetIsolate()->GetCurrentContext();
-  return function.As<v8::Function>()->Call(object_context, object, argc, argv);
-}
-
-script::Any GetUndefined(script::EnvironmentSettings* environment_settings) {
-  auto* global_environment = get_global_environment(environment_settings);
-  auto* isolate = global_environment->isolate();
-  return script::Any(
-      new script::v8c::V8cValueHandleHolder(isolate, v8::Undefined(isolate)));
-}
-
-script::Any EvaluateString(script::EnvironmentSettings* environment_settings,
-                           const std::string& js_code) {
-  auto* global_environment = get_global_environment(environment_settings);
-  auto* wrappable = get_global_wrappable(environment_settings);
-  base::Optional<script::ValueHandleHolder::Reference> reference;
-  scoped_refptr<script::SourceCode> source_code =
-      script::SourceCode::CreateSourceCodeWithoutCaching(
-          js_code, base::SourceLocation(__FILE__, __LINE__, 1));
-  bool eval_enabled = global_environment->IsEvalEnabled();
-  if (!eval_enabled) {
-    global_environment->EnableEval();
-  }
-  bool success =
-      global_environment->EvaluateScript(source_code, wrappable, &reference);
-  if (!eval_enabled) {
-    global_environment->DisableEval("");
-  }
-  if (success && reference) {
-    return script::Any(reference.value());
-  } else {
-    return GetUndefined(environment_settings);
-  }
-}
-
-base::Optional<script::Any> CreateInstance(
-    script::EnvironmentSettings* environment_settings,
-    const std::string& class_name, int argc, v8::Local<v8::Value> argv[]) {
-  auto* global_environment = get_global_environment(environment_settings);
-  auto* isolate = global_environment->isolate();
-  auto reponse_function =
-      cache_utils::EvaluateString(environment_settings, class_name);
-  auto v8_function =
-      script::GetV8Value(*reponse_function.GetScriptValue()).As<v8::Function>();
-  auto context = isolate->GetCurrentContext();
-  auto maybe_instance = v8_function->NewInstance(context, argc, argv);
-  if (maybe_instance.IsEmpty()) {
+base::Optional<v8::Local<v8::Promise>> OptionalPromise(
+    base::Optional<v8::Local<v8::Value>> value) {
+  if (!value || !(*value)->IsPromise()) {
     return base::nullopt;
   }
-  return script::Any(new script::v8c::V8cValueHandleHolder(
-      isolate, maybe_instance.ToLocalChecked()));
+  return value->As<v8::Promise>();
 }
 
-base::Optional<script::Any> CreateRequest(
-    script::EnvironmentSettings* environment_settings, const std::string& url) {
-  auto* global_environment = get_global_environment(environment_settings);
-  auto* isolate = global_environment->isolate();
-  v8::Local<v8::Value> argv[] = {V8String(isolate, url)};
-  return CreateInstance(environment_settings, "Request", /*argc=*/1, argv);
+std::string Stringify(v8::Isolate* isolate, v8::Local<v8::Value> value) {
+  auto global = isolate->GetCurrentContext()->Global();
+  Set(global, "___tempObject", value);
+  auto result = Evaluate(isolate, "JSON.stringify(___tempObject);");
+  Delete(global, "___tempObject");
+  if (!result) {
+    return "";
+  }
+  return FromV8String(isolate, result.value());
 }
 
-base::Optional<script::Any> CreateResponse(
-    script::EnvironmentSettings* environment_settings,
-    std::unique_ptr<std::vector<uint8_t>> data) {
-  auto* global_environment = get_global_environment(environment_settings);
-  auto* isolate = global_environment->isolate();
-  auto array_buffer = v8::ArrayBuffer::New(isolate, data->size());
-  memcpy(array_buffer->GetBackingStore()->Data(), data->data(), data->size());
-  v8::Local<v8::Value> argv[] = {array_buffer};
-  return CreateInstance(environment_settings, "Response", /*argc=*/1, argv);
+base::Optional<base::Value> Deserialize(const std::string& json) {
+  if (json.empty()) {
+    return base::nullopt;
+  }
+  return base::Value::FromUniquePtrValue(base::JSONReader::Read(json));
 }
 
-uint32_t GetKey(const std::string& url) { return cache::Cache::CreateKey(url); }
+base::Optional<base::Value> V8ToBase(v8::Isolate* isolate,
+                                     v8::Local<v8::Value> value) {
+  return Deserialize(Stringify(isolate, value));
+}
 
-uint32_t GetKey(script::EnvironmentSettings* environment_settings,
+template <typename T>
+base::Optional<v8::Local<T>> ToOptional(v8::MaybeLocal<T> value) {
+  if (value.IsEmpty()) {
+    return base::nullopt;
+  }
+  return value.ToLocalChecked();
+}
+
+v8::Isolate* GetIsolate(v8::Local<v8::Value> object) {
+  if (!object->IsObject()) {
+    return nullptr;
+  }
+  return object.As<v8::Object>()->GetIsolate();
+}
+
+base::Optional<v8::Local<v8::Value>> GetInternal(v8::Local<v8::Value> object,
+                                                 const std::string& path,
+                                                 bool parent) {
+  auto* isolate = GetIsolate(object);
+  if (!isolate) {
+    return base::nullopt;
+  }
+
+  base::Optional<v8::Local<v8::Value>> curr = object;
+  auto context = isolate->GetCurrentContext();
+  auto parts = base::SplitString(path, ".", base::TRIM_WHITESPACE,
+                                 base::SPLIT_WANT_NONEMPTY);
+  int offset = parent ? -1 : 0;
+  for (int i = 0; i < parts.size() + offset; i++) {
+    if (!curr || !curr.value()->IsObject()) {
+      return base::nullopt;
+    }
+    std::string part = parts[i];
+    if (base::ContainsOnlyChars(part, "0123456789")) {
+      uint32_t index;
+      if (!base::StringToUint32(part, &index)) {
+        return base::nullopt;
+      }
+      curr = ToOptional(curr->As<v8::Object>()->Get(context, index));
+    } else {
+      curr = ToOptional(
+          curr->As<v8::Object>()->Get(context, V8String(isolate, part)));
+    }
+  }
+  return curr;
+}
+
+base::Optional<v8::Local<v8::Value>> Get(v8::Local<v8::Value> object,
+                                         const std::string& path) {
+  return GetInternal(object, path, /*parent=*/false);
+}
+
+const base::Value* Get(const base::Value& value, const std::string& path,
+                       bool parent) {
+  if (!value.is_dict() && !value.is_list()) {
+    return nullptr;
+  }
+  const base::Value* curr = &value;
+  auto parts = base::SplitString(path, ".", base::TRIM_WHITESPACE,
+                                 base::SPLIT_WANT_NONEMPTY);
+  int offset = parent ? -1 : 0;
+  for (int i = 0; i < parts.size() + offset; i++) {
+    std::string part = parts[i];
+    if (curr->is_list()) {
+      uint32_t index;
+      if (!base::StringToUint32(part, &index)) {
+        return nullptr;
+      }
+      if (index > curr->GetList().size() - 1) {
+        return nullptr;
+      }
+      curr = &curr->GetList()[index];
+    } else if (curr->is_dict()) {
+      curr = curr->FindKey(part);
+    } else {
+      return nullptr;
+    }
+  }
+  return curr;
+}
+
+template <typename T>
+using V8Transform =
+    std::function<base::Optional<T>(v8::Isolate*, v8::Local<v8::Value>)>;
+
+struct V8Transforms {
+  static base::Optional<double> ToDouble(v8::Isolate* isolate,
+                                         v8::Local<v8::Value> value) {
+    if (!value->IsNumber()) {
+      return base::nullopt;
+    }
+    return value.As<v8::Number>()->Value();
+  }
+
+  static base::Optional<std::string> ToString(v8::Isolate* isolate,
+                                              v8::Local<v8::Value> value) {
+    if (!value->IsString()) {
+      return base::nullopt;
+    }
+    auto v8_string = value.As<v8::String>();
+    std::string result;
+    FromJSValue(isolate, v8_string, script::v8c::kNoConversionFlags, nullptr,
+                &result);
+    return std::move(result);
+  }
+
+};  // V8Transforms
+
+template <typename T>
+base::Optional<T> Get(v8::Local<v8::Value> object, const std::string& path,
+                      V8Transform<T> transform) {
+  auto value = GetInternal(object, path, /*parent=*/false);
+  if (!value) {
+    return base::nullopt;
+  }
+  return transform(GetIsolate(object), value.value());
+}
+
+base::Optional<std::string> GetString(v8::Local<v8::Value> object,
+                                      const std::string& path) {
+  return Get<std::string>(object, path, V8Transforms::ToString);
+}
+
+base::Optional<double> GetNumber(v8::Local<v8::Value> object,
+                                 const std::string& path) {
+  return Get<double>(object, path, V8Transforms::ToDouble);
+}
+
+bool Set(v8::Local<v8::Object> object, const std::string& key,
+         v8::Local<v8::Value> value) {
+  auto* isolate = object->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto result = object->Set(context, V8String(isolate, key), value);
+  return result.FromMaybe(false);
+}
+
+bool Delete(v8::Local<v8::Object> object, const std::string& key) {
+  auto* isolate = object->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto result = object->Delete(context, V8String(isolate, key));
+  return result.FromMaybe(false);
+}
+
+double FromNumber(v8::Local<v8::Value> value) {
+  return value.As<v8::Number>()->Value();
+}
+
+v8::Local<v8::Number> ToNumber(v8::Isolate* isolate, double d) {
+  return v8::Number::New(isolate, d);
+}
+
+std::vector<uint8_t> ToUint8Vector(v8::Local<v8::Value> buffer) {
+  if (!buffer->IsArrayBuffer()) {
+    return std::vector<uint8_t>();
+  }
+  auto array_buffer = buffer.As<v8::ArrayBuffer>();
+  auto byte_length = array_buffer->ByteLength();
+  auto uint8_array =
+      v8::Uint8Array::New(array_buffer, /*byte_offset=*/0, byte_length);
+  auto vector = std::vector<uint8_t>(byte_length);
+  uint8_array->CopyContents(vector.data(), byte_length);
+  return std::move(vector);
+}
+
+base::Optional<v8::Local<v8::Value>> Call(
+    v8::Local<v8::Value> object, const std::string& path,
+    std::initializer_list<v8::Local<v8::Value>> args) {
+  if (!object->IsObject()) {
+    return base::nullopt;
+  }
+  v8::Local<v8::Value> result;
+  auto optional_function = cache_utils::Get(object, path);
+  if (!optional_function || !optional_function.value()->IsFunction()) {
+    return base::nullopt;
+  }
+  auto context_object =
+      cache_utils::GetInternal(object, path, /*parent=*/true).value();
+  auto context =
+      context_object.As<v8::Object>()->GetIsolate()->GetCurrentContext();
+  const size_t argc = args.size();
+  std::vector<v8::Local<v8::Value>> argv = args;
+  return ToOptional(optional_function->As<v8::Function>()->Call(
+      context, context_object, argv.size(), argv.data()));
+}
+
+base::Optional<v8::Local<v8::Value>> Then(v8::Local<v8::Value> value,
+                                          OnFullfilled on_fullfilled) {
+  if (!value->IsPromise()) {
+    on_fullfilled.Reset();
+    return base::nullopt;
+  }
+  auto promise = value.As<v8::Promise>();
+  auto* isolate = promise->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto data = v8::Object::New(isolate);
+  Set(data, "promise", promise);
+  auto* on_fullfilled_ptr = new OnFullfilled(std::move(on_fullfilled));
+  Set(data, "onFullfilled", v8::External::New(isolate, on_fullfilled_ptr));
+  auto resulting_promise = promise->Then(
+      context,
+      v8::Function::New(
+          context,
+          [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+            auto promise = Get(info.Data(), "promise")->As<v8::Promise>();
+            auto on_fullfilled = std::unique_ptr<OnFullfilled>(
+                static_cast<OnFullfilled*>(Get(info.Data(), "onFullfilled")
+                                               ->As<v8::External>()
+                                               ->Value()));
+            auto optional_resulting_promise =
+                std::move(*on_fullfilled).Run(promise);
+            if (!optional_resulting_promise) {
+              return;
+            }
+            info.GetReturnValue().Set(optional_resulting_promise.value());
+          },
+          data)
+          .ToLocalChecked(),
+      v8::Function::New(
+          context,
+          [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+            auto on_fullfilled = std::unique_ptr<OnFullfilled>(
+                static_cast<OnFullfilled*>(Get(info.Data(), "onFullfilled")
+                                               ->As<v8::External>()
+                                               ->Value()));
+            on_fullfilled->Reset();
+            info.GetIsolate()->ThrowException(info[0]);
+          },
+          data)
+          .ToLocalChecked());
+  if (resulting_promise.IsEmpty()) {
+    delete on_fullfilled_ptr;
+    return base::nullopt;
+  }
+  return resulting_promise.ToLocalChecked();
+}
+
+void Resolve(v8::Local<v8::Promise::Resolver> resolver,
+             v8::Local<v8::Value> value) {
+  auto* isolate = resolver->GetIsolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto context = isolate->GetCurrentContext();
+  if (value.IsEmpty()) {
+    value = v8::Undefined(isolate);
+  }
+  auto result = resolver->Resolve(context, value);
+  DCHECK(result.FromJust());
+}
+
+void Reject(v8::Local<v8::Promise::Resolver> resolver) {
+  auto* isolate = resolver->GetIsolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto context = isolate->GetCurrentContext();
+  auto result = resolver->Reject(context, v8::Undefined(isolate));
+  DCHECK(result.FromJust());
+}
+
+script::HandlePromiseAny FromResolver(
+    v8::Local<v8::Promise::Resolver> resolver) {
+  auto* isolate = resolver->GetIsolate();
+  return script::HandlePromiseAny(
+      new script::v8c::V8cUserObjectHolder<
+          script::v8c::NativePromise<script::Any>>(isolate, resolver));
+}
+
+void Trace(v8::Isolate* isolate,
+           std::initializer_list<v8::Local<v8::Value>> values,
+           std::vector<v8::TracedGlobal<v8::Value>*>& traced_globals_out,
+           base::OnceClosure& cleanup_traced) {
+  auto heap_tracer =
+      script::v8c::V8cEngine::GetFromIsolate(isolate)->heap_tracer();
+  std::vector<std::unique_ptr<v8::TracedGlobal<v8::Value>>> traced_globals;
+  for (auto value : values) {
+    auto traced_global =
+        std::make_unique<v8::TracedGlobal<v8::Value>>(isolate, value);
+    heap_tracer->AddRoot(traced_global.get());
+    traced_globals_out.push_back(traced_global.get());
+    traced_globals.push_back(std::move(traced_global));
+  }
+  cleanup_traced = base::BindOnce(
+      [](script::v8c::V8cHeapTracer* heap_tracer,
+         std::vector<std::unique_ptr<v8::TracedGlobal<v8::Value>>>
+             traced_globals) {
+        for (int i = 0; i < traced_globals.size(); i++) {
+          heap_tracer->RemoveRoot(traced_globals[i].get());
+        }
+      },
+      heap_tracer, std::move(traced_globals));
+}
+
+script::Any FromV8Value(v8::Isolate* isolate, v8::Local<v8::Value> value) {
+  return script::Any(new script::v8c::V8cValueHandleHolder(isolate, value));
+}
+
+v8::Local<v8::Value> ToV8Value(const script::Any& any) {
+  return script::GetV8Value(*any.GetScriptValue());
+}
+
+base::Optional<v8::Local<v8::Value>> Evaluate(v8::Isolate* isolate,
+                                              const std::string& js_code) {
+  auto context = isolate->GetCurrentContext();
+  auto script = v8::Script::Compile(context, V8String(isolate, js_code));
+  if (script.IsEmpty()) {
+    return base::nullopt;
+  }
+  return ToOptional(script.ToLocalChecked()->Run(context));
+}
+
+base::Optional<v8::Local<v8::Value>> CreateInstance(
+    v8::Isolate* isolate, const std::string& class_name,
+    std::initializer_list<v8::Local<v8::Value>> args) {
+  auto constructor = Evaluate(isolate, class_name);
+  if (!constructor) {
+    return base::nullopt;
+  }
+  auto context = isolate->GetCurrentContext();
+  std::vector<v8::Local<v8::Value>> argv = args;
+  return ToOptional(constructor.value().As<v8::Function>()->NewInstance(
+      context, argv.size(), argv.data()));
+}
+
+base::Optional<v8::Local<v8::Value>> CreateRequest(v8::Isolate* isolate,
+                                                   const std::string& url,
+                                                   const base::Value& options) {
+  auto v8_options = v8::Object::New(isolate);
+  auto mode = options.FindKey("mode");
+  if (mode) {
+    Set(v8_options, "mode", V8String(isolate, mode->GetString()));
+  }
+  auto headers = options.FindKey("headers");
+  if (headers) {
+    auto v8_headers = v8::Object::New(isolate);
+    for (const auto& header : headers->GetList()) {
+      const auto& pair = header.GetList();
+      DCHECK(pair.size() == 2);
+      auto name = pair[0].GetString();
+      auto value = pair[1].GetString();
+      Set(v8_headers, name, V8String(isolate, value));
+    }
+    Set(v8_options, "headers", v8_headers);
+  }
+  return CreateInstance(isolate, "Request",
+                        {V8String(isolate, url), v8_options});
+}
+
+base::Optional<v8::Local<v8::Value>> CreateResponse(
+    v8::Isolate* isolate, const std::vector<uint8_t>& body,
+    const base::Value& options) {
+  auto status = options.FindKey("status");
+  auto status_text = options.FindKey("statusText");
+  auto headers = options.FindKey("headers");
+  if (body.size() == 0 || !status || !status_text || !headers) {
+    return base::nullopt;
+  }
+  auto v8_body = v8::ArrayBuffer::New(isolate, body.size());
+  memcpy(v8_body->GetBackingStore()->Data(), body.data(), body.size());
+  auto v8_options = v8::Object::New(isolate);
+  Set(v8_options, "status", ToNumber(isolate, status->GetDouble()));
+  Set(v8_options, "statusText", V8String(isolate, status_text->GetString()));
+  auto v8_headers = v8::Object::New(isolate);
+  for (const auto& header : headers->GetList()) {
+    const auto& pair = header.GetList();
+    DCHECK(pair.size() == 2);
+    auto name = pair[0].GetString();
+    auto value = pair[1].GetString();
+    Set(v8_headers, name, V8String(isolate, value));
+  }
+  Set(v8_options, "headers", v8_headers);
+  return CreateInstance(isolate, "Response", {v8_body, v8_options});
+}
+
+base::Optional<base::Value> ExtractResponseOptions(
+    v8::Local<v8::Value> response) {
+  if (!response->IsObject()) {
+    return base::nullopt;
+  }
+  auto response_object = response.As<v8::Object>();
+  auto* isolate = response_object->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto global = context->Global();
+  Set(global, "___tempResponseObject", response_object);
+  auto result = Evaluate(isolate,
+                         "(() =>"
+                         "___tempResponseObject instanceof Response && {"
+                         "status: ___tempResponseObject.status,"
+                         "statusText: ___tempResponseObject.statusText,"
+                         "headers: Array.from(___tempResponseObject.headers),"
+                         "}"
+                         ")()");
+  Delete(global, "___tempResponseObject");
+  if (!result) {
+    return base::nullopt;
+  }
+  return V8ToBase(isolate, result.value());
+}
+
+uint32_t GetKey(const std::string& s) {
+  return starboard::MurmurHash2_32(s.c_str(), s.size());
+}
+
+uint32_t GetKey(const GURL& base_url,
                 const script::ValueHandleHolder& request_info) {
-  return GetKey(GetUrl(environment_settings, request_info));
+  return GetKey(GetUrl(base_url, request_info));
 }
 
-std::string GetUrl(script::EnvironmentSettings* environment_settings,
+std::string GetUrl(const GURL& base_url,
                    const script::ValueHandleHolder& request_info) {
   auto v8_value = GetV8Value(request_info);
   auto* isolate = GetIsolate(request_info);
-  v8::Local<v8::String> v8_string;
-  if (v8_value->IsString()) {
-    v8_string = v8_value.As<v8::String>();
-  } else {
-    auto context = isolate->GetCurrentContext();
-    // Treat like |Request| and get "url" property.
-    v8_string = Get(context, v8_value, "url").As<v8::String>();
-  }
   std::string url;
-  FromJSValue(isolate, v8_string, script::v8c::kNoConversionFlags, nullptr,
-              &url);
+  if (v8_value->IsString()) {
+    url = FromV8String(isolate, v8_value);
+  } else {
+    // Treat like |Request| and get "url" property.
+    auto v8_url = Get(v8_value, "url");
+    if (!v8_url) {
+      return "";
+    }
+    url = FromV8String(isolate, v8_url.value());
+  }
   GURL::Replacements replacements;
   replacements.ClearUsername();
   replacements.ClearPassword();
   replacements.ClearRef();
-  return environment_settings->base_url()
-      .Resolve(url)
-      .ReplaceComponents(replacements)
-      .spec();
+  return base_url.Resolve(url).ReplaceComponents(replacements).spec();
 }
 
 }  // namespace cache_utils
diff --git a/cobalt/web/cache_utils.h b/cobalt/web/cache_utils.h
index 0ed4c1b..25958f8 100644
--- a/cobalt/web/cache_utils.h
+++ b/cobalt/web/cache_utils.h
@@ -15,87 +15,136 @@
 #ifndef COBALT_WEB_CACHE_UTILS_H_
 #define COBALT_WEB_CACHE_UTILS_H_
 
+#include <initializer_list>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "base/bind.h"
+#include "base/optional.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/values.h"
 #include "cobalt/script/environment_settings.h"
 #include "cobalt/script/script_value_factory.h"
 #include "cobalt/script/value_handle.h"
+#include "url/gurl.h"
 #include "v8/include/v8.h"
 
 namespace cobalt {
 namespace web {
 namespace cache_utils {
 
+using OnFullfilled = base::OnceCallback<base::Optional<v8::Local<v8::Promise>>(
+    v8::Local<v8::Promise>)>;
+
 v8::Local<v8::String> V8String(v8::Isolate* isolate, const std::string& s);
 
-v8::MaybeLocal<v8::Value> TryGet(v8::Local<v8::Context> context,
-                                 v8::Local<v8::Value> object,
-                                 const std::string& key);
+std::string FromV8String(v8::Isolate* isolate, v8::Local<v8::Value> value);
 
-v8::Local<v8::Value> Get(v8::Local<v8::Context> context,
-                         v8::Local<v8::Value> object, const std::string& key);
+base::Optional<v8::Local<v8::Promise>> OptionalPromise(
+    base::Optional<v8::Local<v8::Value>> value);
+
+const base::Value* Get(const base::Value& value, const std::string& path,
+                       bool parent = false);
+
+base::Optional<v8::Local<v8::Value>> Get(v8::Local<v8::Value> object,
+                                         const std::string& path);
 
 template <typename T>
-inline T* GetExternal(v8::Local<v8::Context> context,
-                      v8::Local<v8::Value> object, const std::string& key) {
-  return static_cast<T*>(
-      web::cache_utils::Get(context, object, key).As<v8::External>()->Value());
+inline T* GetExternal(v8::Local<v8::Value> object, const std::string& path) {
+  base::Optional<v8::Local<v8::Value>> value = Get(object, path);
+  if (!value) {
+    return nullptr;
+  }
+  return static_cast<T*>(value->As<v8::External>()->Value());
 }
 
 template <typename T>
-inline std::unique_ptr<T> GetOwnedExternal(v8::Local<v8::Context> context,
-                                           v8::Local<v8::Value> object,
-                                           const std::string& key) {
-  return std::unique_ptr<T>(
-      web::cache_utils::GetExternal<T>(context, object, key));
+inline std::unique_ptr<T> GetOwnedExternal(v8::Local<v8::Object> object,
+                                           const std::string& path) {
+  return std::unique_ptr<T>(web::cache_utils::GetExternal<T>(object, path));
 }
 
-bool Set(v8::Local<v8::Context> context, v8::Local<v8::Value> object,
-         const std::string& key, v8::Local<v8::Value> value);
+base::Optional<double> GetNumber(v8::Local<v8::Value> object,
+                                 const std::string& path);
+base::Optional<std::string> GetString(v8::Local<v8::Value> object,
+                                      const std::string& path);
 
+bool Set(v8::Local<v8::Object> object, const std::string& key,
+         v8::Local<v8::Value> value);
 
 template <typename T>
-inline bool SetExternal(v8::Local<v8::Context> context,
-                        v8::Local<v8::Value> object, const std::string& key,
+inline bool SetExternal(v8::Local<v8::Object> object, const std::string& key,
                         T* value) {
-  auto* isolate = context->GetIsolate();
-  return Set(context, object, key, v8::External::New(isolate, value));
+  auto* isolate = object->GetIsolate();
+  return Set(object, key, v8::External::New(isolate, value));
 }
 
 template <typename T>
-inline bool SetOwnedExternal(v8::Local<v8::Context> context,
-                             v8::Local<v8::Value> object,
+inline bool SetOwnedExternal(v8::Local<v8::Object> object,
                              const std::string& key, std::unique_ptr<T> value) {
-  return SetExternal<T>(context, object, key, value.release());
+  return SetExternal<T>(object, key, value.release());
 }
 
-v8::MaybeLocal<v8::Value> TryCall(v8::Local<v8::Context> context,
-                                  v8::Local<v8::Value> object,
-                                  const std::string& key, int argc = 0,
-                                  v8::Local<v8::Value> argv[] = nullptr);
+bool Delete(v8::Local<v8::Object> object, const std::string& key);
 
-script::Any GetUndefined(script::EnvironmentSettings* environment_settings);
+base::Optional<v8::Local<v8::Value>> Call(
+    v8::Local<v8::Value> object, const std::string& key,
+    std::initializer_list<v8::Local<v8::Value>> args = {});
+base::Optional<v8::Local<v8::Value>> Then(v8::Local<v8::Value> value,
+                                          OnFullfilled on_fullfilled);
+void Resolve(v8::Local<v8::Promise::Resolver> resolver,
+             v8::Local<v8::Value> value = v8::Local<v8::Value>());
+void Reject(v8::Local<v8::Promise::Resolver> resolver);
+script::HandlePromiseAny FromResolver(
+    v8::Local<v8::Promise::Resolver> resolver);
 
-script::Any EvaluateString(script::EnvironmentSettings* environment_settings,
-                           const std::string& js_code);
+// Keeps |values| from being garbage collected until |cleanup_traced| is run.
+// The caller needs |traced_globals_out| to get a valid reference of the
+// |v8::Value|. To get a reference, the caller needs to create a
+// |v8::HandleScope| and then call |v8::TracedGlobal::Get| to get a valid
+// |v8::Value|.
+// |values| will have a 1:1 relationship with |traced_globals_out|.
+// It is up to the caller to ensure that |cleanup_traced| is run in all
+// possible code paths.
+void Trace(v8::Isolate* isolate,
+           std::initializer_list<v8::Local<v8::Value>> values,
+           std::vector<v8::TracedGlobal<v8::Value>*>& traced_globals_out,
+           base::OnceClosure& cleanup_traced);
 
-base::Optional<script::Any> CreateInstance(
-    script::EnvironmentSettings* environment_settings,
-    const std::string& class_name, int argc, v8::Local<v8::Value> argv[]);
-base::Optional<script::Any> CreateRequest(
-    script::EnvironmentSettings* environment_settings, const std::string& url);
-base::Optional<script::Any> CreateResponse(
-    script::EnvironmentSettings* environment_settings,
-    std::unique_ptr<std::vector<uint8_t>> data);
+std::string Stringify(v8::Isolate* isolate, v8::Local<v8::Value> value);
+base::Optional<v8::Local<v8::Value>> BaseToV8(v8::Isolate* isolate,
+                                              const base::Value& value);
+base::Optional<base::Value> Deserialize(const std::string& json);
+base::Optional<base::Value> V8ToBase(v8::Isolate* isolate,
+                                     v8::Local<v8::Value> value);
 
-uint32_t GetKey(const std::string& url);
+double FromNumber(v8::Local<v8::Value> value);
+v8::Local<v8::Number> ToNumber(v8::Isolate* isolate, double d);
 
-uint32_t GetKey(script::EnvironmentSettings* environment_settings,
+std::vector<uint8_t> ToUint8Vector(v8::Local<v8::Value> buffer);
+
+script::Any FromV8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
+v8::Local<v8::Value> ToV8Value(const script::Any& any);
+
+base::Optional<v8::Local<v8::Value>> Evaluate(v8::Isolate* isolate,
+                                              const std::string& js_code);
+
+base::Optional<v8::Local<v8::Value>> CreateRequest(
+    v8::Isolate* isolate, const std::string& url,
+    const base::Value& options = base::DictionaryValue());
+base::Optional<v8::Local<v8::Value>> CreateResponse(
+    v8::Isolate* isolate, const std::vector<uint8_t>& body,
+    const base::Value& options);
+base::Optional<base::Value> ExtractResponseOptions(
+    v8::Local<v8::Value> response);
+
+uint32_t GetKey(const std::string& s);
+
+uint32_t GetKey(const GURL& base_url,
                 const script::ValueHandleHolder& request_info);
 
-std::string GetUrl(script::EnvironmentSettings* environment_settings,
+std::string GetUrl(const GURL& base_url,
                    const script::ValueHandleHolder& request_info);
 
 }  // namespace cache_utils
diff --git a/cobalt/web/cache_utils_test.cc b/cobalt/web/cache_utils_test.cc
new file mode 100644
index 0000000..3e62bb8
--- /dev/null
+++ b/cobalt/web/cache_utils_test.cc
@@ -0,0 +1,230 @@
+// Copyright 2022 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/web/cache_utils.h"
+
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "cobalt/script/v8c/entry_scope.h"
+#include "cobalt/web/agent.h"
+#include "cobalt/web/context.h"
+#include "cobalt/web/testing/test_with_javascript.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace web {
+
+namespace {
+
+v8::Local<v8::Value> ExpectState(
+    base::Optional<v8::Local<v8::Value>> promise_value,
+    v8::Promise::PromiseState expected) {
+  EXPECT_TRUE(promise_value.has_value());
+  EXPECT_TRUE(promise_value.value()->IsPromise());
+  auto promise = promise_value->As<v8::Promise>();
+  auto* isolate = promise->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto e = std::make_unique<base::WaitableEvent>();
+  auto fulfilled_promise = promise->Then(
+      context,
+      v8::Function::New(context,
+                        [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+                          static_cast<base::WaitableEvent*>(
+                              info.Data().As<v8::External>()->Value())
+                              ->Signal();
+                        },
+                        v8::External::New(isolate, e.get()))
+          .ToLocalChecked());
+  auto rejected_promise = promise->Catch(
+      context,
+      v8::Function::New(context,
+                        [](const v8::FunctionCallbackInfo<v8::Value>& info) {
+                          static_cast<base::WaitableEvent*>(
+                              info.Data().As<v8::External>()->Value())
+                              ->Signal();
+                        },
+                        v8::External::New(isolate, e.get()))
+          .ToLocalChecked());
+  EXPECT_TRUE(!fulfilled_promise.IsEmpty());
+  EXPECT_TRUE(!rejected_promise.IsEmpty());
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  // Ensure promise is scheduled to be resolved.
+  isolate->PerformMicrotaskCheckpoint();
+  e->Wait();
+  EXPECT_TRUE(promise->State() == expected);
+  return promise->Result();
+}
+
+class GetGlobalScopeTypeIdWindow : public ::testing::Test {
+ public:
+  base::TypeId GetGlobalScopeTypeId() const {
+    return base::GetTypeId<dom::Window>();
+  }
+};
+
+class CacheUtilsTest
+    : public testing::TestWithJavaScriptBase<GetGlobalScopeTypeIdWindow> {};
+
+}  // namespace
+
+TEST_F(CacheUtilsTest, Eval) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto v8_this = v8::Object::New(isolate);
+  cache_utils::Set(v8_this, "a", v8::Number::New(isolate, 1.0));
+  EXPECT_TRUE(v8_this->IsObject());
+  EXPECT_DOUBLE_EQ(1.0,
+                   cache_utils::Get(v8_this, "a")->As<v8::Number>()->Value());
+  auto context = isolate->GetCurrentContext();
+  auto global = context->Global();
+  cache_utils::Set(global, "obj", v8_this);
+  auto result =
+      cache_utils::Evaluate(isolate, "obj.a++; obj;")->As<v8::Object>();
+
+  EXPECT_DOUBLE_EQ(2.0,
+                   cache_utils::Get(result, "a")->As<v8::Number>()->Value());
+  EXPECT_DOUBLE_EQ(2.0,
+                   cache_utils::Get(v8_this, "a")->As<v8::Number>()->Value());
+}
+
+TEST_F(CacheUtilsTest, ResponseHeaders) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  std::string body_string = "body";
+  auto* body_begin = reinterpret_cast<const uint8_t*>(body_string.data());
+  auto* body_end = body_begin + body_string.size();
+  std::vector<uint8_t> body(body_begin, body_end);
+  base::DictionaryValue initial_options;
+  initial_options.SetKey("status", base::Value(200));
+  initial_options.SetKey("statusText", base::Value("OK"));
+  base::ListValue initial_headers;
+  base::ListValue header_1;
+  header_1.GetList().emplace_back("a");
+  header_1.GetList().emplace_back("1");
+  initial_headers.GetList().push_back(std::move(header_1));
+  base::ListValue header_2;
+  header_2.GetList().emplace_back("b");
+  header_2.GetList().emplace_back("2");
+  initial_headers.GetList().push_back(std::move(header_2));
+  initial_options.SetKey("headers", std::move(initial_headers));
+  auto response =
+      cache_utils::CreateResponse(isolate, body, initial_options).value();
+
+  EXPECT_DOUBLE_EQ(200, cache_utils::FromNumber(
+                            cache_utils::Get(response, "status").value()));
+  EXPECT_EQ("OK",
+            cache_utils::FromV8String(
+                isolate, cache_utils::Get(response, "statusText").value()));
+  base::Value options = cache_utils::ExtractResponseOptions(response).value();
+
+  EXPECT_DOUBLE_EQ(200, cache_utils::Get(options, "status")->GetDouble());
+  EXPECT_EQ("OK", cache_utils::Get(options, "statusText")->GetString());
+  EXPECT_EQ(2, cache_utils::Get(options, "headers")->GetList().size());
+  EXPECT_EQ("a", cache_utils::Get(options, "headers.0.0")->GetString());
+  EXPECT_EQ("1", cache_utils::Get(options, "headers.0.1")->GetString());
+  EXPECT_EQ("b", cache_utils::Get(options, "headers.1.0")->GetString());
+  EXPECT_EQ("2", cache_utils::Get(options, "headers.1.1")->GetString());
+}
+
+TEST_F(CacheUtilsTest, BaseToV8) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  std::string json = R"~({
+  "options": {
+    "headers": [["a", "1"], ["b", "2"]],
+    "status": 200,
+    "statusText": "OK"
+  },
+  "url": "https://www.example.com/1"
+})~";
+  base::Value base_value = cache_utils::Deserialize(json).value();
+  auto v8_value = cache_utils::BaseToV8(isolate, base_value).value();
+  EXPECT_TRUE(v8_value->IsObject());
+  EXPECT_EQ("https://www.example.com/1",
+            cache_utils::GetString(v8_value, "url"));
+  EXPECT_DOUBLE_EQ(200,
+                   cache_utils::GetNumber(v8_value, "options.status").value());
+  EXPECT_EQ("OK", cache_utils::GetString(v8_value, "options.statusText"));
+  EXPECT_EQ("a", cache_utils::GetString(v8_value, "options.headers.0.0"));
+  EXPECT_EQ("1", cache_utils::GetString(v8_value, "options.headers.0.1"));
+  EXPECT_EQ("b", cache_utils::GetString(v8_value, "options.headers.1.0"));
+  EXPECT_EQ("2", cache_utils::GetString(v8_value, "options.headers.1.1"));
+
+  EXPECT_EQ(base_value, cache_utils::V8ToBase(isolate, v8_value));
+}
+
+TEST_F(CacheUtilsTest, ThenFulfilled) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto promise =
+      cache_utils::Evaluate(isolate, "Promise.resolve('success')").value();
+  auto still_fulfilled_promise = cache_utils::Then(
+      promise, base::BindOnce([&](v8::Local<v8::Promise> p)
+                                  -> base::Optional<v8::Local<v8::Promise>> {
+        auto* isolate = p->GetIsolate();
+        std::string new_message =
+            "still " + cache_utils::FromV8String(isolate, p->Result());
+        return cache_utils::Evaluate(isolate,
+                                     base::StringPrintf("Promise.resolve('%s')",
+                                                        new_message.c_str()))
+            ->As<v8::Promise>();
+      }));
+  auto promise_result = ExpectState(still_fulfilled_promise,
+                                    v8::Promise::PromiseState::kFulfilled);
+  EXPECT_EQ("still success",
+            cache_utils::FromV8String(isolate, promise_result));
+}
+
+TEST_F(CacheUtilsTest, ThenFulfilledThenRejected) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto promise =
+      cache_utils::Evaluate(isolate, "Promise.resolve('success')").value();
+  auto rejected_promise = cache_utils::Then(
+      promise, base::BindOnce([&](v8::Local<v8::Promise> p)
+                                  -> base::Optional<v8::Local<v8::Promise>> {
+        auto* isolate = p->GetIsolate();
+        std::string new_message =
+            "no longer " + cache_utils::FromV8String(isolate, p->Result());
+        return cache_utils::Evaluate(isolate,
+                                     base::StringPrintf("Promise.reject('%s')",
+                                                        new_message.c_str()))
+            ->As<v8::Promise>();
+      }));
+  auto promise_result =
+      ExpectState(rejected_promise, v8::Promise::PromiseState::kRejected);
+  EXPECT_EQ("no longer success",
+            cache_utils::FromV8String(isolate, promise_result));
+}
+
+TEST_F(CacheUtilsTest, ThenRejected) {
+  auto* isolate = web_context()->global_environment()->isolate();
+  script::v8c::EntryScope entry_scope(isolate);
+  auto promise =
+      cache_utils::Evaluate(isolate, "Promise.reject('fail')").value();
+  auto still_rejected_promise = cache_utils::Then(
+      promise,
+      base::BindOnce(
+          [](v8::Local<v8::Promise>) -> base::Optional<v8::Local<v8::Promise>> {
+            return base::nullopt;
+          }));
+  auto promise_result =
+      ExpectState(still_rejected_promise, v8::Promise::PromiseState::kRejected);
+  EXPECT_EQ("fail", cache_utils::FromV8String(isolate, promise_result));
+}
+
+}  // namespace web
+}  // namespace cobalt
diff --git a/cobalt/web/context.h b/cobalt/web/context.h
index 66825db..3fdf42c 100644
--- a/cobalt/web/context.h
+++ b/cobalt/web/context.h
@@ -68,7 +68,9 @@
   virtual worker::ServiceWorkerJobs* service_worker_jobs() const = 0;
 
   virtual const std::string& name() const = 0;
-  virtual void setup_environment_settings(EnvironmentSettings* settings) = 0;
+  virtual void SetupEnvironmentSettings(EnvironmentSettings* settings) = 0;
+  virtual void SetupFinished() = 0;
+
   virtual EnvironmentSettings* environment_settings() const = 0;
 
   virtual scoped_refptr<worker::ServiceWorkerRegistration>
diff --git a/cobalt/web/csp_delegate.cc b/cobalt/web/csp_delegate.cc
index 2a54b9c..3fe54b5 100644
--- a/cobalt/web/csp_delegate.cc
+++ b/cobalt/web/csp_delegate.cc
@@ -28,9 +28,9 @@
 
 CspDelegateSecure::CspDelegateSecure(
     std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-    csp::CSPHeaderPolicy require_csp,
+    csp::CSPHeaderPolicy csp_header_policy,
     const base::Closure& policy_changed_callback) {
-  require_csp_ = require_csp;
+  csp_header_policy_ = csp_header_policy;
   was_header_received_ = false;
   policy_changed_callback_ = policy_changed_callback;
 
@@ -77,7 +77,7 @@
     if (type == kLocation) {
       should_allow = csp_->AllowNavigateToSource(url, redirect_status);
     }
-    if (require_csp_ == csp::kCSPRequired || should_allow) {
+    if (csp_header_policy_ == csp::kCSPRequired || should_allow) {
       return should_allow;
     } else {
       DLOG(WARNING) << "Page must include Content-Security-Policy header, it "
diff --git a/cobalt/web/csp_delegate.h b/cobalt/web/csp_delegate.h
index 4fa1cfb..95ce400 100644
--- a/cobalt/web/csp_delegate.h
+++ b/cobalt/web/csp_delegate.h
@@ -20,6 +20,7 @@
 
 #include "cobalt/base/source_location.h"
 #include "cobalt/csp/content_security_policy.h"
+#include "cobalt/web/csp_delegate_type.h"
 #include "cobalt/web/csp_violation_reporter.h"
 
 namespace cobalt {
@@ -31,6 +32,22 @@
 // Note that any thread may call CanLoad().
 class CspDelegate {
  public:
+  struct Options {
+    Options() = default;
+    Options(const network_bridge::PostSender& post_sender,
+            csp::CSPHeaderPolicy header_policy,
+            CspEnforcementType enforcement_type, int insecure_allowed_token = 0)
+        : post_sender(post_sender),
+          header_policy(header_policy),
+          enforcement_type(enforcement_type),
+          insecure_allowed_token(insecure_allowed_token) {}
+
+    network_bridge::PostSender post_sender;
+    csp::CSPHeaderPolicy header_policy = csp::kCSPRequired;
+    CspEnforcementType enforcement_type = kCspEnforcementEnable;
+    int insecure_allowed_token = 0;
+  };
+
   enum ResourceType {
     kFont,
     kImage,
@@ -117,7 +134,7 @@
 class CspDelegateSecure : public CspDelegate {
  public:
   CspDelegateSecure(std::unique_ptr<CspViolationReporter> violation_reporter,
-                    const GURL& url, csp::CSPHeaderPolicy require_csp,
+                    const GURL& url, csp::CSPHeaderPolicy csp_header_policy,
                     const base::Closure& policy_changed_callback);
   ~CspDelegateSecure();
 
@@ -172,7 +189,7 @@
   base::Closure policy_changed_callback_;
 
   // Whether Cobalt is forbidden to render without receiving CSP header.
-  csp::CSPHeaderPolicy require_csp_;
+  csp::CSPHeaderPolicy csp_header_policy_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CspDelegateSecure);
diff --git a/cobalt/web/csp_delegate_factory.cc b/cobalt/web/csp_delegate_factory.cc
index 89d546c..5eb8065 100644
--- a/cobalt/web/csp_delegate_factory.cc
+++ b/cobalt/web/csp_delegate_factory.cc
@@ -12,16 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "cobalt/web/csp_delegate_factory.h"
+
 #include <memory>
 #include <utility>
 
-#include "cobalt/web/csp_delegate_factory.h"
-
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/threading/thread_local.h"
-
 #include "cobalt/web/csp_delegate.h"
+#include "cobalt/web/csp_violation_reporter.h"
+#include "cobalt/web/window_or_worker_global_scope.h"
 
 namespace cobalt {
 namespace web {
@@ -48,7 +49,7 @@
 
 CspDelegate* CreateInsecureDelegate(
     std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-    csp::CSPHeaderPolicy require_csp,
+    csp::CSPHeaderPolicy header_policy,
     const base::Closure& policy_changed_callback, int insecure_allowed_token) {
   if (InsecureAllowed(insecure_allowed_token)) {
     return new CspDelegateInsecure();
@@ -60,10 +61,10 @@
 
 CspDelegate* CreateSecureDelegate(
     std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-    csp::CSPHeaderPolicy require_csp,
+    csp::CSPHeaderPolicy header_policy,
     const base::Closure& policy_changed_callback, int insecure_allowed_token) {
-  return new CspDelegateSecure(std::move(violation_reporter), url, require_csp,
-                               policy_changed_callback);
+  return new CspDelegateSecure(std::move(violation_reporter), url,
+                               header_policy, policy_changed_callback);
 }
 }  // namespace
 
@@ -84,14 +85,16 @@
 #endif  // !defined(COBALT_FORCE_CSP)
 }
 
-std::unique_ptr<CspDelegate> CspDelegateFactory::Create(
-    CspEnforcementType type,
-    std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-    csp::CSPHeaderPolicy require_csp,
-    const base::Closure& policy_changed_callback, int insecure_allowed_token) {
-  std::unique_ptr<CspDelegate> delegate(
-      method_[type](std::move(violation_reporter), url, require_csp,
-                    policy_changed_callback, insecure_allowed_token));
+std::unique_ptr<CspDelegate> CspDelegateFactory::CreateDelegate(
+    WindowOrWorkerGlobalScope* global, const CspDelegate::Options& options,
+    const base::Closure& policy_changed_callback) {
+  std::unique_ptr<CspViolationReporter> violation_reporter(
+      new CspViolationReporter(global, options.post_sender));
+  std::unique_ptr<CspDelegate> delegate(method_[options.enforcement_type](
+      std::move(violation_reporter),
+      (global ? global->environment_settings()->creation_url() : GURL()),
+      options.header_policy, policy_changed_callback,
+      options.insecure_allowed_token));
   return delegate;
 }
 
diff --git a/cobalt/web/csp_delegate_factory.h b/cobalt/web/csp_delegate_factory.h
index aa10ac9..f9717e5 100644
--- a/cobalt/web/csp_delegate_factory.h
+++ b/cobalt/web/csp_delegate_factory.h
@@ -18,10 +18,13 @@
 #include <memory>
 #include <string>
 
+#include "base/bind.h"
 #include "base/callback_forward.h"
 #include "base/gtest_prod_util.h"
 #include "base/memory/singleton.h"
 #include "cobalt/csp/content_security_policy.h"
+#include "cobalt/network_bridge/net_poster.h"
+#include "cobalt/web/csp_delegate.h"
 #include "cobalt/web/csp_delegate_type.h"
 #include "url/gurl.h"
 
@@ -41,22 +44,27 @@
 class CspDelegateFactory {
  public:
   static CspDelegateFactory* GetInstance();
-  std::unique_ptr<CspDelegate> Create(
-      CspEnforcementType type,
-      std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-      csp::CSPHeaderPolicy require_csp,
-      const base::Closure& policy_changed_callback,
-      int insecure_allowed_token = 0);
+  static std::unique_ptr<CspDelegate> Create(
+      WindowOrWorkerGlobalScope* global, const CspDelegate::Options& options,
+      const base::Closure& policy_changed_callback = base::Closure()) {
+    return GetInstance()->CreateDelegate(global, options,
+                                         policy_changed_callback);
+  }
+
 
   typedef CspDelegate* (*CspDelegateCreator)(
       std::unique_ptr<CspViolationReporter> violation_reporter, const GURL& url,
-      csp::CSPHeaderPolicy require_csp,
+      csp::CSPHeaderPolicy csp_header_policy,
       const base::Closure& policy_changed_callback, int insecure_allowed_token);
 
 #if !defined(COBALT_FORCE_CSP)
   // Allow tests to have the factory create a different delegate type.
   void OverrideCreator(CspEnforcementType type, CspDelegateCreator creator);
 #endif
+ protected:
+  std::unique_ptr<CspDelegate> CreateDelegate(
+      WindowOrWorkerGlobalScope* global, const CspDelegate::Options& options,
+      const base::Closure& policy_changed_callback);
 
  private:
 #if !defined(COBALT_FORCE_CSP)
diff --git a/cobalt/web/csp_delegate_test.cc b/cobalt/web/csp_delegate_test.cc
index 96e5ccc..f4e920f 100644
--- a/cobalt/web/csp_delegate_test.cc
+++ b/cobalt/web/csp_delegate_test.cc
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "cobalt/web/csp_delegate.h"
+
 #include <memory>
 #include <utility>
 
 #include "base/strings/stringprintf.h"
 #include "cobalt/base/polymorphic_downcast.h"
-#include "cobalt/web/csp_delegate.h"
 #include "cobalt/web/csp_delegate_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -81,7 +82,7 @@
 class MockViolationReporter : public CspViolationReporter {
  public:
   MockViolationReporter()
-      : CspViolationReporter(NULL, network_bridge::PostSender()) {}
+      : CspViolationReporter(nullptr, network_bridge::PostSender()) {}
   MOCK_METHOD1(Report, void(const csp::ViolationInfo&));
 };
 
@@ -105,7 +106,7 @@
 
   ~ScopedLogInterceptor() {
     logging::SetLogMessageHandler(old_handler_);
-    log_interceptor_ = NULL;
+    log_interceptor_ = nullptr;
   }
 
   static bool LogHandler(int severity, const char* file, int line,
@@ -166,11 +167,11 @@
                         ResourcePairName);
 
 TEST(CspDelegateFactoryTest, Secure) {
+  CspDelegate::Options options;
+  options.enforcement_type = kCspEnforcementEnable;
   std::unique_ptr<CspDelegate> delegate =
-      CspDelegateFactory::GetInstance()->Create(
-          kCspEnforcementEnable, std::unique_ptr<CspViolationReporter>(),
-          GURL(), csp::kCSPRequired, base::Closure());
-  EXPECT_TRUE(delegate != NULL);
+      CspDelegateFactory::Create(nullptr, options);
+  EXPECT_TRUE(delegate != nullptr);
 }
 
 TEST(CspDelegateFactoryTest, InsecureBlocked) {
@@ -179,10 +180,10 @@
     // Capture the output, because we should get a FATAL log and we don't
     // want to crash.
     ScopedLogInterceptor li(&output);
+    CspDelegate::Options options;
+    options.enforcement_type = kCspEnforcementDisable;
     std::unique_ptr<CspDelegate> delegate =
-        CspDelegateFactory::GetInstance()->Create(
-            kCspEnforcementDisable, std::unique_ptr<CspViolationReporter>(),
-            GURL(), csp::kCSPRequired, base::Closure());
+        CspDelegateFactory::Create(nullptr, options);
 
     std::unique_ptr<CspDelegate> empty_delegate;
     EXPECT_EQ(empty_delegate.get(), delegate.get());
@@ -193,12 +194,13 @@
 TEST(CspDelegateFactoryTest, InsecureAllowed) {
   // This only compiles because this test is a friend of CspDelegateFactory,
   // otherwise GetInsecureAllowedToken is private.
-  int token = CspDelegateFactory::GetInstance()->GetInsecureAllowedToken();
+  CspDelegate::Options options;
+  options.enforcement_type = kCspEnforcementDisable;
+  options.insecure_allowed_token =
+      CspDelegateFactory::GetInstance()->GetInsecureAllowedToken();
   std::unique_ptr<CspDelegate> delegate =
-      CspDelegateFactory::GetInstance()->Create(
-          kCspEnforcementDisable, std::unique_ptr<CspViolationReporter>(),
-          GURL(), csp::kCSPRequired, base::Closure(), token);
-  EXPECT_TRUE(delegate != NULL);
+      CspDelegateFactory::Create(nullptr, options);
+  EXPECT_TRUE(delegate != nullptr);
 }
 
 }  // namespace web
diff --git a/cobalt/web/environment_settings_helper.cc b/cobalt/web/environment_settings_helper.cc
index 4a87c2e..3c50954 100644
--- a/cobalt/web/environment_settings_helper.cc
+++ b/cobalt/web/environment_settings_helper.cc
@@ -32,6 +32,10 @@
   return get_context(environment_settings)->global_environment();
 }
 
+v8::Isolate* get_isolate(script::EnvironmentSettings* environment_settings) {
+  return get_global_environment(environment_settings)->isolate();
+}
+
 script::Wrappable* get_global_wrappable(
     script::EnvironmentSettings* environment_settings) {
   return get_global_environment(environment_settings)->global_wrappable();
@@ -42,5 +46,10 @@
   return get_global_environment(environment_settings)->script_value_factory();
 }
 
+base::MessageLoop* get_message_loop(
+    script::EnvironmentSettings* environment_settings) {
+  return get_context(environment_settings)->message_loop();
+}
+
 }  // namespace web
 }  // namespace cobalt
diff --git a/cobalt/web/environment_settings_helper.h b/cobalt/web/environment_settings_helper.h
index ca1b83e..5511937 100644
--- a/cobalt/web/environment_settings_helper.h
+++ b/cobalt/web/environment_settings_helper.h
@@ -19,17 +19,21 @@
 #include "cobalt/script/global_environment.h"
 #include "cobalt/script/script_value_factory.h"
 #include "cobalt/web/context.h"
+#include "v8/include/v8.h"
 
 namespace cobalt {
 namespace web {
 
 Context* get_context(script::EnvironmentSettings* environment_settings);
+v8::Isolate* get_isolate(script::EnvironmentSettings* environment_settings);
 script::GlobalEnvironment* get_global_environment(
     script::EnvironmentSettings* environment_settings);
 script::Wrappable* get_global_wrappable(
     script::EnvironmentSettings* environment_settings);
 script::ScriptValueFactory* get_script_value_factory(
     script::EnvironmentSettings* environment_settings);
+base::MessageLoop* get_message_loop(
+    script::EnvironmentSettings* environment_settings);
 
 }  // namespace web
 }  // namespace cobalt
diff --git a/cobalt/web/event_target.h b/cobalt/web/event_target.h
index 134fe79..1663f80 100644
--- a/cobalt/web/event_target.h
+++ b/cobalt/web/event_target.h
@@ -16,6 +16,7 @@
 #define COBALT_WEB_EVENT_TARGET_H_
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -536,6 +537,14 @@
     return environment_settings_;
   }
 
+  std::set<base::Token>& event_listener_event_types() const {
+    static std::set<base::Token> event_listener_event_types;
+    for (auto& event_listener_info : event_listener_infos_) {
+      event_listener_event_types.insert(event_listener_info->type());
+    }
+    return event_listener_event_types;
+  }
+
  protected:
   virtual ~EventTarget() { environment_settings_ = nullptr; }
 
diff --git a/cobalt/web/stat_tracker.cc b/cobalt/web/stat_tracker.cc
index edead88..6f2899e 100644
--- a/cobalt/web/stat_tracker.cc
+++ b/cobalt/web/stat_tracker.cc
@@ -18,18 +18,21 @@
 
 namespace cobalt {
 namespace web {
-StatTracker::StatTracker(const std::string& name)
+StatTracker::StatTracker(const std::string& name, const char* component)
     : count_window_timers_interval_(
-          base::StringPrintf("Count.%s.DOM.WindowTimers.Interval",
-                             name.c_str()),
+          base::StringPrintf("Count.%s.%s.WindowTimers.Interval", name.c_str(),
+                             component),
           0, "Number of active WindowTimer Intervals."),
       count_window_timers_timeout_(
-          base::StringPrintf("Count.%s.DOM.WindowTimers.Timeout", name.c_str()),
+          base::StringPrintf("Count.%s.%s.WindowTimers.Timeout", name.c_str(),
+                             component),
           0, "Number of active WindowTimer Timeouts."),
       count_window_timers_interval_created_(0),
       count_window_timers_interval_destroyed_(0),
       count_window_timers_timeout_created_(0),
-      count_window_timers_timeout_destroyed_(0) {}
+      count_window_timers_timeout_destroyed_(0) {
+  DCHECK(component);
+}
 
 StatTracker::~StatTracker() {
   FlushPeriodicTracking();
diff --git a/cobalt/web/stat_tracker.h b/cobalt/web/stat_tracker.h
index 3e9edc8..5d23345 100644
--- a/cobalt/web/stat_tracker.h
+++ b/cobalt/web/stat_tracker.h
@@ -25,7 +25,7 @@
 // Tracks stats for web resources.
 class StatTracker {
  public:
-  explicit StatTracker(const std::string& name);
+  StatTracker(const std::string& name, const char* component);
   ~StatTracker();
 
   void OnWindowTimersIntervalCreated() {
diff --git a/cobalt/web/testing/stub_web_context.h b/cobalt/web/testing/stub_web_context.h
index 311c255..87268f0 100644
--- a/cobalt/web/testing/stub_web_context.h
+++ b/cobalt/web/testing/stub_web_context.h
@@ -116,16 +116,18 @@
   }
 
   const std::string& name() const final { return name_; };
-  void setup_environment_settings(
+  void SetupEnvironmentSettings(
       EnvironmentSettings* environment_settings) final {
     environment_settings_.reset(environment_settings);
     if (environment_settings_) environment_settings_->set_context(this);
   }
+  void SetupFinished() final {}
+
   EnvironmentSettings* environment_settings() const final {
     return environment_settings_.get();
   }
   EnvironmentSettings* setup_stub_environment_settings() {
-    setup_environment_settings(new testing::StubEnvironmentSettings);
+    SetupEnvironmentSettings(new testing::StubEnvironmentSettings);
     return environment_settings();
   }
 
diff --git a/cobalt/web/window_or_worker_global_scope.cc b/cobalt/web/window_or_worker_global_scope.cc
index 769cd77..21b385d 100644
--- a/cobalt/web/window_or_worker_global_scope.cc
+++ b/cobalt/web/window_or_worker_global_scope.cc
@@ -16,6 +16,7 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "cobalt/script/environment_settings.h"
 #include "cobalt/web/csp_delegate_factory.h"
 #include "cobalt/web/event_target.h"
@@ -30,22 +31,24 @@
 }  // namespace worker
 namespace web {
 WindowOrWorkerGlobalScope::WindowOrWorkerGlobalScope(
-    script::EnvironmentSettings* settings, StatTracker* stat_tracker,
-    Options options)
+    script::EnvironmentSettings* settings, const Options& options)
     // Global scope object EventTargets require special handling for onerror
     // events, see EventTarget constructor for more details.
     : EventTarget(settings, kUnpackOnErrorEvents),
+      options_(options),
       caches_(new CacheStorage()),
       crypto_(new Crypto()),
-      window_timers_(this, stat_tracker, debugger_hooks(),
+      window_timers_(this, options.stat_tracker, debugger_hooks(),
                      options.initial_state),
       preflight_cache_(new loader::CORSPreflightCache()) {
-  std::unique_ptr<web::CspViolationReporter> violation_reporter(
-      new web::CspViolationReporter(this, options.post_sender));
-  csp_delegate_ = web::CspDelegateFactory::GetInstance()->Create(
-      options.csp_enforcement_mode, std::move(violation_reporter),
-      environment_settings()->creation_url(), options.require_csp,
-      options.csp_policy_changed_callback, options.csp_insecure_allowed_token);
+  csp_delegate_ = CspDelegateFactory::Create(
+      this, options.csp_options,
+      base::Bind(&WindowOrWorkerGlobalScope::OnCspPolicyChanged,
+                 base::Unretained(this)));
+}
+
+WindowOrWorkerGlobalScope::~WindowOrWorkerGlobalScope() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
 bool WindowOrWorkerGlobalScope::IsWindow() {
@@ -66,8 +69,24 @@
          base::GetTypeId<worker::ServiceWorkerGlobalScope>();
 }
 
+void WindowOrWorkerGlobalScope::OnCspPolicyChanged() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(csp_delegate());
+  DCHECK(environment_settings()->context()->global_environment());
+
+  std::string eval_disabled_message;
+  bool allow_eval = csp_delegate()->AllowEval(&eval_disabled_message);
+  if (allow_eval) {
+    environment_settings()->context()->global_environment()->EnableEval();
+  } else {
+    environment_settings()->context()->global_environment()->DisableEval(
+        eval_disabled_message);
+  }
+}
+
 int WindowOrWorkerGlobalScope::SetTimeout(
-    const web::WindowTimers::TimerCallbackArg& handler, int timeout) {
+    const WindowTimers::TimerCallbackArg& handler, int timeout) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return window_timers_.SetTimeout(handler, timeout);
 }
 
@@ -76,7 +95,8 @@
 }
 
 int WindowOrWorkerGlobalScope::SetInterval(
-    const web::WindowTimers::TimerCallbackArg& handler, int timeout) {
+    const WindowTimers::TimerCallbackArg& handler, int timeout) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   return window_timers_.SetInterval(handler, timeout);
 }
 
@@ -85,6 +105,7 @@
 }
 
 void WindowOrWorkerGlobalScope::DestroyTimers() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   window_timers_.DisableCallbacks();
 }
 
diff --git a/cobalt/web/window_or_worker_global_scope.h b/cobalt/web/window_or_worker_global_scope.h
index d2580ac..ee8afc1 100644
--- a/cobalt/web/window_or_worker_global_scope.h
+++ b/cobalt/web/window_or_worker_global_scope.h
@@ -21,15 +21,16 @@
 
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
 #include "cobalt/loader/cors_preflight_cache.h"
 #include "cobalt/script/environment_settings.h"
 #include "cobalt/web/cache_storage.h"
 #include "cobalt/web/crypto.h"
 #include "cobalt/web/csp_delegate.h"
-#include "cobalt/web/csp_delegate_type.h"
 #include "cobalt/web/event_target.h"
 #include "cobalt/web/event_target_listener_info.h"
 #include "cobalt/web/navigator_base.h"
+#include "cobalt/web/stat_tracker.h"
 #include "cobalt/web/window_timers.h"
 
 namespace cobalt {
@@ -48,34 +49,21 @@
 class WindowOrWorkerGlobalScope : public EventTarget {
  public:
   struct Options {
-    explicit Options(base::ApplicationState initial_state)
-        : initial_state(initial_state),
-          csp_enforcement_mode(web::kCspEnforcementEnable) {}
-
+    Options() = default;
     Options(base::ApplicationState initial_state,
-            const network_bridge::PostSender& post_sender,
-            csp::CSPHeaderPolicy require_csp,
-            web::CspEnforcementType csp_enforcement_mode,
-            base::Closure csp_policy_changed_callback,
-            int csp_insecure_allowed_token = 0)
+            const web::CspDelegate::Options& csp_options,
+            StatTracker* stat_tracker = nullptr)
         : initial_state(initial_state),
-          post_sender(post_sender),
-          require_csp(require_csp),
-          csp_enforcement_mode(csp_enforcement_mode),
-          csp_policy_changed_callback(csp_policy_changed_callback),
-          csp_insecure_allowed_token(csp_insecure_allowed_token) {}
+          csp_options(csp_options),
+          stat_tracker(stat_tracker) {}
 
-    base::ApplicationState initial_state;
-    network_bridge::PostSender post_sender;
-    csp::CSPHeaderPolicy require_csp;
-    web::CspEnforcementType csp_enforcement_mode;
-    base::Closure csp_policy_changed_callback;
-    int csp_insecure_allowed_token;
+    base::ApplicationState initial_state = base::kApplicationStateStarted;
+    web::CspDelegate::Options csp_options;
+    StatTracker* stat_tracker = nullptr;
   };
 
   explicit WindowOrWorkerGlobalScope(script::EnvironmentSettings* settings,
-                                     StatTracker* stat_tracker,
-                                     Options options);
+                                     const Options& options);
   WindowOrWorkerGlobalScope(const WindowOrWorkerGlobalScope&) = delete;
   WindowOrWorkerGlobalScope& operator=(const WindowOrWorkerGlobalScope&) =
       delete;
@@ -101,7 +89,7 @@
 
   // The CspDelegate gives access to the CSP list of the policy container
   //   https://html.spec.whatwg.org/commit-snapshots/ae3c91103aada3d6d346a6dd3c5356773195fc79/#policy-container
-  web::CspDelegate* csp_delegate() const {
+  CspDelegate* csp_delegate() const {
     DCHECK(csp_delegate_);
     return csp_delegate_.get();
   }
@@ -110,26 +98,25 @@
     return preflight_cache_;
   }
 
-  DEFINE_WRAPPABLE_TYPE(WindowOrWorkerGlobalScope);
+  // Callback from the CspDelegate.
+  void OnCspPolicyChanged();
 
   // Web API: WindowTimers (implements)
   //   https://www.w3.org/TR/html50/webappapis.html#timers
   //
-  int SetTimeout(const web::WindowTimers::TimerCallbackArg& handler) {
+  int SetTimeout(const WindowTimers::TimerCallbackArg& handler) {
     return SetTimeout(handler, 0);
   }
 
-  int SetTimeout(const web::WindowTimers::TimerCallbackArg& handler,
-                 int timeout);
+  int SetTimeout(const WindowTimers::TimerCallbackArg& handler, int timeout);
 
   void ClearTimeout(int handle);
 
-  int SetInterval(const web::WindowTimers::TimerCallbackArg& handler) {
+  int SetInterval(const WindowTimers::TimerCallbackArg& handler) {
     return SetInterval(handler, 0);
   }
 
-  int SetInterval(const web::WindowTimers::TimerCallbackArg& handler,
-                  int timeout);
+  int SetInterval(const WindowTimers::TimerCallbackArg& handler, int timeout);
 
   void ClearInterval(int handle);
 
@@ -143,18 +130,27 @@
   //   https://www.w3.org/TR/WebCryptoAPI/#crypto-interface
   scoped_refptr<Crypto> crypto() const;
 
- protected:
-  virtual ~WindowOrWorkerGlobalScope() {}
+  const Options& options() { return options_; }
 
+  DEFINE_WRAPPABLE_TYPE(WindowOrWorkerGlobalScope);
+
+ protected:
+  virtual ~WindowOrWorkerGlobalScope();
+
+  Options options_;
   scoped_refptr<CacheStorage> caches_;
   scoped_refptr<Crypto> crypto_;
-  web::WindowTimers window_timers_;
+  WindowTimers window_timers_;
 
  private:
-  std::unique_ptr<web::CspDelegate> csp_delegate_;
+  std::unique_ptr<CspDelegate> csp_delegate_;
   NavigatorBase* navigator_base_ = nullptr;
   // Global preflight cache.
   scoped_refptr<loader::CORSPreflightCache> preflight_cache_;
+
+  // Thread checker ensures all calls to the WebModule are made from the same
+  // thread that it is created in.
+  THREAD_CHECKER(thread_checker_);
 };
 
 }  // namespace web
diff --git a/cobalt/web/window_timers_test.cc b/cobalt/web/window_timers_test.cc
index f389997..51e75a3 100644
--- a/cobalt/web/window_timers_test.cc
+++ b/cobalt/web/window_timers_test.cc
@@ -27,7 +27,6 @@
 #include "cobalt/script/testing/fake_script_value.h"
 #include "cobalt/web/stat_tracker.h"
 #include "net/test/test_with_scoped_task_environment.h"
-
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -90,7 +89,7 @@
   WindowTimersTest()
       : WithScopedTaskEnvironment(
             base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
-        stat_tracker_("WindowTimersTest"),
+        stat_tracker_("WindowTimersTest", "Test"),
         callback_(&mock_timer_callback_) {
     script::Wrappable* foo = nullptr;
     timers_.reset(
@@ -244,11 +243,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 
   EXPECT_EQ(GetPendingMainThreadTaskCount(), 2);
@@ -262,11 +261,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 }
 
@@ -398,11 +397,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 
   EXPECT_EQ(GetPendingMainThreadTaskCount(), 2);
@@ -417,11 +416,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 }
 
@@ -440,11 +439,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 
   EXPECT_EQ(GetPendingMainThreadTaskCount(), 4);
@@ -459,11 +458,11 @@
   stat_tracker_.FlushPeriodicTracking();
   EXPECT_EQ("2", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Interval")
+                         "Count.WindowTimersTest.Test.WindowTimers.Interval")
                      .value_or("Foo"));
   EXPECT_EQ("0", base::CValManager::GetInstance()
                      ->GetValueAsString(
-                         "Count.WindowTimersTest.DOM.WindowTimers.Timeout")
+                         "Count.WindowTimersTest.Test.WindowTimers.Timeout")
                      .value_or("Foo"));
 }
 
diff --git a/cobalt/websocket/web_socket_impl_test.cc b/cobalt/websocket/web_socket_impl_test.cc
index 66da04c..d7ddb7b 100644
--- a/cobalt/websocket/web_socket_impl_test.cc
+++ b/cobalt/websocket/web_socket_impl_test.cc
@@ -63,10 +63,11 @@
 
  protected:
   WebSocketImplTest() : web_context_(new web::testing::StubWebContext()) {
-    web_context_->setup_environment_settings(
+    web_context_->SetupEnvironmentSettings(
         new dom::testing::StubEnvironmentSettings());
     web_context_->environment_settings()->set_creation_url(
         GURL("https://127.0.0.1:1234"));
+    web_context_->SetupFinished();
     std::vector<std::string> sub_protocols;
     sub_protocols.push_back("chat");
     network_task_runner_ = web_context_->network_module()
diff --git a/cobalt/worker/BUILD.gn b/cobalt/worker/BUILD.gn
index f56409c..24d8147 100644
--- a/cobalt/worker/BUILD.gn
+++ b/cobalt/worker/BUILD.gn
@@ -36,6 +36,8 @@
     "navigation_preload_manager.h",
     "service_worker.cc",
     "service_worker.h",
+    "service_worker_consts.cc",
+    "service_worker_consts.h",
     "service_worker_container.cc",
     "service_worker_container.h",
     "service_worker_global_scope.cc",
@@ -69,6 +71,7 @@
     "//cobalt/browser:generated_bindings",
     "//cobalt/loader",
     "//cobalt/web",
+    "//net",
     "//url",
   ]
 
diff --git a/cobalt/worker/clients.cc b/cobalt/worker/clients.cc
index 0a81e08..c7c7f1a 100644
--- a/cobalt/worker/clients.cc
+++ b/cobalt/worker/clients.cc
@@ -67,7 +67,8 @@
           ->script_value_factory()
           ->CreateInterfacePromise<scoped_refptr<Client>>();
   std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
-      new script::ValuePromiseWrappable::Reference(this, promise));
+      new script::ValuePromiseWrappable::Reference(
+          settings_->context()->GetWindowOrWorkerGlobalScope(), promise));
 
   // 2. Run these substeps in parallel:
   ServiceWorkerJobs* jobs = settings_->context()->service_worker_jobs();
@@ -96,8 +97,8 @@
                      ->script_value_factory()
                      ->CreateBasicPromise<script::SequenceWrappable>();
   std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
-      promise_reference(
-          new script::ValuePromiseSequenceWrappable::Reference(this, promise));
+      promise_reference(new script::ValuePromiseSequenceWrappable::Reference(
+          settings_->context()->GetWindowOrWorkerGlobalScope(), promise));
   // 2. Run the following steps in parallel:
   ServiceWorkerJobs* jobs = settings_->context()->service_worker_jobs();
   DCHECK(jobs);
@@ -125,7 +126,8 @@
                      ->script_value_factory()
                      ->CreateBasicPromise<void>();
   std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference(
-      new script::ValuePromiseVoid::Reference(this, promise));
+      new script::ValuePromiseVoid::Reference(
+          settings_->context()->GetWindowOrWorkerGlobalScope(), promise));
 
   // 1. If the service worker is not an active worker, return a promise rejected
   // with an "InvalidStateError" DOMException.
diff --git a/cobalt/worker/dedicated_worker.cc b/cobalt/worker/dedicated_worker.cc
index 39251a7..43f2b0d 100644
--- a/cobalt/worker/dedicated_worker.cc
+++ b/cobalt/worker/dedicated_worker.cc
@@ -77,6 +77,15 @@
       environment_settings()->context()->web_settings();
   options.web_options.network_module =
       environment_settings()->context()->network_module();
+
+  // Propagate the CSP Options from the current environment settings.
+  options.global_scope_options.csp_options =
+      environment_settings()
+          ->context()
+          ->GetWindowOrWorkerGlobalScope()
+          ->options()
+          .csp_options;
+
   // 6. Let worker be a new Worker object.
   // 7. Let outside port be a new MessagePort in outside settings's Realm.
   // 8. Associate the outside port with worker.
diff --git a/cobalt/worker/dedicated_worker_global_scope.cc b/cobalt/worker/dedicated_worker_global_scope.cc
index 7043148..948803d 100644
--- a/cobalt/worker/dedicated_worker_global_scope.cc
+++ b/cobalt/worker/dedicated_worker_global_scope.cc
@@ -26,8 +26,10 @@
 namespace worker {
 DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(
     script::EnvironmentSettings* settings,
+    const web::WindowOrWorkerGlobalScope::Options& options,
     bool parent_cross_origin_isolated_capability)
-    : WorkerGlobalScope(settings), cross_origin_isolated_capability_(false) {
+    : WorkerGlobalScope(settings, options),
+      cross_origin_isolated_capability_(false) {
   // Algorithm for 'run a worker'
   //   https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#run-a-worker
   // 14.9. If is shared is false and owner's cross-origin isolated
diff --git a/cobalt/worker/dedicated_worker_global_scope.h b/cobalt/worker/dedicated_worker_global_scope.h
index 4252b4f..a0c2ee4 100644
--- a/cobalt/worker/dedicated_worker_global_scope.h
+++ b/cobalt/worker/dedicated_worker_global_scope.h
@@ -36,6 +36,7 @@
  public:
   explicit DedicatedWorkerGlobalScope(
       script::EnvironmentSettings* settings,
+      const web::WindowOrWorkerGlobalScope::Options& options,
       bool parent_cross_origin_isolated_capability = false);
   DedicatedWorkerGlobalScope(const DedicatedWorkerGlobalScope&) = delete;
   DedicatedWorkerGlobalScope& operator=(const DedicatedWorkerGlobalScope&) =
diff --git a/cobalt/worker/extendable_event.cc b/cobalt/worker/extendable_event.cc
index 5aaa923..87d48cb 100644
--- a/cobalt/worker/extendable_event.cc
+++ b/cobalt/worker/extendable_event.cc
@@ -17,6 +17,14 @@
 namespace cobalt {
 namespace worker {
 
+void ExtendableEvent::OnEnvironmentSettingsChanged(bool context_valid) {
+  if (!context_valid) {
+    while (traced_global_promises_.size() > 0) {
+      LessenLifetime(traced_global_promises_.begin()->first);
+    }
+  }
+}
+
 void ExtendableEvent::WaitUntil(
     script::EnvironmentSettings* settings,
     std::unique_ptr<script::Promise<script::ValueHandle*>>& promise,
@@ -33,6 +41,7 @@
     return;
   }
   // 3. Add promise to event’s extend lifetime promises.
+  ExtendLifetime(promise.get());
   // 4. Increment event’s pending promises count by one.
   ++pending_promise_count_;
   // 5. Upon fulfillment or rejection of promise, queue a microtask to run
@@ -76,8 +85,46 @@
                                  ->service_worker_object()
                                  ->containing_service_worker_registration())));
   }
+  LessenLifetime(promise);
   delete promise;
 }
 
+void ExtendableEvent::ExtendLifetime(
+    const script::Promise<script::ValueHandle*>* promise) {
+  auto heap_tracer =
+      script::v8c::V8cEngine::GetFromIsolate(isolate_)->heap_tracer();
+  if (traced_global_promises_.size() == 0) {
+    heap_tracer->AddRoot(this);
+  }
+  auto* traced_global =
+      new v8::TracedGlobal<v8::Value>(isolate_, promise->promise());
+  traced_global_promises_[promise] = traced_global;
+  heap_tracer->AddRoot(traced_global);
+}
+
+void ExtendableEvent::LessenLifetime(
+    const script::Promise<script::ValueHandle*>* promise) {
+  auto heap_tracer =
+      script::v8c::V8cEngine::GetFromIsolate(isolate_)->heap_tracer();
+  if (traced_global_promises_.count(promise) == 1) {
+    auto* traced_global = traced_global_promises_[promise];
+    heap_tracer->RemoveRoot(traced_global);
+    traced_global_promises_.erase(promise);
+    delete traced_global;
+  }
+  if (traced_global_promises_.size() == 0) {
+    heap_tracer->RemoveRoot(this);
+  }
+}
+
+void ExtendableEvent::InitializeEnvironmentSettingsChangeObserver(
+    script::EnvironmentSettings* settings) {
+  web::Context* context = web::get_context(settings);
+  context->AddEnvironmentSettingsChangeObserver(this);
+  remove_environment_settings_change_observer_ =
+      base::BindOnce(&web::Context::RemoveEnvironmentSettingsChangeObserver,
+                     base::Unretained(context), base::Unretained(this));
+}
+
 }  // namespace worker
 }  // namespace cobalt
diff --git a/cobalt/worker/extendable_event.h b/cobalt/worker/extendable_event.h
index f915189..fbd8136 100644
--- a/cobalt/worker/extendable_event.h
+++ b/cobalt/worker/extendable_event.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_WORKER_EXTENDABLE_EVENT_H_
 #define COBALT_WORKER_EXTENDABLE_EVENT_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -30,6 +31,7 @@
 #include "cobalt/web/context.h"
 #include "cobalt/web/dom_exception.h"
 #include "cobalt/web/environment_settings.h"
+#include "cobalt/web/environment_settings_helper.h"
 #include "cobalt/web/event.h"
 #include "cobalt/web/window_or_worker_global_scope.h"
 #include "cobalt/worker/extendable_event_init.h"
@@ -37,21 +39,38 @@
 #include "cobalt/worker/service_worker_jobs.h"
 #include "cobalt/worker/service_worker_object.h"
 #include "cobalt/worker/service_worker_registration_object.h"
+#include "v8/include/v8.h"
 
 namespace cobalt {
 namespace worker {
 
-class ExtendableEvent : public web::Event {
+class ExtendableEvent : public web::Event,
+                        public web::Context::EnvironmentSettingsChangeObserver {
  public:
-  explicit ExtendableEvent(const std::string& type) : Event(type) {}
-  ExtendableEvent(const std::string& type, const ExtendableEventInit& init_dict)
-      : ExtendableEvent(base::Token(type), init_dict) {}
-  ExtendableEvent(base::Token type,
+  explicit ExtendableEvent(script::EnvironmentSettings* settings,
+                           const std::string& type)
+      : Event(type), isolate_(web::get_isolate(settings)) {
+    InitializeEnvironmentSettingsChangeObserver(settings);
+  }
+  ExtendableEvent(script::EnvironmentSettings* settings,
+                  const std::string& type, const ExtendableEventInit& init_dict)
+      : ExtendableEvent(settings, base::Token(type), init_dict) {}
+  ExtendableEvent(script::EnvironmentSettings* settings, base::Token type,
                   base::OnceCallback<void(bool)> done_callback =
                       base::OnceCallback<void(bool)>())
-      : Event(type), done_callback_(std::move(done_callback)) {}
-  ExtendableEvent(base::Token type, const ExtendableEventInit& init_dict)
-      : Event(type, init_dict) {}
+      : Event(type),
+        done_callback_(std::move(done_callback)),
+        isolate_(web::get_isolate(settings)) {
+    InitializeEnvironmentSettingsChangeObserver(settings);
+  }
+  ExtendableEvent(script::EnvironmentSettings* settings, base::Token type,
+                  const ExtendableEventInit& init_dict)
+      : Event(type, init_dict), isolate_(web::get_isolate(settings)) {
+    InitializeEnvironmentSettingsChangeObserver(settings);
+  }
+
+  // web::Context::EnvironmentSettingsChangeObserver
+  void OnEnvironmentSettingsChanged(bool context_valid) override;
 
   void WaitUntil(
       script::EnvironmentSettings* settings,
@@ -75,9 +94,16 @@
   DEFINE_WRAPPABLE_TYPE(ExtendableEvent);
 
  protected:
-  ~ExtendableEvent() override {}
+  ~ExtendableEvent() override {
+    std::move(remove_environment_settings_change_observer_).Run();
+  }
 
  private:
+  void ExtendLifetime(const script::Promise<script::ValueHandle*>* promise);
+  void LessenLifetime(const script::Promise<script::ValueHandle*>* promise);
+  void InitializeEnvironmentSettingsChangeObserver(
+      script::EnvironmentSettings* settings);
+
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#extendableevent-extend-lifetime-promises
   // std::list<script::Promise<script::ValueHandle*>> extend_lifetime_promises_;
   int pending_promise_count_ = 0;
@@ -86,6 +112,12 @@
   bool timed_out_flag_ = false;
 
   base::OnceCallback<void(bool)> done_callback_;
+  base::OnceClosure remove_environment_settings_change_observer_;
+  v8::Isolate* isolate_;
+
+  std::map<const script::Promise<script::ValueHandle*>*,
+           v8::TracedGlobal<v8::Value>*>
+      traced_global_promises_;
 };
 
 }  // namespace worker
diff --git a/cobalt/worker/extendable_event.idl b/cobalt/worker/extendable_event.idl
index 8a12344..a0db8d1 100644
--- a/cobalt/worker/extendable_event.idl
+++ b/cobalt/worker/extendable_event.idl
@@ -16,6 +16,7 @@
 
 [
   Exposed = ServiceWorker,
+  ConstructorCallWith=EnvironmentSettings,
   Constructor(DOMString type, optional ExtendableEventInit eventInitDict)
 ] interface ExtendableEvent : Event {
   [RaisesException, CallWith = EnvironmentSettings] void waitUntil(Promise<any> f);
diff --git a/cobalt/worker/extendable_message_event.cc b/cobalt/worker/extendable_message_event.cc
index aca29cb..30a253c 100644
--- a/cobalt/worker/extendable_message_event.cc
+++ b/cobalt/worker/extendable_message_event.cc
@@ -28,8 +28,9 @@
 namespace worker {
 
 ExtendableMessageEvent::ExtendableMessageEvent(
-    base::Token type, const ExtendableMessageEventInit& init_dict)
-    : ExtendableEvent(type, init_dict) {
+    script::EnvironmentSettings* settings, base::Token type,
+    const ExtendableMessageEventInit& init_dict)
+    : ExtendableEvent(settings, type, init_dict) {
   if (init_dict.has_data() && init_dict.data()) {
     DCHECK(init_dict.data());
     data_ = script::SerializeScriptValue(*(init_dict.data()));
diff --git a/cobalt/worker/extendable_message_event.h b/cobalt/worker/extendable_message_event.h
index 965f79e..c9b2fea 100644
--- a/cobalt/worker/extendable_message_event.h
+++ b/cobalt/worker/extendable_message_event.h
@@ -22,6 +22,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "cobalt/base/token.h"
+#include "cobalt/script/environment_settings.h"
 #include "cobalt/script/union_type.h"
 #include "cobalt/script/value_handle.h"
 #include "cobalt/script/wrappable.h"
@@ -42,18 +43,24 @@
                                  scoped_refptr<ServiceWorker>,
                                  scoped_refptr<web::MessagePort>>;
 
-  explicit ExtendableMessageEvent(const std::string& type)
-      : ExtendableEvent(type) {}
-  explicit ExtendableMessageEvent(base::Token type) : ExtendableEvent(type) {}
-  ExtendableMessageEvent(const std::string& type,
+  explicit ExtendableMessageEvent(script::EnvironmentSettings* settings,
+                                  const std::string& type)
+      : ExtendableEvent(settings, type) {}
+  explicit ExtendableMessageEvent(script::EnvironmentSettings* settings,
+                                  base::Token type)
+      : ExtendableEvent(settings, type) {}
+  ExtendableMessageEvent(script::EnvironmentSettings* settings,
+                         const std::string& type,
                          const ExtendableMessageEventInit& init_dict)
-      : ExtendableMessageEvent(base::Token(type), init_dict) {}
-  ExtendableMessageEvent(base::Token type,
+      : ExtendableMessageEvent(settings, base::Token(type), init_dict) {}
+  ExtendableMessageEvent(script::EnvironmentSettings* settings,
+                         base::Token type,
                          const ExtendableMessageEventInit& init_dict);
-  ExtendableMessageEvent(base::Token type,
+  ExtendableMessageEvent(script::EnvironmentSettings* settings,
+                         base::Token type,
                          const ExtendableMessageEventInit& init_dict,
                          std::unique_ptr<script::DataBuffer> data)
-      : ExtendableMessageEvent(type, init_dict) {
+      : ExtendableMessageEvent(settings, type, init_dict) {
     data_ = std::move(data);
   }
 
diff --git a/cobalt/worker/extendable_message_event.idl b/cobalt/worker/extendable_message_event.idl
index 30a2001..f117668 100644
--- a/cobalt/worker/extendable_message_event.idl
+++ b/cobalt/worker/extendable_message_event.idl
@@ -16,6 +16,7 @@
 
 [
   Exposed = ServiceWorker,
+  ConstructorCallWith=EnvironmentSettings,
   Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict)
 ] interface ExtendableMessageEvent : ExtendableEvent {
   [CallWith = EnvironmentSettings] readonly attribute any data;
diff --git a/cobalt/worker/extendable_message_event_test.cc b/cobalt/worker/extendable_message_event_test.cc
index 2e8e64f..40591dd 100644
--- a/cobalt/worker/extendable_message_event_test.cc
+++ b/cobalt/worker/extendable_message_event_test.cc
@@ -54,7 +54,7 @@
 TEST_F(ExtendableMessageEventTestWithJavaScript,
        ConstructorWithEventTypeString) {
   scoped_refptr<ExtendableMessageEvent> event =
-      new ExtendableMessageEvent("mytestevent");
+      new ExtendableMessageEvent(environment_settings(), "mytestevent");
 
   EXPECT_EQ("mytestevent", event->type());
   EXPECT_EQ(NULL, event->target().get());
@@ -81,7 +81,7 @@
   EXPECT_GT(data->size, 0U);
   const ExtendableMessageEventInit init;
   scoped_refptr<ExtendableMessageEvent> event = new ExtendableMessageEvent(
-      base::Tokens::message(), init, std::move(data));
+      environment_settings(), base::Tokens::message(), init, std::move(data));
 
   EXPECT_EQ("message", event->type());
   EXPECT_EQ(NULL, event->target().get());
@@ -109,7 +109,7 @@
        ConstructorWithEventTypeAndDefaultInitDict) {
   ExtendableMessageEventInit init;
   scoped_refptr<ExtendableMessageEvent> event =
-      new ExtendableMessageEvent("mytestevent", init);
+      new ExtendableMessageEvent(environment_settings(), "mytestevent", init);
 
   EXPECT_EQ("mytestevent", event->type());
   EXPECT_EQ(nullptr, event->target().get());
@@ -145,7 +145,7 @@
       Client::Create(web_context()->environment_settings()));
   init.set_source(client);
   scoped_refptr<ExtendableMessageEvent> event =
-      new ExtendableMessageEvent("mytestevent", init);
+      new ExtendableMessageEvent(environment_settings(), "mytestevent", init);
 
   EXPECT_EQ("mytestevent", event->type());
   EXPECT_EQ(nullptr, event->target().get());
diff --git a/cobalt/worker/fetch_event.cc b/cobalt/worker/fetch_event.cc
index 4480643..99497fb 100644
--- a/cobalt/worker/fetch_event.cc
+++ b/cobalt/worker/fetch_event.cc
@@ -28,26 +28,29 @@
 FetchEvent::FetchEvent(script::EnvironmentSettings* environment_settings,
                        const std::string& type,
                        const FetchEventInit& event_init_dict)
-    : FetchEvent(
-          environment_settings, base::Token(type), event_init_dict,
-          /*respond_with_callback=*/std::make_unique<RespondWithCallback>(),
-          /*report_load_timing_info=*/
-          std::make_unique<ReportLoadTimingInfo>()) {}
+    : FetchEvent(environment_settings, base::Token(type), event_init_dict,
+                 base::MessageLoop::current()->task_runner(),
+                 RespondWithCallback(), ReportLoadTimingInfo()) {}
 
 FetchEvent::FetchEvent(
     script::EnvironmentSettings* environment_settings, base::Token type,
     const FetchEventInit& event_init_dict,
-    std::unique_ptr<RespondWithCallback> respond_with_callback,
-    std::unique_ptr<ReportLoadTimingInfo> report_load_timing_info)
-    : ExtendableEvent(type, event_init_dict),
+    scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+    RespondWithCallback respond_with_callback,
+    ReportLoadTimingInfo report_load_timing_info)
+    : ExtendableEvent(environment_settings, type, event_init_dict),
+      environment_settings_(environment_settings),
+      callback_task_runner_(callback_task_runner),
       respond_with_callback_(std::move(respond_with_callback)),
       report_load_timing_info_(std::move(report_load_timing_info)) {
   auto script_value_factory =
-      web::get_script_value_factory(environment_settings);
+      web::get_script_value_factory(environment_settings_);
   handled_property_ = std::make_unique<script::ValuePromiseVoid::Reference>(
       this, script_value_factory->CreateBasicPromise<void>());
   request_ = std::make_unique<script::ValueHandleHolder::Reference>(
       this, event_init_dict.request());
+  respond_with_done_ = std::make_unique<script::ValuePromiseVoid::Reference>(
+      this, script_value_factory->CreateBasicPromise<void>());
 
   load_timing_info_.request_start = base::TimeTicks::Now();
   load_timing_info_.request_start_time = base::Time::Now();
@@ -56,112 +59,84 @@
   load_timing_info_.service_worker_start_time = base::TimeTicks::Now();
 }
 
-void FetchEvent::RespondWith(
-    script::EnvironmentSettings* environment_settings,
-    std::unique_ptr<script::Promise<script::ValueHandle*>>& response) {
-  respond_with_called_ = true;
-
-  // TODO: call |WaitUntil()|.
-  v8::Local<v8::Promise> v8_response = response->promise();
-  auto* global_environment = web::get_global_environment(environment_settings);
-  auto* isolate = global_environment->isolate();
-  auto context = isolate->GetCurrentContext();
-  auto data = v8::Object::New(isolate);
-  web::cache_utils::SetExternal(context, data, "environment_settings",
-                                environment_settings);
-  web::cache_utils::SetOwnedExternal(context, data, "respond_with_callback",
-                                     std::move(respond_with_callback_));
-  web::cache_utils::SetOwnedExternal(context, data, "report_load_timing_info",
-                                     std::move(report_load_timing_info_));
-  web::cache_utils::SetExternal(context, data, "load_timing_info",
-                                &load_timing_info_);
-  web::cache_utils::SetExternal(context, data, "handled",
-                                handled_property_.get());
-  auto result = v8_response->Then(
-      context,
-      v8::Function::New(
-          context,
-          [](const v8::FunctionCallbackInfo<v8::Value>& info) {
-            auto* isolate = info.GetIsolate();
-            auto context = info.GetIsolate()->GetCurrentContext();
-            v8::Local<v8::Value> text_result;
-            if (!web::cache_utils::TryCall(context, /*object=*/info[0], "text")
-                     .ToLocal(&text_result)) {
-              auto respond_with_callback =
-                  web::cache_utils::GetOwnedExternal<RespondWithCallback>(
-                      context, info.Data(), "respond_with_callback");
-              std::move(*respond_with_callback)
-                  .Run(std::make_unique<std::string>());
-              return;
-            }
-            auto* load_timing_info =
-                web::cache_utils::GetExternal<net::LoadTimingInfo>(
-                    context, info.Data(), "load_timing_info");
-            load_timing_info->receive_headers_end = base::TimeTicks::Now();
-            auto result = text_result.As<v8::Promise>()->Then(
-                context,
-                v8::Function::New(
-                    context,
-                    [](const v8::FunctionCallbackInfo<v8::Value>& info) {
-                      auto* isolate = info.GetIsolate();
-                      auto context = info.GetIsolate()->GetCurrentContext();
-                      auto* handled = web::cache_utils::GetExternal<
-                          script::ValuePromiseVoid::Reference>(
-                          context, info.Data(), "handled");
-                      handled->value().Resolve();
-                      auto respond_with_callback =
-                          web::cache_utils::GetOwnedExternal<
-                              RespondWithCallback>(context, info.Data(),
-                                                   "respond_with_callback");
-                      auto body = std::make_unique<std::string>();
-                      FromJSValue(isolate, info[0],
-                                  script::v8c::kNoConversionFlags, nullptr,
-                                  body.get());
-                      auto* load_timing_info =
-                          web::cache_utils::GetExternal<net::LoadTimingInfo>(
-                              context, info.Data(), "load_timing_info");
-                      auto report_load_timing_info =
-                          web::cache_utils::GetOwnedExternal<
-                              ReportLoadTimingInfo>(context, info.Data(),
-                                                    "report_load_timing_info");
-                      std::move(*report_load_timing_info)
-                          .Run(*load_timing_info);
-                      auto* environment_settings =
-                          web::cache_utils::GetExternal<
-                              script::EnvironmentSettings>(
-                              context, info.Data(), "environment_settings");
-                      web::get_context(environment_settings)
-                          ->network_module()
-                          ->task_runner()
-                          ->PostTask(
-                              FROM_HERE,
-                              base::BindOnce(
-                                  [](std::unique_ptr<base::OnceCallback<void(
-                                         std::unique_ptr<std::string>)>>
-                                         respond_with_callback,
-                                     std::unique_ptr<std::string> body) {
-                                    std::move(*respond_with_callback)
-                                        .Run(std::move(body));
-                                  },
-                                  std::move(respond_with_callback),
-                                  std::move(body)));
-                    },
-                    info.Data())
-                    .ToLocalChecked());
-            if (result.IsEmpty()) {
-              LOG(WARNING) << "Failure during FetchEvent respondWith handling. "
-                              "Retrieving Response text failed.";
-            }
-          },
-          data)
-          .ToLocalChecked());
-  if (result.IsEmpty()) {
-    LOG(WARNING) << "Failure during FetchEvent respondWith handling.";
-  }
+base::Optional<v8::Local<v8::Promise>> FetchEvent::GetText(
+    v8::Local<v8::Promise> response_promise) {
+  callback_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(
+                     [](ReportLoadTimingInfo report_load_timing_info,
+                        const net::LoadTimingInfo& load_timing_info) {
+                       std::move(report_load_timing_info).Run(load_timing_info);
+                     },
+                     std::move(report_load_timing_info_), load_timing_info_));
+  handled_property_->value().Resolve();
+  return web::cache_utils::OptionalPromise(
+      web::cache_utils::Call(response_promise->Result(), "text"));
 }
 
-script::HandlePromiseVoid FetchEvent::handled(
-    script::EnvironmentSettings* environment_settings) {
+void FetchEvent::RespondWithDone() { respond_with_done_->value().Resolve(); }
+
+base::Optional<v8::Local<v8::Promise>> FetchEvent::DoRespondWith(
+    v8::Local<v8::Promise> text_promise) {
+  auto* isolate = text_promise->GetIsolate();
+  auto context = isolate->GetCurrentContext();
+  auto body = web::cache_utils::FromV8String(text_promise->GetIsolate(),
+                                             text_promise->Result());
+  auto callback =
+      base::BindOnce(&FetchEvent::RespondWithDone, base::Unretained(this));
+  web::get_context(environment_settings_)
+      ->network_module()
+      ->task_runner()
+      ->PostTask(
+          FROM_HERE,
+          base::BindOnce(
+              [](scoped_refptr<base::SingleThreadTaskRunner>
+                     callback_task_runner,
+                 RespondWithCallback respond_with_callback, std::string body,
+                 base::MessageLoop* loop, base::OnceClosure callback) {
+                callback_task_runner->PostTask(
+                    FROM_HERE,
+                    base::BindOnce(
+                        [](RespondWithCallback respond_with_callback,
+                           std::string body) {
+                          std::move(respond_with_callback)
+                              .Run(std::make_unique<std::string>(
+                                  std::move(body)));
+                        },
+                        std::move(respond_with_callback), std::move(body)));
+                loop->task_runner()->PostTask(FROM_HERE, std::move(callback));
+              },
+              callback_task_runner_, std::move(respond_with_callback_),
+              std::move(body), base::MessageLoop::current(),
+              std::move(callback)));
+  return respond_with_done_->value().promise();
+}
+
+void FetchEvent::RespondWith(
+    std::unique_ptr<script::Promise<script::ValueHandle*>>& response,
+    script::ExceptionState* exception_state) {
+  respond_with_called_ = true;
+
+  auto text_promise = web::cache_utils::Then(
+      response->promise(),
+      base::BindOnce(&FetchEvent::GetText, base::Unretained(this)));
+  if (!text_promise) {
+    return;
+  }
+  auto done_promise = web::cache_utils::Then(
+      text_promise.value(),
+      base::BindOnce(&FetchEvent::DoRespondWith, base::Unretained(this)));
+  if (!done_promise) {
+    return;
+  }
+  auto* isolate = response->promise()->GetIsolate();
+  std::unique_ptr<script::Promise<script::ValueHandle*>> wait_promise;
+  script::v8c::FromJSValue(isolate, done_promise.value(), 0, exception_state,
+                           &wait_promise);
+  WaitUntil(environment_settings_, response, exception_state);
+  WaitUntil(environment_settings_, wait_promise, exception_state);
+}
+
+script::HandlePromiseVoid FetchEvent::handled() {
   return script::HandlePromiseVoid(handled_property_->referenced_value());
 }
 
diff --git a/cobalt/worker/fetch_event.h b/cobalt/worker/fetch_event.h
index ac3ff69..2b129c0 100644
--- a/cobalt/worker/fetch_event.h
+++ b/cobalt/worker/fetch_event.h
@@ -41,14 +41,15 @@
              const FetchEventInit& event_init_dict);
   FetchEvent(script::EnvironmentSettings*, base::Token type,
              const FetchEventInit& event_init_dict,
-             std::unique_ptr<RespondWithCallback> respond_with_callback,
-             std::unique_ptr<ReportLoadTimingInfo> report_load_timing_info);
+             scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+             RespondWithCallback respond_with_callback,
+             ReportLoadTimingInfo report_load_timing_info);
   ~FetchEvent() override = default;
 
   void RespondWith(
-      script::EnvironmentSettings*,
-      std::unique_ptr<script::Promise<script::ValueHandle*>>& response);
-  script::HandlePromiseVoid handled(script::EnvironmentSettings*);
+      std::unique_ptr<script::Promise<script::ValueHandle*>>& response,
+      script::ExceptionState* exception_state);
+  script::HandlePromiseVoid handled();
 
   const script::ValueHandleHolder* request() {
     return &(request_->referenced_value());
@@ -59,10 +60,19 @@
   DEFINE_WRAPPABLE_TYPE(FetchEvent);
 
  private:
-  std::unique_ptr<RespondWithCallback> respond_with_callback_;
-  std::unique_ptr<ReportLoadTimingInfo> report_load_timing_info_;
+  base::Optional<v8::Local<v8::Promise>> GetText(
+      v8::Local<v8::Promise> response_promise);
+  base::Optional<v8::Local<v8::Promise>> DoRespondWith(
+      v8::Local<v8::Promise> text_promise);
+  void RespondWithDone();
+
+  script::EnvironmentSettings* environment_settings_;
+  scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner_;
+  RespondWithCallback respond_with_callback_;
+  ReportLoadTimingInfo report_load_timing_info_;
   std::unique_ptr<script::ValueHandleHolder::Reference> request_;
   std::unique_ptr<script::ValuePromiseVoid::Reference> handled_property_;
+  std::unique_ptr<script::ValuePromiseVoid::Reference> respond_with_done_;
   bool respond_with_called_ = false;
   net::LoadTimingInfo load_timing_info_;
 };
diff --git a/cobalt/worker/fetch_event.idl b/cobalt/worker/fetch_event.idl
index 04253c3..072a625 100644
--- a/cobalt/worker/fetch_event.idl
+++ b/cobalt/worker/fetch_event.idl
@@ -24,6 +24,6 @@
 
 
   // Takes a |Promise<any>| because |Response| is polyfilled.
-  [CallWith=EnvironmentSettings] void respondWith(Promise<any> response);
-  [CallWith=EnvironmentSettings] readonly attribute Promise<void> handled;
+  [RaisesException] void respondWith(Promise<any> response);
+  readonly attribute Promise<void> handled;
 };
diff --git a/cobalt/worker/service_worker.cc b/cobalt/worker/service_worker.cc
index de9d193..bc67613 100644
--- a/cobalt/worker/service_worker.cc
+++ b/cobalt/worker/service_worker.cc
@@ -33,9 +33,7 @@
 
 ServiceWorker::ServiceWorker(script::EnvironmentSettings* settings,
                              worker::ServiceWorkerObject* worker)
-    : web::EventTarget(settings),
-      worker_(worker),
-      state_(kServiceWorkerStateParsed) {}
+    : web::EventTarget(settings), worker_(worker) {}
 
 void ServiceWorker::PostMessage(const script::ValueHandleHolder& message) {
   // Algorithm for ServiceWorker.postMessage():
@@ -65,7 +63,7 @@
       FROM_HERE,
       base::BindOnce(&ServiceWorkerJobs::ServiceWorkerPostMessageSubSteps,
                      base::Unretained(jobs), base::Unretained(service_worker),
-                     base::Unretained(incumbent_settings),
+                     base::Unretained(incumbent_settings->context()),
                      std::move(serialize_result)));
 }
 
diff --git a/cobalt/worker/service_worker.h b/cobalt/worker/service_worker.h
index 07d4df5..898a6e5 100644
--- a/cobalt/worker/service_worker.h
+++ b/cobalt/worker/service_worker.h
@@ -51,8 +51,12 @@
   std::string script_url() const { return worker_->script_url().spec(); }
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dom-serviceworker-state
-  void set_state(ServiceWorkerState state) { state_ = state; }
-  ServiceWorkerState state() const { return state_; }
+  void set_state(ServiceWorkerState state) {
+    if (worker_) worker_->set_state(state);
+  }
+  ServiceWorkerState state() const {
+    return worker_ ? worker_->state() : kServiceWorkerStateParsed;
+  }
 
   const EventListenerScriptValue* onstatechange() const {
     return GetAttributeEventListener(base::Tokens::statechange());
@@ -80,7 +84,6 @@
   ~ServiceWorker() override { worker_ = nullptr; }
 
   scoped_refptr<ServiceWorkerObject> worker_;
-  ServiceWorkerState state_;
 };
 
 }  // namespace worker
diff --git a/cobalt/worker/service_worker_consts.cc b/cobalt/worker/service_worker_consts.cc
new file mode 100644
index 0000000..a168caf
--- /dev/null
+++ b/cobalt/worker/service_worker_consts.cc
@@ -0,0 +1,49 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/worker/service_worker_consts.h"
+
+namespace cobalt {
+namespace worker {
+const char ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError[] =
+    "Service Worker Register failed: The script has an unsupported MIME type "
+    "('%s').";
+
+const char ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError[] =
+    "Service Worker Register failed: The script does not have a MIME type.";
+
+const char
+    ServiceWorkerConsts::kServiceWorkerRegisterScriptOriginNotSameError[] =
+        "Service Worker Register failed: Script URL ('%s') and referrer ('%s') "
+        "origin are not the same.";
+
+const char
+    ServiceWorkerConsts::kServiceWorkerRegisterScopeOriginNotSameError[] =
+        "Service Worker Register failed: Scope URL ('%s') and referrer ('%s') "
+        "origin are not the same.";
+
+const char ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError[] =
+    "Service Worker Register failed: Scope ('%s') is not allowed.";
+
+const char
+    ServiceWorkerConsts::kServiceWorkerUnregisterScopeOriginNotSameError[] =
+        "Service Worker Unregister failed: Scope origin does not match.";
+
+const char ServiceWorkerConsts::kServiceWorkerAllowed[] =
+    "Service-Worker-Allowed";
+
+const char ServiceWorkerConsts::kSettingsJson[] =
+    "service_worker_settings.json";
+}  // namespace worker
+}  // namespace cobalt
diff --git a/cobalt/worker/service_worker_consts.h b/cobalt/worker/service_worker_consts.h
new file mode 100644
index 0000000..adb4d31
--- /dev/null
+++ b/cobalt/worker/service_worker_consts.h
@@ -0,0 +1,38 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
+#define COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
+
+namespace cobalt {
+namespace worker {
+
+struct ServiceWorkerConsts {
+  // Constants for error messages.
+  static const char kServiceWorkerRegisterBadMIMEError[];
+  static const char kServiceWorkerRegisterNoMIMEError[];
+  static const char kServiceWorkerRegisterScriptOriginNotSameError[];
+  static const char kServiceWorkerRegisterScopeOriginNotSameError[];
+  static const char kServiceWorkerRegisterBadScopeError[];
+  static const char kServiceWorkerUnregisterScopeOriginNotSameError[];
+  static const char kServiceWorkerAllowed[];
+
+  // Constants for ServiceWorkerPersistentSettings
+  static const char kSettingsJson[];
+};
+
+}  // namespace worker
+}  // namespace cobalt
+
+#endif  // COBALT_WORKER_SERVICE_WORKER_CONSTS_H_
diff --git a/cobalt/worker/service_worker_container.cc b/cobalt/worker/service_worker_container.cc
index 97677b2..9350212 100644
--- a/cobalt/worker/service_worker_container.cc
+++ b/cobalt/worker/service_worker_container.cc
@@ -69,16 +69,17 @@
                          ->script_value_factory()
                          ->CreateInterfacePromise<
                              scoped_refptr<ServiceWorkerRegistration>>();
-    promise_reference_.reset(
-        new script::ValuePromiseWrappable::Reference(this, ready_promise_));
+    promise_reference_.reset(new script::ValuePromiseWrappable::Reference(
+        environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+        ready_promise_));
   }
   // 2. Let readyPromise be this's ready promise.
   script::HandlePromiseWrappable ready_promise(ready_promise_);
   // 3. If readyPromise is pending, run the following substeps in parallel:
   if (ready_promise->State() == script::PromiseState::kPending) {
     //    3.1. Let client by this's service worker client.
-    web::EnvironmentSettings* client = environment_settings();
-    worker::ServiceWorkerJobs* jobs = client->context()->service_worker_jobs();
+    web::Context* client = environment_settings()->context();
+    worker::ServiceWorkerJobs* jobs = client->service_worker_jobs();
     jobs->message_loop()->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ServiceWorkerJobs::MaybeResolveReadyPromiseSubSteps,
@@ -132,10 +133,12 @@
           ->script_value_factory()
           ->CreateInterfacePromise<scoped_refptr<ServiceWorkerRegistration>>();
   std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
-      new script::ValuePromiseWrappable::Reference(this, promise));
+      new script::ValuePromiseWrappable::Reference(
+          environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+          promise));
 
   // 2. Let client be this's service worker client.
-  web::EnvironmentSettings* client = environment_settings();
+  web::Context* client = environment_settings()->context();
   // 3. Let scriptURL be the result of parsing scriptURL with this's
   // relevant settings object’s API base URL.
   const GURL& base_url = environment_settings()->base_url();
@@ -152,9 +155,9 @@
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerJobs::StartRegister,
-                     base::Unretained(client->context()->service_worker_jobs()),
-                     scope_url, script_url, std::move(promise_reference),
-                     client, options.type(), options.update_via_cache()));
+                     base::Unretained(client->service_worker_jobs()), scope_url,
+                     script_url, std::move(promise_reference), client,
+                     options.type(), options.update_via_cache()));
   // 7. Return p.
   return promise;
 }
@@ -170,14 +173,15 @@
   // Perform the rest of the steps in a task, because the promise has to be
   // returned before we can safely reject or resolve it.
   auto promise =
-      base::polymorphic_downcast<web::EnvironmentSettings*>(
-          environment_settings())
+      environment_settings()
           ->context()
           ->global_environment()
           ->script_value_factory()
           ->CreateInterfacePromise<scoped_refptr<ServiceWorkerRegistration>>();
   std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
-      new script::ValuePromiseWrappable::Reference(this, promise));
+      new script::ValuePromiseWrappable::Reference(
+          environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+          promise));
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&ServiceWorkerContainer::GetRegistrationTask,
                                 base::Unretained(this), url,
@@ -197,11 +201,11 @@
   // Algorithm for 'ServiceWorkerContainer.getRegistration()':
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#navigator-service-worker-getRegistration
   // 1. Let client be this's service worker client.
-  web::EnvironmentSettings* client = environment_settings();
+  web::Context* client = environment_settings()->context();
 
   // 2. Let storage key be the result of running obtain a storage key given
   //    client.
-  url::Origin storage_key = client->ObtainStorageKey();
+  url::Origin storage_key = client->environment_settings()->ObtainStorageKey();
 
   // 3. Let clientURL be the result of parsing clientURL with this's relevant
   //    settings object’s API base URL.
@@ -232,7 +236,7 @@
 
   // 7. Let promise be a new promise.
   // 8. Run the following substeps in parallel:
-  worker::ServiceWorkerJobs* jobs = client->context()->service_worker_jobs();
+  worker::ServiceWorkerJobs* jobs = client->service_worker_jobs();
   DCHECK(jobs);
   jobs->message_loop()->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&ServiceWorkerJobs::GetRegistrationSubSteps,
@@ -248,8 +252,9 @@
                      ->script_value_factory()
                      ->CreateBasicPromise<script::SequenceWrappable>();
   std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
-      promise_reference(
-          new script::ValuePromiseSequenceWrappable::Reference(this, promise));
+      promise_reference(new script::ValuePromiseSequenceWrappable::Reference(
+          environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+          promise));
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&ServiceWorkerContainer::GetRegistrationsTask,
@@ -260,7 +265,7 @@
 void ServiceWorkerContainer::GetRegistrationsTask(
     std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
         promise_reference) {
-  auto* client = environment_settings();
+  auto* client = environment_settings()->context();
   // https://w3c.github.io/ServiceWorker/#navigator-service-worker-getRegistrations
   worker::ServiceWorkerJobs* jobs =
       environment_settings()->context()->service_worker_jobs();
diff --git a/cobalt/worker/service_worker_container.h b/cobalt/worker/service_worker_container.h
index aca45b6..94679d6 100644
--- a/cobalt/worker/service_worker_container.h
+++ b/cobalt/worker/service_worker_container.h
@@ -76,8 +76,6 @@
       std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
           promise_reference);
 
-  scoped_refptr<ServiceWorker> ready_;
-
   script::HandlePromiseWrappable ready_promise_;
   std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference_;
 };
diff --git a/cobalt/worker/service_worker_global_scope.cc b/cobalt/worker/service_worker_global_scope.cc
index fe6552f..e71735f 100644
--- a/cobalt/worker/service_worker_global_scope.cc
+++ b/cobalt/worker/service_worker_global_scope.cc
@@ -34,9 +34,12 @@
 
 namespace cobalt {
 namespace worker {
+
 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
-    script::EnvironmentSettings* settings, ServiceWorkerObject* service_worker)
-    : WorkerGlobalScope(settings),
+    script::EnvironmentSettings* settings,
+    const web::WindowOrWorkerGlobalScope::Options& options,
+    ServiceWorkerObject* service_worker)
+    : WorkerGlobalScope(settings, options),
       clients_(new Clients(settings)),
       service_worker_object_(base::AsWeakPtr(service_worker)) {
   loader::FetchInterceptorCoordinator::GetInstance()->Add(this);
@@ -190,28 +193,49 @@
 }
 
 void ServiceWorkerGlobalScope::StartFetch(
-    const GURL& url,
-    std::unique_ptr<base::OnceCallback<void(std::unique_ptr<std::string>)>>
-        callback,
-    std::unique_ptr<base::OnceCallback<void(const net::LoadTimingInfo&)>>
+    const GURL& url, bool main_resource,
+    const net::HttpRequestHeaders& request_headers,
+    scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+    base::OnceCallback<void(std::unique_ptr<std::string>)> callback,
+    base::OnceCallback<void(const net::LoadTimingInfo&)>
         report_load_timing_info,
-    std::unique_ptr<base::OnceClosure> fallback) {
+    base::OnceClosure fallback) {
+  // Only HTTP or HTTPS fetches should be intercepted.
+  // https://fetch.spec.whatwg.org/commit-snapshots/8f8ab504da6ca9681db5c7f8aa3d1f4b6bf8840c/#http-fetch
+  if (!url.SchemeIsHTTPOrHTTPS()) {
+    std::move(fallback).Run();
+    return;
+  }
   if (base::MessageLoop::current() !=
       environment_settings()->context()->message_loop()) {
     environment_settings()->context()->message_loop()->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ServiceWorkerGlobalScope::StartFetch,
-                       base::Unretained(this), url, std::move(callback),
-                       std::move(report_load_timing_info),
+                       base::Unretained(this), url, main_resource,
+                       request_headers, callback_task_runner,
+                       std::move(callback), std::move(report_load_timing_info),
                        std::move(fallback)));
     return;
   }
   if (!service_worker()) {
-    std::move(*fallback).Run();
+    callback_task_runner->PostTask(FROM_HERE, std::move(fallback));
     return;
   }
+
+  auto* registration =
+      service_worker_object_->containing_service_worker_registration();
+  if (registration && (main_resource || registration->stale())) {
+    worker::ServiceWorkerJobs* jobs =
+        environment_settings()->context()->service_worker_jobs();
+    jobs->message_loop()->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ServiceWorkerJobs::SoftUpdate, base::Unretained(jobs),
+                       base::Unretained(registration),
+                       /*force_bypass_cache=*/false));
+  }
+
   // TODO: handle the following steps in
-  //       https://w3c.github.io/ServiceWorker/#handle-fetch.
+  //       https://www.w3.org/TR/2022/CRD-service-workers-20220712/#handle-fetch.
   // 22. If activeWorker’s state is "activating", wait for activeWorker’s state
   //     to become "activated".
   // 23. If the result of running the Run Service Worker algorithm with
@@ -220,22 +244,37 @@
   auto* global_environment = get_global_environment(environment_settings());
   auto* isolate = global_environment->isolate();
   script::v8c::EntryScope entry_scope(isolate);
+  base::DictionaryValue options;
+  if (main_resource) {
+    options.SetKey("mode", base::Value("navigate"));
+  }
+  base::ListValue headers;
+  for (auto header_pair : request_headers.GetHeaderVector()) {
+    base::ListValue header;
+    header.GetList().emplace_back(header_pair.key);
+    header.GetList().emplace_back(header_pair.value);
+    headers.GetList().push_back(std::move(header));
+  }
+  options.SetKey("headers", std::move(headers));
   auto request =
-      web::cache_utils::CreateRequest(environment_settings(), url.spec());
+      web::cache_utils::CreateRequest(isolate, url.spec(), std::move(options));
   if (!request) {
-    std::move(*fallback).Run();
+    callback_task_runner->PostTask(FROM_HERE, std::move(fallback));
     return;
   }
+
   FetchEventInit event_init;
-  event_init.set_request(request.value().GetScriptValue());
+  event_init.set_request(
+      web::cache_utils::FromV8Value(isolate, request.value()).GetScriptValue());
   scoped_refptr<FetchEvent> fetch_event =
       new FetchEvent(environment_settings(), base::Tokens::fetch(), event_init,
-                     std::move(callback), std::move(report_load_timing_info));
+                     callback_task_runner, std::move(callback),
+                     std::move(report_load_timing_info));
   // 24. Create and dispatch event.
   DispatchEvent(fetch_event);
   // TODO: implement steps 25 and 26.
   if (!fetch_event->respond_with_called()) {
-    std::move(*fallback).Run();
+    callback_task_runner->PostTask(FROM_HERE, std::move(fallback));
   }
 }
 
diff --git a/cobalt/worker/service_worker_global_scope.h b/cobalt/worker/service_worker_global_scope.h
index f89606c..a32ba66 100644
--- a/cobalt/worker/service_worker_global_scope.h
+++ b/cobalt/worker/service_worker_global_scope.h
@@ -38,6 +38,7 @@
 #include "cobalt/worker/service_worker_registration.h"
 #include "cobalt/worker/worker_global_scope.h"
 #include "net/base/load_timing_info.h"
+#include "net/http/http_request_headers.h"
 
 namespace cobalt {
 namespace worker {
@@ -48,8 +49,10 @@
 class ServiceWorkerGlobalScope : public WorkerGlobalScope,
                                  public loader::FetchInterceptor {
  public:
-  explicit ServiceWorkerGlobalScope(script::EnvironmentSettings* settings,
-                                    ServiceWorkerObject* service_worker);
+  explicit ServiceWorkerGlobalScope(
+      script::EnvironmentSettings* settings,
+      const web::WindowOrWorkerGlobalScope::Options& options,
+      ServiceWorkerObject* service_worker);
   ServiceWorkerGlobalScope(const ServiceWorkerGlobalScope&) = delete;
   ServiceWorkerGlobalScope& operator=(const ServiceWorkerGlobalScope&) = delete;
 
@@ -72,12 +75,13 @@
   script::HandlePromiseVoid SkipWaiting();
 
   void StartFetch(
-      const GURL& url,
-      std::unique_ptr<base::OnceCallback<void(std::unique_ptr<std::string>)>>
-          callback,
-      std::unique_ptr<base::OnceCallback<void(const net::LoadTimingInfo&)>>
+      const GURL& url, bool main_resource,
+      const net::HttpRequestHeaders& request_headers,
+      scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner,
+      base::OnceCallback<void(std::unique_ptr<std::string>)> callback,
+      base::OnceCallback<void(const net::LoadTimingInfo&)>
           report_load_timing_info,
-      std::unique_ptr<base::OnceClosure> fallback) override;
+      base::OnceClosure fallback) override;
 
   const web::EventTargetListenerInfo::EventListenerScriptValue* oninstall() {
     return GetAttributeEventListener(base::Tokens::install());
diff --git a/cobalt/worker/service_worker_jobs.cc b/cobalt/worker/service_worker_jobs.cc
index 6f4e1ad..3052d63 100644
--- a/cobalt/worker/service_worker_jobs.cc
+++ b/cobalt/worker/service_worker_jobs.cc
@@ -28,6 +28,7 @@
 #include "base/message_loop/message_loop_current.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/synchronization/lock.h"
 #include "base/task_runner.h"
 #include "base/time/time.h"
@@ -51,6 +52,7 @@
 #include "cobalt/worker/extendable_message_event.h"
 #include "cobalt/worker/frame_type.h"
 #include "cobalt/worker/service_worker.h"
+#include "cobalt/worker/service_worker_consts.h"
 #include "cobalt/worker/service_worker_container.h"
 #include "cobalt/worker/service_worker_global_scope.h"
 #include "cobalt/worker/service_worker_registration.h"
@@ -69,6 +71,13 @@
 namespace worker {
 
 namespace {
+
+const base::TimeDelta kWaitForAsynchronousExtensionsTimeout =
+    base::TimeDelta::FromSeconds(3);
+
+const base::TimeDelta kShutdownWaitTimeoutSecs =
+    base::TimeDelta::FromSeconds(5);
+
 bool PathContainsEscapedSlash(const GURL& url) {
   const std::string path = url.path();
   return (path.find("%2f") != std::string::npos ||
@@ -129,7 +138,8 @@
 ServiceWorkerJobs::ServiceWorkerJobs(web::WebSettings* web_settings,
                                      network::NetworkModule* network_module,
                                      web::UserAgentPlatformInfo* platform_info,
-                                     base::MessageLoop* message_loop)
+                                     base::MessageLoop* message_loop,
+                                     const GURL& url)
     : message_loop_(message_loop) {
   DCHECK_EQ(message_loop_, base::MessageLoop::current());
   fetcher_factory_.reset(new loader::FetcherFactory(network_module));
@@ -140,24 +150,31 @@
   DCHECK(script_loader_factory_);
 
   ServiceWorkerPersistentSettings::Options options(web_settings, network_module,
-                                                   platform_info, this);
+                                                   platform_info, this, url);
   scope_to_registration_map_.reset(new ServiceWorkerRegistrationMap(options));
   DCHECK(scope_to_registration_map_);
 }
 
 ServiceWorkerJobs::~ServiceWorkerJobs() {
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
-  while (!web_context_registrations_.empty()) {
-    // Wait for web context registrations to be cleared.
-    web_context_registrations_cleared_.Wait();
-  }
   scope_to_registration_map_->HandleUserAgentShutdown(this);
   scope_to_registration_map_->AbortAllActive();
-}
+  scope_to_registration_map_.reset();
+  if (!web_context_registrations_.empty()) {
+    // Abort any Service Workers that remain.
+    for (auto& context : web_context_registrations_) {
+      DCHECK(context);
+      if (context->GetWindowOrWorkerGlobalScope()->IsServiceWorker()) {
+        ServiceWorkerGlobalScope* service_worker =
+            context->GetWindowOrWorkerGlobalScope()->AsServiceWorker();
+        if (service_worker && service_worker->service_worker_object()) {
+          service_worker->service_worker_object()->Abort();
+        }
+      }
+    }
 
-void ServiceWorkerJobs::Stop() {
-  if (!done_event_.IsSignaled()) {
-    done_event_.Signal();
+    // Wait for web context registrations to be cleared.
+    web_context_registrations_cleared_.TimedWait(kShutdownWaitTimeoutSecs);
   }
 }
 
@@ -165,13 +182,13 @@
     const base::Optional<GURL>& maybe_scope_url,
     const GURL& script_url_with_fragment,
     std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference,
-    web::EnvironmentSettings* client, const WorkerType& type,
+    web::Context* client, const WorkerType& type,
     const ServiceWorkerUpdateViaCache& update_via_cache) {
   TRACE_EVENT2("cobalt::worker", "ServiceWorkerJobs::StartRegister()", "scope",
                maybe_scope_url.value_or(GURL()).spec(), "script",
                script_url_with_fragment.spec());
   DCHECK_NE(message_loop(), base::MessageLoop::current());
-  DCHECK_EQ(client->context()->message_loop(), base::MessageLoop::current());
+  DCHECK_EQ(client->message_loop(), base::MessageLoop::current());
   // Algorithm for Start Register:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#start-register-algorithm
   // 1. If scriptURL is failure, reject promise with a TypeError and abort these
@@ -205,7 +222,7 @@
 
   DCHECK(client);
   web::WindowOrWorkerGlobalScope* window_or_worker_global_scope =
-      client->context()->GetWindowOrWorkerGlobalScope();
+      client->GetWindowOrWorkerGlobalScope();
   DCHECK(window_or_worker_global_scope);
   web::CspDelegate* csp_delegate =
       window_or_worker_global_scope->csp_delegate();
@@ -252,7 +269,7 @@
 
   // 10. Let storage key be the result of running obtain a storage key given
   //     client.
-  url::Origin storage_key = client->ObtainStorageKey();
+  url::Origin storage_key = client->environment_settings()->ObtainStorageKey();
 
   // 11. Let job be the result of running Create Job with register, storage key,
   //     scopeURL, scriptURL, promise, and client.
@@ -271,9 +288,7 @@
   // This is the same value as set in CreateJob().
 
   // 15. Invoke Schedule Job with job.
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
-                                base::Unretained(this), std::move(job)));
+  ScheduleJob(std::move(job));
   DCHECK(!job.get());
 }
 
@@ -290,7 +305,7 @@
 std::unique_ptr<ServiceWorkerJobs::Job> ServiceWorkerJobs::CreateJob(
     JobType type, const url::Origin& storage_key, const GURL& scope_url,
     const GURL& script_url, std::unique_ptr<JobPromiseType> promise,
-    web::EnvironmentSettings* client) {
+    web::Context* client) {
   TRACE_EVENT2("cobalt::worker", "ServiceWorkerJobs::CreateJob()", "type", type,
                "script_url", script_url.spec());
   // Algorithm for Create Job:
@@ -306,7 +321,7 @@
                                    client, std::move(promise)));
   // 8. If client is not null, set job’s referrer to client’s creation URL.
   if (client) {
-    job->referrer = client->creation_url();
+    job->referrer = client->environment_settings()->creation_url();
   }
   // 9. Return job.
   return job;
@@ -314,8 +329,16 @@
 
 void ServiceWorkerJobs::ScheduleJob(std::unique_ptr<Job> job) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::ScheduleJob()");
-  DCHECK_EQ(message_loop(), base::MessageLoop::current());
   DCHECK(job);
+
+  if (base::MessageLoop::current() != message_loop()) {
+    DCHECK(message_loop());
+    message_loop()->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
+                                  base::Unretained(this), std::move(job)));
+    return;
+  }
+  DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Schedule Job:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#schedule-job
   // 1. Let jobQueue be null.
@@ -325,21 +348,28 @@
 
   // 3. If scope to job queue map[jobScope] does not exist, set scope to job
   // queue map[jobScope] to a new job queue.
-  if (job_queue_map_.find(job_scope) == job_queue_map_.end()) {
+  auto job_queue_iterator_for_scope = job_queue_map_.find(job_scope);
+  if (job_queue_iterator_for_scope == job_queue_map_.end()) {
     auto insertion = job_queue_map_.emplace(
         job_scope, std::unique_ptr<JobQueue>(new JobQueue()));
     DCHECK(insertion.second);
+    job_queue_iterator_for_scope = insertion.first;
   }
 
   // 4. Set jobQueue to scope to job queue map[jobScope].
-  DCHECK(job_queue_map_.find(job_scope) != job_queue_map_.end());
-  JobQueue* job_queue = job_queue_map_.find(job_scope)->second.get();
+  DCHECK(job_queue_iterator_for_scope != job_queue_map_.end());
+  JobQueue* job_queue = job_queue_iterator_for_scope->second.get();
 
   // 5. If jobQueue is empty, then:
   if (job_queue->empty()) {
     // 5.1. Set job’s containing job queue to jobQueue, and enqueue job to
     // jobQueue.
     job->containing_job_queue = job_queue;
+    if (!IsWebContextRegistered(job->client)) {
+      // Note: The client that requested the job has already exited and isn't
+      // able to handle the promise.
+      job->containing_job_queue->PrepareJobForClientShutdown(job, job->client);
+    }
     job_queue->Enqueue(std::move(job));
 
     // 5.2. Invoke Run Job with jobQueue.
@@ -355,7 +385,7 @@
       // settled, append job to lastJob’s list of equivalent jobs.
       DCHECK(last_job);
       base::AutoLock lock(last_job->equivalent_jobs_promise_mutex);
-      if (EquivalentJobs(job.get(), last_job) && last_job->promise &&
+      if (ReturnJobsAreEquivalent(job.get(), last_job) && last_job->promise &&
           last_job->promise->is_pending()) {
         last_job->equivalent_jobs.push_back(std::move(job));
         return;
@@ -365,12 +395,17 @@
     // 6.3. Else, set job’s containing job queue to jobQueue, and enqueue job to
     // jobQueue.
     job->containing_job_queue = job_queue;
+    if (!IsWebContextRegistered(job->client)) {
+      // Note: The client that requested the job has already exited and isn't
+      // able to handle the promise.
+      job->containing_job_queue->PrepareJobForClientShutdown(job, job->client);
+    }
     job_queue->Enqueue(std::move(job));
   }
   DCHECK(!job);
 }
 
-bool ServiceWorkerJobs::EquivalentJobs(Job* one, Job* two) {
+bool ServiceWorkerJobs::ReturnJobsAreEquivalent(Job* one, Job* two) {
   // Algorithm for Two jobs are equivalent:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-job-equivalent
   DCHECK(one);
@@ -476,10 +511,13 @@
   if (!job_script_origin.IsSameOriginWith(job_referrer_origin)) {
     // 2.1. Invoke Reject Job Promise with job and "SecurityError" DOMException.
     RejectJobPromise(
-        job, PromiseErrorData(
-                 web::DOMException::kSecurityErr,
-                 "Service Worker Register failed: Script URL and referrer "
-                 "origin are not the same."));
+        job,
+        PromiseErrorData(
+            web::DOMException::kSecurityErr,
+            base::StringPrintf(
+                ServiceWorkerConsts::
+                    kServiceWorkerRegisterScriptOriginNotSameError,
+                job->script_url.spec().c_str(), job->referrer.spec().c_str())));
     // 2.2. Invoke Finish Job with job and abort these steps.
     FinishJob(job);
     return;
@@ -491,10 +529,13 @@
   if (!job_scope_origin.IsSameOriginWith(job_referrer_origin)) {
     // 3.1. Invoke Reject Job Promise with job and "SecurityError" DOMException.
     RejectJobPromise(
-        job, PromiseErrorData(
-                 web::DOMException::kSecurityErr,
-                 "Service Worker Register failed: Scope URL and referrer "
-                 "origin are not the same."));
+        job,
+        PromiseErrorData(
+            web::DOMException::kSecurityErr,
+            base::StringPrintf(
+                ServiceWorkerConsts::
+                    kServiceWorkerRegisterScopeOriginNotSameError,
+                job->scope_url.spec().c_str(), job->referrer.spec().c_str())));
 
     // 3.2. Invoke Finish Job with job and abort these steps.
     FinishJob(job);
@@ -511,7 +552,8 @@
   if (registration) {
     // 5.1 Let newestWorker be the result of running the Get Newest Worker
     // algorithm passing registration as the argument.
-    ServiceWorkerObject* newest_worker = registration->GetNewestWorker();
+    const scoped_refptr<ServiceWorkerObject>& newest_worker =
+        registration->GetNewestWorker();
 
     // 5.2 If newestWorker is not null, job’s script url equals newestWorker’s
     // script url, job’s worker type equals newestWorker’s type, and job’s
@@ -538,6 +580,69 @@
   Update(job);
 }
 
+void ServiceWorkerJobs::SoftUpdate(
+    ServiceWorkerRegistrationObject* registration, bool force_bypass_cache) {
+  TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::SoftUpdate()");
+  DCHECK_EQ(message_loop(), base::MessageLoop::current());
+  DCHECK(registration);
+  // Algorithm for SoftUpdate:
+  //    https://www.w3.org/TR/2022/CRD-service-workers-20220712/#soft-update
+  // 1. Let newestWorker be the result of running Get Newest Worker algorithm
+  // passing registration as its argument.
+  ServiceWorkerObject* newest_worker = registration->GetNewestWorker();
+
+  // 2. If newestWorker is null, abort these steps.
+  if (newest_worker == nullptr) {
+    return;
+  }
+
+  // 3. Let job be the result of running Create Job with update, registration’s
+  // storage key, registration’s scope url, newestWorker’s script url, null, and
+  // null.
+  std::unique_ptr<Job> job = CreateJobWithoutPromise(
+      kUpdate, registration->storage_key(), registration->scope_url(),
+      newest_worker->script_url());
+
+  // 4. Set job’s worker type to newestWorker’s type.
+  // Cobalt only supports 'classic' worker type.
+
+  // 5. Set job’s force bypass cache flag if forceBypassCache is true.
+  job->force_bypass_cache_flag = force_bypass_cache;
+
+  // 6. Invoke Schedule Job with job.
+  message_loop()->task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
+                                base::Unretained(this), std::move(job)));
+  DCHECK(!job.get());
+}
+
+void ServiceWorkerJobs::EnsureServiceWorkerStarted(
+    const url::Origin& storage_key, const GURL& client_url,
+    base::WaitableEvent* done_event) {
+  if (message_loop() != base::MessageLoop::current()) {
+    message_loop()->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ServiceWorkerJobs::EnsureServiceWorkerStarted,
+                       base::Unretained(this), storage_key, client_url,
+                       done_event));
+    return;
+  }
+  base::ScopedClosureRunner signal_done(base::BindOnce(
+      [](base::WaitableEvent* done_event) { done_event->Signal(); },
+      done_event));
+  base::TimeTicks start = base::TimeTicks::Now();
+  auto registration =
+      scope_to_registration_map_->GetRegistration(storage_key, client_url);
+  if (!registration) {
+    return;
+  }
+  auto service_worker_object = registration->active_worker();
+  if (!service_worker_object || service_worker_object->is_running()) {
+    return;
+  }
+  service_worker_object->ObtainWebAgentAndWaitUntilDone();
+}
+
 void ServiceWorkerJobs::Update(Job* job) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::Update()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
@@ -562,7 +667,8 @@
   }
   // 3. Let newestWorker be the result of running Get Newest Worker algorithm
   //    passing registration as the argument.
-  ServiceWorkerObject* newest_worker = registration->GetNewestWorker();
+  const scoped_refptr<ServiceWorkerObject>& newest_worker =
+      registration->GetNewestWorker();
 
   // 4. If job’s job type is update, and newestWorker is not null and its script
   //    url does not equal job’s script url, then:
@@ -657,6 +763,14 @@
   if (headers->GetNormalizedHeader("Content-type", &content_type)) {
     //   8.7.  Extract a MIME type from the response’s header list. If this MIME
     //         type (ignoring parameters) is not a JavaScript MIME type, then:
+    if (content_type.empty()) {
+      RejectJobPromise(
+          state->job,
+          PromiseErrorData(
+              web::DOMException::kSecurityErr,
+              ServiceWorkerConsts::kServiceWorkerRegisterNoMIMEError));
+      return true;
+    }
     for (auto mime_type : kJavaScriptMimeTypes) {
       if (net::MatchesMimeType(mime_type, content_type)) {
         mime_type_is_javascript = true;
@@ -668,17 +782,20 @@
     //   8.7.1. Invoke Reject Job Promise with job and "SecurityError"
     //          DOMException.
     //   8.7.2. Asynchronously complete these steps with a network error.
-    RejectJobPromise(state->job,
-                     PromiseErrorData(web::DOMException::kSecurityErr,
-                                      "Service Worker Script is not "
-                                      "JavaScript MIME type."));
+    RejectJobPromise(
+        state->job,
+        PromiseErrorData(
+            web::DOMException::kSecurityErr,
+            base::StringPrintf(
+                ServiceWorkerConsts::kServiceWorkerRegisterBadMIMEError,
+                content_type.c_str())));
     return true;
   }
-  //   8.8.  Let serviceWorkerAllowed be the resulf extracting header list
+  //   8.8.  Let serviceWorkerAllowed be the result of extracting header list
   //         values given `Service-Worker-Allowed` and response’s header list.
   std::string service_worker_allowed;
   bool service_worker_allowed_exists = headers->GetNormalizedHeader(
-      "Service-Worker-Allowed", &service_worker_allowed);
+      ServiceWorkerConsts::kServiceWorkerAllowed, &service_worker_allowed);
   //   8.9.  Set policyContainer to the result of creating a policy container
   //         from a fetch response given response.
   state->script_headers = headers;
@@ -720,9 +837,13 @@
     //   8.16.1. Invoke Reject Job Promise with job and "SecurityError"
     //           DOMException.
     //   8.16.2. Asynchronously complete these steps with a network error.
-    RejectJobPromise(state->job,
-                     PromiseErrorData(web::DOMException::kSecurityErr,
-                                      "Scope not allowed."));
+    RejectJobPromise(
+        state->job,
+        PromiseErrorData(
+            web::DOMException::kSecurityErr,
+            base::StringPrintf(
+                ServiceWorkerConsts::kServiceWorkerRegisterBadScopeError,
+                scope_string.c_str())));
     return true;
   }
   return true;
@@ -748,6 +869,15 @@
   DCHECK(updated_script_content);
   //   8.19. If response’s cache state is not "local", set registration’s last
   //         update check time to the current time.
+  scoped_refptr<ServiceWorkerRegistrationObject> registration =
+      scope_to_registration_map_->GetRegistration(state->job->storage_key,
+                                                  state->job->scope_url);
+  if (registration) {
+    registration->set_last_update_check_time(base::Time::Now());
+    scope_to_registration_map_->PersistRegistration(registration->storage_key(),
+                                                    registration->scope_url());
+  }
+  // TODO(b/228904017):
   //   8.20. Set hasUpdatedResources to true if any of the following are true:
   //          - newestWorker is null.
   //          - newestWorker’s script url is not url or newestWorker’s type is
@@ -781,9 +911,15 @@
   TRACE_EVENT0("cobalt::worker",
                "ServiceWorkerJobs::UpdateOnLoadingComplete()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
-  if (state->job->promise.get() == nullptr) {
-    // The job is already rejected, which means there was an error, so finish
-    // the job and skip the remaining steps.
+  bool check_promise = !state->job->no_promise_okay;
+  if (state->job->no_promise_okay && !state->job->client &&
+      web_context_registrations_.size() > 0) {
+    state->job->client = *(web_context_registrations_.begin());
+  }
+  if ((check_promise && !state->job->promise.get()) || !state->job->client) {
+    // The job is already rejected, which means there was an error, or the
+    // client is already shutdown, so finish the job and skip the remaining
+    // steps.
     FinishJob(state->job);
     return;
   }
@@ -791,7 +927,7 @@
   if (error) {
     RejectJobPromise(
         state->job,
-        PromiseErrorData(web::DOMException::kNetworkErr, error.value()));
+        PromiseErrorData(web::DOMException::kSecurityErr, error.value()));
     if (state->newest_worker == nullptr) {
       scope_to_registration_map_->RemoveRegistration(state->job->storage_key,
                                                      state->job->scope_url);
@@ -806,7 +942,12 @@
       state->newest_worker->classic_scripts_imported()) {
     // This checks if there are any updates to already stored importScripts
     // resources.
-    if (state->newest_worker->worker_global_scope()
+    // TODO(b/259731731): worker_global_scope_ is set in
+    // ServiceWorkerObject::Initialize, part of the RunServiceWorkerAlgorithm.
+    // For persisted service workers this may not be called before SoftUpdate,
+    // find a way to ensure worker_global_scope_ is not null in that case.
+    if (state->newest_worker->worker_global_scope() != nullptr &&
+        state->newest_worker->worker_global_scope()
             ->LoadImportsAndReturnIfUpdated(
                 state->newest_worker->script_resource_map(),
                 &state->updated_resource_map)) {
@@ -855,12 +996,11 @@
 
   // 11. Let worker be a new service worker.
   ServiceWorkerObject::Options options(
-      "ServiceWorker", state->job->client->context()->web_settings(),
-      state->job->client->context()->network_module(), state->registration);
-  options.web_options.platform_info =
-      state->job->client->context()->platform_info();
+      "ServiceWorker", state->job->client->web_settings(),
+      state->job->client->network_module(), state->registration);
+  options.web_options.platform_info = state->job->client->platform_info();
   options.web_options.service_worker_jobs =
-      state->job->client->context()->service_worker_jobs();
+      state->job->client->service_worker_jobs();
   scoped_refptr<ServiceWorkerObject> worker(new ServiceWorkerObject(options));
   // 12. Set worker’s script url to job’s script url, worker’s script
   //     resource to script, worker’s type to job’s worker type, and worker’s
@@ -884,8 +1024,8 @@
   // RunServiceWorker, such as for registering the web context, execute first.
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE, base::Bind(&ServiceWorkerJobs::UpdateOnRunServiceWorker,
-                            base::Unretained(this), state, std::move(worker),
-                            run_result_is_success));
+                            base::Unretained(this), std::move(state),
+                            std::move(worker), run_result_is_success));
 }
 
 void ServiceWorkerJobs::UpdateOnRunServiceWorker(
@@ -948,9 +1088,26 @@
   return worker->start_status();
 }
 
+bool ServiceWorkerJobs::WaitForAsynchronousExtensions(
+    const scoped_refptr<ServiceWorkerRegistrationObject>& registration) {
+  // TODO(b/240164388): Investigate a better approach for combining waiting
+  // for the ExtendableEvent while also allowing use of algorithms that run
+  // on the same thread from the event handler.
+  base::TimeTicks wait_start_time = base::TimeTicks::Now();
+  do {
+    if (registration->done_event()->TimedWait(
+            base::TimeDelta::FromMilliseconds(100)))
+      break;
+    base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
+    base::RunLoop().RunUntilIdle();
+  } while ((base::TimeTicks::Now() - wait_start_time) <
+           kWaitForAsynchronousExtensionsTimeout);
+  return registration->done_event()->IsSignaled();
+}
+
 void ServiceWorkerJobs::Install(
-    Job* job, scoped_refptr<ServiceWorkerObject> worker,
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    Job* job, const scoped_refptr<ServiceWorkerObject>& worker,
+    const scoped_refptr<ServiceWorkerRegistrationObject>& registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::Install()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Install:
@@ -965,7 +1122,8 @@
 
   // 2. Let newestWorker be the result of running Get Newest Worker algorithm
   //    passing registration as its argument.
-  ServiceWorkerObject* newest_worker = registration->GetNewestWorker();
+  const scoped_refptr<ServiceWorkerObject>& newest_worker =
+      registration->GetNewestWorker();
 
   // 3. Set registration’s update via cache mode to job’s update via cache mode.
   registration->set_update_via_cache_mode(job->update_via_cache);
@@ -979,7 +1137,7 @@
   UpdateWorkerState(registration->installing_worker(),
                     kServiceWorkerStateInstalling);
   // 6. Assert: job’s job promise is not null.
-  DCHECK(job->promise.get() != nullptr);
+  DCHECK(job->no_promise_okay || job->promise.get() != nullptr);
   // 7. Invoke Resolve Job Promise with job and registration.
   ResolveJobPromise(job, registration);
   // 8. Let settingsObjects be all environment settings objects whose origin is
@@ -1040,8 +1198,8 @@
     } else {
       // 11.3.1. Queue a task task on installingWorker’s event loop using the
       //         DOM manipulation task source to run the following steps:
-      DCHECK(done_event_.IsSignaled());
-      done_event_.Reset();
+      DCHECK(registration->done_event()->IsSignaled());
+      registration->done_event()->Reset();
       installing_worker->web_agent()
           ->context()
           ->message_loop()
@@ -1075,8 +1233,12 @@
                           done_event->Signal();
                         },
                         done_event, install_failed);
-                    scoped_refptr<ExtendableEvent> event(new ExtendableEvent(
-                        base::Tokens::install(), std::move(done_callback)));
+                    auto* settings = installing_worker->web_agent()
+                                         ->context()
+                                         ->environment_settings();
+                    scoped_refptr<ExtendableEvent> event(
+                        new ExtendableEvent(settings, base::Tokens::install(),
+                                            std::move(done_callback)));
                     installing_worker->worker_global_scope()->DispatchEvent(
                         event);
                     if (!event->IsActive()) {
@@ -1086,18 +1248,15 @@
                       done_event->Signal();
                     }
                   },
-                  base::Unretained(installing_worker), &done_event_,
-                  install_failed));
+                  base::Unretained(installing_worker),
+                  registration->done_event(), install_failed));
       // 11.3.2. Wait for task to have executed or been discarded.
       // This waiting is done inside PostBlockingTask above.
       // 11.3.3. Wait for the step labeled WaitForAsynchronousExtensions to
       //         complete.
-      // TODO(b/240164388): Investigate a better approach for combining waiting
-      // for the ExtendableEvent while also allowing use of algorithms that run
-      // on the same thread from the event handler.
-      while (!done_event_.TimedWait(base::TimeDelta::FromMilliseconds(100))) {
-        base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
-        base::RunLoop().RunUntilIdle();
+      if (!WaitForAsynchronousExtensions(registration)) {
+        // Timeout
+        install_failed->store(true);
       }
     }
   }
@@ -1163,7 +1322,7 @@
 }
 
 bool ServiceWorkerJobs::IsAnyClientUsingRegistration(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    ServiceWorkerRegistrationObject* registration) {
   bool any_client_is_using = false;
   for (auto& context : web_context_registrations_) {
     // When a service worker client is controlled by a service worker, it is
@@ -1179,7 +1338,7 @@
 }
 
 void ServiceWorkerJobs::TryActivate(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    ServiceWorkerRegistrationObject* registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::TryActivate()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Try Activate:
@@ -1218,7 +1377,7 @@
 }
 
 void ServiceWorkerJobs::Activate(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    ServiceWorkerRegistrationObject* registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::Activate()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Activate:
@@ -1262,7 +1421,7 @@
   // 7. For each client of matchedClients, queue a task on client’s  responsible
   //    event loop, using the DOM manipulation task source, to run the following
   //    substeps:
-  for (auto& context : matched_clients) {
+  for (auto& client : matched_clients) {
     // 7.1. Let readyPromise be client’s global object's
     //      ServiceWorkerContainer object’s ready
     //      promise.
@@ -1272,14 +1431,14 @@
     //      the service worker registration object that
     //      represents registration in readyPromise’s
     //      relevant settings object.
-    context->message_loop()->task_runner()->PostTask(
+    client->message_loop()->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ServiceWorkerContainer::MaybeResolveReadyPromise,
-                       base::Unretained(context->GetWindowOrWorkerGlobalScope()
+                       base::Unretained(client->GetWindowOrWorkerGlobalScope()
                                             ->navigator_base()
                                             ->service_worker()
                                             .get()),
-                       registration));
+                       base::Unretained(registration)));
   }
   // 8. For each client of matchedClients:
   // 8.1. If client is a window client, unassociate client’s responsible
@@ -1289,16 +1448,25 @@
   // Cobalt doesn't implement 'application cache':
   //   https://www.w3.org/TR/2011/WD-html5-20110525/offline.html#applicationcache
   // 9. For each service worker client client who is using registration:
-  for (auto& context : web_context_registrations_) {
-    web::EnvironmentSettings* client = context->environment_settings();
+  // Note: The spec defines "control" and "use" of a service worker from the
+  // value of the active service worker property of the client environment, but
+  // that property is set here, so here we should not use that exact definition
+  // to determine if the client is using this registration. Instead, we use the
+  // Match Service Worker Registration algorithm to find the registration for a
+  // client and compare it with the registration being activated.
+  //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-use
+  for (const auto& client : web_context_registrations_) {
+    scoped_refptr<ServiceWorkerRegistrationObject> client_registration =
+        scope_to_registration_map_->MatchServiceWorkerRegistration(
+            client->environment_settings()->ObtainStorageKey(),
+            client->environment_settings()->creation_url());
     // When a service worker client is controlled by a service worker, it is
     // said that the service worker client is using the service worker’s
     // containing service worker registration.
     //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-control
-    if (context->is_controlled_by(registration->active_worker())) {
+    if (client_registration.get() == registration) {
       // 9.1. Set client’s active worker to registration’s active worker.
-      client->context()->set_active_service_worker(
-          registration->active_worker());
+      client->set_active_service_worker(registration->active_worker());
       // 9.2. Invoke Notify Controller Change algorithm with client as the
       //      argument.
       NotifyControllerChange(client);
@@ -1321,8 +1489,8 @@
                 active_worker->worker_global_scope()
                     ->environment_settings()
                     ->context());
-      DCHECK(done_event_.IsSignaled());
-      done_event_.Reset();
+      DCHECK(registration->done_event()->IsSignaled());
+      registration->done_event()->Reset();
       active_worker->web_agent()
           ->context()
           ->message_loop()
@@ -1336,8 +1504,12 @@
                         base::BindOnce([](base::WaitableEvent* done_event,
                                           bool) { done_event->Signal(); },
                                        done_event);
-                    scoped_refptr<ExtendableEvent> event(new ExtendableEvent(
-                        base::Tokens::activate(), std::move(done_callback)));
+                    auto* settings = active_worker->web_agent()
+                                         ->context()
+                                         ->environment_settings();
+                    scoped_refptr<ExtendableEvent> event(
+                        new ExtendableEvent(settings, base::Tokens::activate(),
+                                            std::move(done_callback)));
                     // 11.1.1.1. Let e be the result of creating an event with
                     //           ExtendableEvent.
                     // 11.1.1.2. Initialize e’s type attribute to activate.
@@ -1352,7 +1524,7 @@
                       done_event->Signal();
                     }
                   },
-                  base::Unretained(active_worker), &done_event_));
+                  base::Unretained(active_worker), registration->done_event()));
       // 11.1.2. Wait for task to have executed or been discarded.
       // This waiting is done inside PostBlockingTask above.
       // 11.1.3. Wait for the step labeled WaitForAsynchronousExtensions to
@@ -1360,10 +1532,12 @@
       // TODO(b/240164388): Investigate a better approach for combining waiting
       // for the ExtendableEvent while also allowing use of algorithms that run
       // on the same thread from the event handler.
-      while (!done_event_.TimedWait(base::TimeDelta::FromMilliseconds(100))) {
-        base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
-        base::RunLoop().RunUntilIdle();
+      if (!WaitForAsynchronousExtensions(registration)) {
+        // Timeout
+        activated = false;
       }
+    } else {
+      activated = false;
     }
   }
   // 12. Run the Update Worker State algorithm passing registration’s active
@@ -1379,8 +1553,7 @@
   }
 }
 
-void ServiceWorkerJobs::NotifyControllerChange(
-    web::EnvironmentSettings* client) {
+void ServiceWorkerJobs::NotifyControllerChange(web::Context* client) {
   // Algorithm for Notify Controller Change:
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#notify-controller-change-algorithm
   // 1. Assert: client is not null.
@@ -1389,11 +1562,10 @@
   // 2. If client is an environment settings object, queue a task to fire an
   //    event named controllerchange at the ServiceWorkerContainer object that
   //    client is associated with.
-  client->context()->message_loop()->task_runner()->PostTask(
+  client->message_loop()->task_runner()->PostTask(
       FROM_HERE, base::Bind(
-                     [](web::EnvironmentSettings* client) {
-                       client->context()
-                           ->GetWindowOrWorkerGlobalScope()
+                     [](web::Context* client) {
+                       client->GetWindowOrWorkerGlobalScope()
                            ->navigator_base()
                            ->service_worker()
                            ->DispatchEvent(new web::Event(
@@ -1416,7 +1588,7 @@
 }
 
 void ServiceWorkerJobs::ClearRegistration(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    ServiceWorkerRegistrationObject* registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::ClearRegistration()");
   // Algorithm for Clear Registration:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#clear-registration-algorithm
@@ -1470,7 +1642,7 @@
 }
 
 void ServiceWorkerJobs::TryClearRegistration(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    ServiceWorkerRegistrationObject* registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::TryClearRegistration()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Try Clear Registration:
@@ -1505,8 +1677,8 @@
 }
 
 void ServiceWorkerJobs::UpdateRegistrationState(
-    scoped_refptr<ServiceWorkerRegistrationObject> registration,
-    RegistrationState target, scoped_refptr<ServiceWorkerObject> source) {
+    ServiceWorkerRegistrationObject* registration, RegistrationState target,
+    const scoped_refptr<ServiceWorkerObject>& source) {
   TRACE_EVENT2("cobalt::worker", "ServiceWorkerJobs::UpdateRegistrationState()",
                "target", target, "source", source);
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
@@ -1531,8 +1703,7 @@
             FROM_HERE,
             base::BindOnce(
                 [](web::Context* context,
-                   scoped_refptr<ServiceWorkerRegistrationObject>
-                       registration) {
+                   ServiceWorkerRegistrationObject* registration) {
                   // 2.2.1. ... set the installing attribute of
                   //        registrationObject to null if registration’s
                   //        installing worker is null, or the result of getting
@@ -1547,7 +1718,7 @@
                             registration->installing_worker()));
                   }
                 },
-                context, registration));
+                context, base::Unretained(registration)));
       }
       break;
     }
@@ -1562,8 +1733,7 @@
             FROM_HERE,
             base::BindOnce(
                 [](web::Context* context,
-                   scoped_refptr<ServiceWorkerRegistrationObject>
-                       registration) {
+                   ServiceWorkerRegistrationObject* registration) {
                   // 3.2.1. ... set the waiting attribute of registrationObject
                   //        to null if registration’s waiting worker is null, or
                   //        the result of getting the service worker object that
@@ -1576,7 +1746,7 @@
                         registration->waiting_worker()));
                   }
                 },
-                context, registration));
+                context, base::Unretained(registration)));
       }
       break;
     }
@@ -1591,8 +1761,7 @@
             FROM_HERE,
             base::BindOnce(
                 [](web::Context* context,
-                   scoped_refptr<ServiceWorkerRegistrationObject>
-                       registration) {
+                   ServiceWorkerRegistrationObject* registration) {
                   // 4.2.1. ... set the active attribute of registrationObject
                   //        to null if registration’s active worker is null, or
                   //        the result of getting the service worker object that
@@ -1605,7 +1774,7 @@
                         registration->active_worker()));
                   }
                 },
-                context, registration));
+                context, base::Unretained(registration)));
       }
       break;
     }
@@ -1670,8 +1839,7 @@
   }
 }
 
-void ServiceWorkerJobs::HandleServiceWorkerClientUnload(
-    web::EnvironmentSettings* client) {
+void ServiceWorkerJobs::HandleServiceWorkerClientUnload(web::Context* client) {
   TRACE_EVENT0("cobalt::worker",
                "ServiceWorkerJobs::HandleServiceWorkerClientUnload()");
   // Algorithm for Handle Servicer Worker Client Unload:
@@ -1682,8 +1850,7 @@
 
   // 2. Let registration be the service worker registration used by client.
   // 3. If registration is null, abort these steps.
-  ServiceWorkerObject* active_service_worker =
-      client->context()->active_service_worker();
+  ServiceWorkerObject* active_service_worker = client->active_service_worker();
   if (!active_service_worker) return;
   ServiceWorkerRegistrationObject* registration =
       active_service_worker->containing_service_worker_registration();
@@ -1693,12 +1860,13 @@
   //    steps.
   // Ensure the client is already removed from the registrations when this runs.
   DCHECK(web_context_registrations_.end() ==
-         web_context_registrations_.find(client->context()));
+         web_context_registrations_.find(client));
   if (IsAnyClientUsingRegistration(registration)) return;
 
   // 5. If registration is unregistered, invoke Try Clear Registration with
   //    registration.
-  if (scope_to_registration_map_->IsUnregistered(registration)) {
+  if (scope_to_registration_map_ &&
+      scope_to_registration_map_->IsUnregistered(registration)) {
     TryClearRegistration(registration);
   }
 
@@ -1754,7 +1922,9 @@
   }
 
   // 1.5. Abort the script currently running in serviceWorker.
-  if (worker->is_running()) worker->Abort();
+  if (worker->is_running()) {
+    worker->Abort();
+  }
 
   // 1.6. Set serviceWorker’s start status to null.
   worker->set_start_status(nullptr);
@@ -1766,14 +1936,17 @@
   // Algorithm for Unregister:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#unregister-algorithm
   // 1. If the origin of job’s scope url is not job’s client's origin, then:
-  if (!url::Origin::Create(GURL(job->client->GetOrigin().SerializedOrigin()))
+  if (job->client &&
+      !url::Origin::Create(GURL(job->client->environment_settings()
+                                    ->GetOrigin()
+                                    .SerializedOrigin()))
            .IsSameOriginWith(url::Origin::Create(job->scope_url))) {
     // 1.1. Invoke Reject Job Promise with job and "SecurityError" DOMException.
     RejectJobPromise(
         job,
-        PromiseErrorData(
-            web::DOMException::kSecurityErr,
-            "Service Worker Unregister failed: Scope origin does not match."));
+        PromiseErrorData(web::DOMException::kSecurityErr,
+                         ServiceWorkerConsts::
+                             kServiceWorkerUnregisterScopeOriginNotSameError));
 
     // 1.2. Invoke Finish Job with job and abort these steps.
     FinishJob(job);
@@ -1817,94 +1990,84 @@
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Reject Job Promise:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#reject-job-promise
+  base::AutoLock lock(job->equivalent_jobs_promise_mutex);
   // 1. If job’s client is not null, queue a task, on job’s client's responsible
   //    event loop using the DOM manipulation task source, to reject job’s job
   //    promise with a new exception with errorData and a user agent-defined
   //    message, in job’s client's Realm.
-
-  auto reject_task = [](std::unique_ptr<JobPromiseType> promise,
-                        const PromiseErrorData& error_data) {
-    error_data.Reject(std::move(promise));
-  };
-
-  if (job->client) {
-    base::AutoLock lock(job->equivalent_jobs_promise_mutex);
-    job->client->context()->message_loop()->task_runner()->PostTask(
-        FROM_HERE,
-        base::BindOnce(reject_task, std::move(job->promise), error_data));
+  // 2.1. If equivalentJob’s client is null, continue.
+  // 2.2. Queue a task, on equivalentJob’s client's responsible event loop
+  //      using the DOM manipulation task source, to reject equivalentJob’s
+  //      job promise with a new exception with errorData and a user
+  //      agent-defined message, in equivalentJob’s client's Realm.
+  if (job->client && job->promise != nullptr) {
+    DCHECK(IsWebContextRegistered(job->client));
+    job->client->message_loop()->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(
+                       [](std::unique_ptr<JobPromiseType> promise,
+                          const PromiseErrorData& error_data) {
+                         error_data.Reject(std::move(promise));
+                       },
+                       std::move(job->promise), error_data));
     // Ensure that the promise is cleared, so that equivalent jobs won't get
     // added from this point on.
     CHECK(!job->promise);
   }
   // 2. For each equivalentJob in job’s list of equivalent jobs:
   for (auto& equivalent_job : job->equivalent_jobs) {
-    // Equivalent jobs should never have equivalent jobs of their own.
-    DCHECK(equivalent_job->equivalent_jobs.empty());
-
-    // 2.1. If equivalentJob’s client is null, continue.
-    if (equivalent_job->client) {
-      // 2.2. Queue a task, on equivalentJob’s client's responsible event loop
-      //      using the DOM manipulation task source, to reject equivalentJob’s
-      //      job promise with a new exception with errorData and a user
-      //      agent-defined message, in equivalentJob’s client's Realm.
-      equivalent_job->client->context()
-          ->message_loop()
-          ->task_runner()
-          ->PostTask(
-              FROM_HERE,
-              base::BindOnce(reject_task, std::move(equivalent_job->promise),
-                             error_data));
-      // Check that the promise is cleared.
-      CHECK(!equivalent_job->promise);
-    }
+    // Recurse for the equivalent jobs.
+    RejectJobPromise(equivalent_job.get(), error_data);
   }
   job->equivalent_jobs.clear();
 }
 
 void ServiceWorkerJobs::ResolveJobPromise(
     Job* job, bool value,
-    scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+    const scoped_refptr<ServiceWorkerRegistrationObject>& registration) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::ResolveJobPromise()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   DCHECK(job);
   // Algorithm for Resolve Job Promise:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#resolve-job-promise-algorithm
-
+  base::AutoLock lock(job->equivalent_jobs_promise_mutex);
   // 1. If job’s client is not null, queue a task, on job’s client's responsible
   //    event loop using the DOM manipulation task source, to run the following
   //    substeps:
-  auto resolve_task =
-      [](JobType type, web::EnvironmentSettings* client,
-         std::unique_ptr<JobPromiseType> promise, bool value,
-         scoped_refptr<ServiceWorkerRegistrationObject> registration) {
-        TRACE_EVENT0("cobalt::worker",
-                     "ServiceWorkerJobs::ResolveJobPromise() ResolveTask");
-        // 1.1./2.2.1. Let convertedValue be null.
-        // 1.2./2.2.2. If job’s job type is either register or update, set
-        //             convertedValue to the result of getting the service
-        //             worker registration object that represents value in job’s
-        //             client.
-        if (type == kRegister || type == kUpdate) {
-          scoped_refptr<cobalt::script::Wrappable> converted_value =
-              client->context()->GetServiceWorkerRegistration(registration);
-          // 1.4./2.2.4. Resolve job’s job promise with convertedValue.
-          promise->Resolve(converted_value);
-        } else {
-          DCHECK_EQ(kUnregister, type);
-          // 1.3./2.2.3. Else, set convertedValue to value, in job’s client's
-          //             Realm.
-          bool converted_value = value;
-          // 1.4./2.2.4. Resolve job’s job promise with convertedValue.
-          promise->Resolve(converted_value);
-        }
-      };
-
-  if (job->client) {
-    base::AutoLock lock(job->equivalent_jobs_promise_mutex);
-    job->client->context()->message_loop()->task_runner()->PostTask(
+  // 2.1 If equivalentJob’s client is null, continue to the next iteration of
+  // the loop.
+  if (job->client && job->promise != nullptr) {
+    DCHECK(IsWebContextRegistered(job->client));
+    job->client->message_loop()->task_runner()->PostTask(
         FROM_HERE,
-        base::BindOnce(resolve_task, job->type, job->client,
-                       std::move(job->promise), value, registration));
+        base::BindOnce(
+            [](JobType type, web::Context* client,
+               std::unique_ptr<JobPromiseType> promise, bool value,
+               scoped_refptr<ServiceWorkerRegistrationObject> registration) {
+              TRACE_EVENT0(
+                  "cobalt::worker",
+                  "ServiceWorkerJobs::ResolveJobPromise() ResolveTask");
+              // 1.1./2.2.1. Let convertedValue be null.
+              // 1.2./2.2.2. If job’s job type is either register or update, set
+              //             convertedValue to the result of getting the service
+              //             worker registration object that represents value in
+              //             job’s client.
+              if (type == kRegister || type == kUpdate) {
+                scoped_refptr<cobalt::script::Wrappable> converted_value =
+                    client->GetServiceWorkerRegistration(registration);
+                // 1.4./2.2.4. Resolve job’s job promise with convertedValue.
+                promise->Resolve(converted_value);
+              } else {
+                DCHECK_EQ(kUnregister, type);
+                // 1.3./2.2.3. Else, set convertedValue to value, in job’s
+                // client's
+                //             Realm.
+                bool converted_value = value;
+                // 1.4./2.2.4. Resolve job’s job promise with convertedValue.
+                promise->Resolve(converted_value);
+              }
+            },
+            job->type, job->client, std::move(job->promise), value,
+            registration));
     // Ensure that the promise is cleared, so that equivalent jobs won't get
     // added from this point on.
     CHECK(!job->promise);
@@ -1912,26 +2075,8 @@
 
   // 2. For each equivalentJob in job’s list of equivalent jobs:
   for (auto& equivalent_job : job->equivalent_jobs) {
-    // Equivalent jobs should never have equivalent jobs of their own.
-    DCHECK(equivalent_job->equivalent_jobs.empty());
-
-    // 2.1. If equivalentJob’s client is null, continue to the next iteration of
-    //      the loop.
-    if (equivalent_job->client) {
-      // 2.2. Queue a task, on equivalentJob’s client's responsible event loop
-      //      using the DOM manipulation task source, to run the following
-      //      substeps:
-      equivalent_job->client->context()
-          ->message_loop()
-          ->task_runner()
-          ->PostTask(FROM_HERE,
-                     base::BindOnce(resolve_task, equivalent_job->type,
-                                    equivalent_job->client,
-                                    std::move(equivalent_job->promise), value,
-                                    registration));
-      // Check that the promise is cleared.
-      CHECK(!equivalent_job->promise);
-    }
+    // Recurse for the equivalent jobs.
+    ResolveJobPromise(equivalent_job.get(), value, registration);
   }
   job->equivalent_jobs.clear();
 }
@@ -1955,8 +2100,7 @@
   }
 }
 
-void ServiceWorkerJobs::MaybeResolveReadyPromiseSubSteps(
-    web::EnvironmentSettings* client) {
+void ServiceWorkerJobs::MaybeResolveReadyPromiseSubSteps(web::Context* client) {
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Algorithm for Sub steps of ServiceWorkerContainer.ready():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#navigator-service-worker-ready
@@ -1964,13 +2108,13 @@
   //    3.1. Let client by this's service worker client.
   //    3.2. Let storage key be the result of running obtain a storage
   //         key given client.
-  url::Origin storage_key = client->ObtainStorageKey();
+  url::Origin storage_key = client->environment_settings()->ObtainStorageKey();
   //    3.3. Let registration be the result of running Match Service
   //         Worker Registration given storage key and client’s
   //         creation URL.
   // TODO(b/234659851): Investigate whether this should use the creation URL
   // directly instead.
-  const GURL& base_url = client->creation_url();
+  const GURL& base_url = client->environment_settings()->creation_url();
   GURL client_url = base_url.Resolve("");
   scoped_refptr<ServiceWorkerRegistrationObject> registration =
       scope_to_registration_map_->MatchServiceWorkerRegistration(storage_key,
@@ -1983,11 +2127,10 @@
   //         registration object that represents registration in
   //         readyPromise’s relevant settings object.
   if (registration && registration->active_worker()) {
-    client->context()->message_loop()->task_runner()->PostTask(
+    client->message_loop()->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ServiceWorkerContainer::MaybeResolveReadyPromise,
-                       base::Unretained(client->context()
-                                            ->GetWindowOrWorkerGlobalScope()
+                       base::Unretained(client->GetWindowOrWorkerGlobalScope()
                                             ->navigator_base()
                                             ->service_worker()
                                             .get()),
@@ -1997,7 +2140,7 @@
 
 void ServiceWorkerJobs::GetRegistrationSubSteps(
     const url::Origin& storage_key, const GURL& client_url,
-    web::EnvironmentSettings* client,
+    web::Context* client,
     std::unique_ptr<script::ValuePromiseWrappable::Reference>
         promise_reference) {
   TRACE_EVENT0("cobalt::worker",
@@ -2016,34 +2159,33 @@
   // 8.3. Resolve promise with the result of getting the service worker
   //      registration object that represents registration in promise’s
   //      relevant settings object.
-  client->context()->message_loop()->task_runner()->PostTask(
+  client->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
-          [](web::EnvironmentSettings* settings,
+          [](web::Context* client,
              std::unique_ptr<script::ValuePromiseWrappable::Reference> promise,
              scoped_refptr<ServiceWorkerRegistrationObject> registration) {
             TRACE_EVENT0(
                 "cobalt::worker",
                 "ServiceWorkerJobs::GetRegistrationSubSteps() Resolve");
             promise->value().Resolve(
-                settings->context()->GetServiceWorkerRegistration(
-                    registration));
+                client->GetServiceWorkerRegistration(registration));
           },
           client, std::move(promise_reference), registration));
 }
 
 void ServiceWorkerJobs::GetRegistrationsSubSteps(
-    const url::Origin& storage_key, web::EnvironmentSettings* client,
+    const url::Origin& storage_key, web::Context* client,
     std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
         promise_reference) {
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   std::vector<scoped_refptr<ServiceWorkerRegistrationObject>>
       registration_objects =
           scope_to_registration_map_->GetRegistrations(storage_key);
-  client->context()->message_loop()->task_runner()->PostTask(
+  client->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
-          [](web::EnvironmentSettings* settings,
+          [](web::Context* client,
              std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
                  promise,
              std::vector<scoped_refptr<ServiceWorkerRegistrationObject>>
@@ -2054,8 +2196,7 @@
             script::Sequence<scoped_refptr<script::Wrappable>> registrations;
             for (auto registration_object : registration_objects) {
               registrations.push_back(scoped_refptr<script::Wrappable>(
-                  settings->context()
-                      ->GetServiceWorkerRegistration(registration_object)
+                  client->GetServiceWorkerRegistration(registration_object)
                       .get()));
             }
             promise->value().Resolve(std::move(registrations));
@@ -2065,13 +2206,13 @@
 }
 
 void ServiceWorkerJobs::SkipWaitingSubSteps(
-    web::Context* client_context, ServiceWorkerObject* service_worker,
+    web::Context* worker_context, ServiceWorkerObject* service_worker,
     std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::SkipWaitingSubSteps()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Check if the client web context is still active. This may trigger if
   // skipWaiting() was called and service worker installation fails.
-  if (!IsWebContextRegistered(client_context)) {
+  if (!IsWebContextRegistered(worker_context)) {
     promise_reference.release();
     return;
   }
@@ -2087,7 +2228,7 @@
   TryActivate(service_worker->containing_service_worker_registration());
 
   // 2.3. Resolve promise with undefined.
-  client_context->message_loop()->task_runner()->PostTask(
+  worker_context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](std::unique_ptr<script::ValuePromiseVoid::Reference> promise) {
@@ -2115,7 +2256,7 @@
 }
 
 void ServiceWorkerJobs::ClientsGetSubSteps(
-    web::Context* promise_context,
+    web::Context* worker_context,
     ServiceWorkerObject* associated_service_worker,
     std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference,
     const std::string& id) {
@@ -2123,7 +2264,7 @@
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   // Check if the client web context is still active. This may trigger if
   // Clients.get() was called and service worker installation fails.
-  if (!IsWebContextRegistered(promise_context)) {
+  if (!IsWebContextRegistered(worker_context)) {
     promise_reference.release();
     return;
   }
@@ -2135,12 +2276,12 @@
   const url::Origin& storage_key =
       associated_service_worker->containing_service_worker_registration()
           ->storage_key();
-  for (auto& context : web_context_registrations_) {
-    web::EnvironmentSettings* client = context->environment_settings();
-    url::Origin client_storage_key = client->ObtainStorageKey();
+  for (auto& client : web_context_registrations_) {
+    url::Origin client_storage_key =
+        client->environment_settings()->ObtainStorageKey();
     if (client_storage_key.IsSameOriginWith(storage_key)) {
       // 2.1.1. If client’s id is not id, continue.
-      if (client->id() != id) continue;
+      if (client->environment_settings()->id() != id) continue;
 
       // 2.1.2. Wait for either client’s execution ready flag to be set or for
       //        client’s discarded flag to be set.
@@ -2149,13 +2290,13 @@
 
       // 2.1.3. If client’s execution ready flag is set, then invoke Resolve Get
       //        Client Promise with client and promise, and abort these steps.
-      ResolveGetClientPromise(client, promise_context,
+      ResolveGetClientPromise(client, worker_context,
                               std::move(promise_reference));
       return;
     }
   }
   // 2.2. Resolve promise with undefined.
-  promise_context->message_loop()->task_runner()->PostTask(
+  worker_context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](std::unique_ptr<script::ValuePromiseWrappable::Reference>
@@ -2168,7 +2309,7 @@
 }
 
 void ServiceWorkerJobs::ResolveGetClientPromise(
-    web::EnvironmentSettings* client, web::Context* promise_context,
+    web::Context* client, web::Context* worker_context,
     std::unique_ptr<script::ValuePromiseWrappable::Reference>
         promise_reference) {
   TRACE_EVENT0("cobalt::worker",
@@ -2191,15 +2332,16 @@
 
   // 3. If client is an environment settings object and is not a window client,
   //    then:
-  if (!client->context()->GetWindowOrWorkerGlobalScope()->IsWindow()) {
+  if (!client->GetWindowOrWorkerGlobalScope()->IsWindow()) {
     // 3.1. Let clientObject be the result of running Create Client algorithm
     //      with client as the argument.
-    scoped_refptr<Client> client_object = Client::Create(client);
+    scoped_refptr<Client> client_object =
+        Client::Create(client->environment_settings());
 
     // 3.2. Queue a task to resolve promise with clientObject, on promise’s
     //      relevant settings object's responsible event loop using the DOM
     //      manipulation task source, and abort these steps.
-    promise_context->message_loop()->task_runner()->PostTask(
+    worker_context->message_loop()->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(
             [](std::unique_ptr<script::ValuePromiseWrappable::Reference>
@@ -2226,10 +2368,10 @@
   // functionality in the client context. It is included however to help future
   // implementation for fetching values for WindowClient properties, with
   // similar logic existing in ClientsMatchAllSubSteps.
-  client->context()->message_loop()->task_runner()->PostTask(
+  client->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
-          [](web::EnvironmentSettings* client, web::Context* promise_context,
+          [](web::Context* client, web::Context* worker_context,
              std::unique_ptr<script::ValuePromiseWrappable::Reference>
                  promise_reference) {
             // 4.4.1. Let frameType be the result of running Get Frame Type with
@@ -2241,7 +2383,8 @@
             //        steps with browsingContext’s active document as the
             //        argument.
             // Handled in the WindowData constructor.
-            std::unique_ptr<WindowData> window_data(new WindowData(client));
+            std::unique_ptr<WindowData> window_data(
+                new WindowData(client->environment_settings()));
 
             // 4.4.4. Let ancestorOriginsList be the empty list.
             // 4.4.5. If client is a window client, set ancestorOriginsList to
@@ -2253,7 +2396,7 @@
             // 4.4.6. Queue a task to run the following steps on promise’s
             //        relevant settings object's responsible event loop using
             //        the DOM manipulation task source:
-            promise_context->message_loop()->task_runner()->PostTask(
+            worker_context->message_loop()->task_runner()->PostTask(
                 FROM_HERE,
                 base::BindOnce(
                     [](std::unique_ptr<script::ValuePromiseWrappable::Reference>
@@ -2273,12 +2416,12 @@
                     },
                     std::move(promise_reference), std::move(window_data)));
           },
-          client, promise_context, std::move(promise_reference)));
+          client, worker_context, std::move(promise_reference)));
   DCHECK_EQ(nullptr, promise_reference.get());
 }
 
 void ServiceWorkerJobs::ClientsMatchAllSubSteps(
-    web::Context* client_context,
+    web::Context* worker_context,
     ServiceWorkerObject* associated_service_worker,
     std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
         promise_reference,
@@ -2286,9 +2429,9 @@
   TRACE_EVENT0("cobalt::worker",
                "ServiceWorkerJobs::ClientsMatchAllSubSteps()");
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
-  // Check if the client web context is still active. This may trigger if
+  // Check if the worker web context is still active. This may trigger if
   // Clients.matchAll() was called and service worker installation fails.
-  if (!IsWebContextRegistered(client_context)) {
+  if (!IsWebContextRegistered(worker_context)) {
     promise_reference.release();
     return;
   }
@@ -2296,7 +2439,7 @@
   // Parallel sub steps (2) for algorithm for Clients.matchAll():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#clients-matchall
   // 2.1. Let targetClients be a new list.
-  std::list<web::EnvironmentSettings*> target_clients;
+  std::list<web::Context*> target_clients;
 
   // 2.2. For each service worker client client where the result of running
   //      obtain a storage key given client equals the associated service
@@ -2304,9 +2447,9 @@
   const url::Origin& storage_key =
       associated_service_worker->containing_service_worker_registration()
           ->storage_key();
-  for (auto& context : web_context_registrations_) {
-    web::EnvironmentSettings* client = context->environment_settings();
-    url::Origin client_storage_key = client->ObtainStorageKey();
+  for (auto& client : web_context_registrations_) {
+    url::Origin client_storage_key =
+        client->environment_settings()->ObtainStorageKey();
     if (client_storage_key.IsSameOriginWith(storage_key)) {
       // 2.2.1. If client’s execution ready flag is unset or client’s discarded
       //        flag is set, continue.
@@ -2321,8 +2464,7 @@
       //        active service worker is not the associated service worker,
       //        continue.
       if (!include_uncontrolled &&
-          (client->context()->active_service_worker() !=
-           associated_service_worker)) {
+          (client->active_service_worker() != associated_service_worker)) {
         continue;
       }
 
@@ -2336,12 +2478,12 @@
       new std::vector<WindowData>);
 
   // 2.4. Let matchedClients be a new list.
-  std::unique_ptr<std::vector<web::EnvironmentSettings*>> matched_clients(
-      new std::vector<web::EnvironmentSettings*>);
+  std::unique_ptr<std::vector<web::Context*>> matched_clients(
+      new std::vector<web::Context*>);
 
   // 2.5. For each service worker client client in targetClients:
   for (auto* client : target_clients) {
-    auto* global_scope = client->context()->GetWindowOrWorkerGlobalScope();
+    auto* global_scope = client->GetWindowOrWorkerGlobalScope();
 
     if ((type == kClientTypeWindow || type == kClientTypeAll) &&
         (global_scope->IsWindow())) {
@@ -2350,7 +2492,7 @@
 
       // 2.5.1.1. Let windowData be [ "client" -> client, "ancestorOriginsList"
       //          -> a new list ].
-      WindowData window_data(client);
+      WindowData window_data(client->environment_settings());
 
       // 2.5.1.2. Let browsingContext be null.
 
@@ -2360,9 +2502,8 @@
 
       // 2.5.1.4. If client is an environment settings object, set
       //          browsingContext to client’s global object's browsing context.
-
       // 2.5.1.5. Else, set browsingContext to client’s target browsing context.
-      web::Context* browsing_context = client_context;
+      web::Context* browsing_context = client;
 
       // 2.5.1.6. Queue a task task to run the following substeps on
       //          browsingContext’s event loop using the user interaction task
@@ -2433,14 +2574,13 @@
   // 2.6. Queue a task to run the following steps on promise’s relevant
   // settings object's responsible event loop using the DOM manipulation
   // task source:
-  client_context->message_loop()->task_runner()->PostTask(
+  worker_context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
                  promise_reference,
              std::unique_ptr<std::vector<WindowData>> matched_window_data,
-             std::unique_ptr<std::vector<web::EnvironmentSettings*>>
-                 matched_clients) {
+             std::unique_ptr<std::vector<web::Context*>> matched_clients) {
             TRACE_EVENT0(
                 "cobalt::worker",
                 "ServiceWorkerJobs::ClientsMatchAllSubSteps() Resolve Promise");
@@ -2470,7 +2610,8 @@
               // 2.6.3.1. Let clientObject be the result of running
               //          Create Client algorithm with client as the
               //          argument.
-              scoped_refptr<Client> client_object = Client::Create(client);
+              scoped_refptr<Client> client_object =
+                  Client::Create(client->environment_settings());
 
               // 2.6.3.2. Append clientObject to clientObjects.
               client_objects.push_back(client_object);
@@ -2496,7 +2637,7 @@
 }
 
 void ServiceWorkerJobs::ClaimSubSteps(
-    web::Context* client_context,
+    web::Context* worker_context,
     ServiceWorkerObject* associated_service_worker,
     std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference) {
   TRACE_EVENT0("cobalt::worker", "ServiceWorkerJobs::ClaimSubSteps()");
@@ -2504,14 +2645,14 @@
 
   // Check if the client web context is still active. This may trigger if
   // Clients.claim() was called and service worker installation fails.
-  if (!IsWebContextRegistered(client_context)) {
+  if (!IsWebContextRegistered(worker_context)) {
     promise_reference.release();
     return;
   }
 
   // Parallel sub steps (3) for algorithm for Clients.claim():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dom-clients-claim
-  std::list<web::EnvironmentSettings*> target_clients;
+  std::list<web::Context*> target_clients;
 
   // 3.1. For each service worker client client where the result of running
   //      obtain a storage key given client equals the service worker's
@@ -2519,11 +2660,11 @@
   const url::Origin& storage_key =
       associated_service_worker->containing_service_worker_registration()
           ->storage_key();
-  for (auto& context : web_context_registrations_) {
+  for (auto& client : web_context_registrations_) {
     // Don't claim to be our own service worker.
-    if (context == client_context) continue;
-    web::EnvironmentSettings* client = context->environment_settings();
-    url::Origin client_storage_key = client->ObtainStorageKey();
+    if (client == worker_context) continue;
+    url::Origin client_storage_key =
+        client->environment_settings()->ObtainStorageKey();
     if (client_storage_key.IsSameOriginWith(storage_key)) {
       // 3.1.1. If client’s execution ready flag is unset or client’s discarded
       //        flag is set, continue.
@@ -2540,7 +2681,7 @@
       //        Registration given storage key and client’s creation URL.
       // TODO(b/234659851): Investigate whether this should use the creation
       // URL directly instead.
-      const GURL& base_url = client->creation_url();
+      const GURL& base_url = client->environment_settings()->creation_url();
       GURL client_url = base_url.Resolve("");
       scoped_refptr<ServiceWorkerRegistrationObject> registration =
           scope_to_registration_map_->MatchServiceWorkerRegistration(
@@ -2555,14 +2696,13 @@
 
       // 3.1.6. If client’s active service worker is not the service worker,
       //        then:
-      if (client->context()->active_service_worker() !=
-          associated_service_worker) {
+      if (client->active_service_worker() != associated_service_worker) {
         // 3.1.6.1. Invoke Handle Service Worker Client Unload with client as
         //          the argument.
         HandleServiceWorkerClientUnload(client);
 
         // 3.1.6.2. Set client’s active service worker to service worker.
-        client->context()->set_active_service_worker(associated_service_worker);
+        client->set_active_service_worker(associated_service_worker);
 
         // 3.1.6.3. Invoke Notify Controller Change algorithm with client as the
         //          argument.
@@ -2571,7 +2711,7 @@
     }
   }
   // 3.2. Resolve promise with undefined.
-  client_context->message_loop()->task_runner()->PostTask(
+  worker_context->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](std::unique_ptr<script::ValuePromiseVoid::Reference> promise) {
@@ -2581,8 +2721,7 @@
 }
 
 void ServiceWorkerJobs::ServiceWorkerPostMessageSubSteps(
-    ServiceWorkerObject* service_worker,
-    web::EnvironmentSettings* incumbent_settings,
+    ServiceWorkerObject* service_worker, web::Context* incumbent_client,
     std::unique_ptr<script::DataBuffer> serialize_result) {
   // Parallel sub steps (6) for algorithm for ServiceWorker.postMessage():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#service-worker-postmessage-options
@@ -2596,11 +2735,11 @@
 
   // 6.2 Queue a task on the DOM manipulation task source to run the following
   //     steps:
-  incumbent_settings->context()->message_loop()->task_runner()->PostTask(
+  incumbent_client->message_loop()->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(
           [](ServiceWorkerObject* service_worker,
-             web::EnvironmentSettings* incumbent_settings,
+             web::Context* incumbent_client,
              std::unique_ptr<script::DataBuffer> serialize_result) {
             if (!serialize_result) return;
 
@@ -2609,8 +2748,8 @@
             if (!event_target) return;
 
             web::WindowOrWorkerGlobalScope* incumbent_global =
-                incumbent_settings->context()->GetWindowOrWorkerGlobalScope();
-            DCHECK_EQ(incumbent_settings,
+                incumbent_client->GetWindowOrWorkerGlobalScope();
+            DCHECK_EQ(incumbent_client->environment_settings(),
                       incumbent_global->environment_settings());
             base::TypeId incumbent_type = incumbent_global->GetWrappableType();
             ServiceWorkerObject* incumbent_worker =
@@ -2628,7 +2767,7 @@
                 base::BindOnce(
                     [](const base::TypeId& incumbent_type,
                        ServiceWorkerObject* incumbent_worker,
-                       web::EnvironmentSettings* incumbent_settings,
+                       web::Context* incumbent_client,
                        web::EventTarget* event_target,
                        std::unique_ptr<script::DataBuffer> serialize_result) {
                       ExtendableMessageEventInit init_dict;
@@ -2651,18 +2790,20 @@
                         //          a new WindowClient object that represents
                         //          incumbentGlobal’s relevant settings object.
                         init_dict.set_source(ExtendableMessageEvent::SourceType(
-                            WindowClient::Create(
-                                WindowData(incumbent_settings))));
+                            WindowClient::Create(WindowData(
+                                incumbent_client->environment_settings()))));
                       } else {
                         //        . Otherwise
                         //          a new Client object that represents
                         //          incumbentGlobal’s associated worker
-                        init_dict.set_source(ExtendableMessageEvent::SourceType(
-                            Client::Create(incumbent_settings)));
+                        init_dict.set_source(
+                            ExtendableMessageEvent::SourceType(Client::Create(
+                                incumbent_client->environment_settings())));
                       }
 
                       event_target->DispatchEvent(
                           new worker::ExtendableMessageEvent(
+                              event_target->environment_settings(),
                               base::Tokens::message(), init_dict,
                               std::move(serialize_result)));
                     },
@@ -2672,12 +2813,12 @@
                     // processes the event, but since base::WeakPtr
                     // dereferencing isn't thread-safe, that can't actually be
                     // used here.
-                    base::Unretained(incumbent_settings),
+                    base::Unretained(incumbent_client),
                     base::Unretained(event_target),
                     std::move(serialize_result)));
           },
-          base::Unretained(service_worker),
-          base::Unretained(incumbent_settings), std::move(serialize_result)));
+          base::Unretained(service_worker), base::Unretained(incumbent_client),
+          std::move(serialize_result)));
 }
 
 void ServiceWorkerJobs::RegisterWebContext(web::Context* context) {
@@ -2695,6 +2836,27 @@
   web_context_registrations_.insert(context);
 }
 
+void ServiceWorkerJobs::SetActiveWorker(web::EnvironmentSettings* client) {
+  if (!client) return;
+  if (base::MessageLoop::current() != message_loop()) {
+    DCHECK(message_loop());
+    message_loop()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ServiceWorkerJobs::SetActiveWorker,
+                              base::Unretained(this), client));
+    return;
+  }
+  DCHECK(scope_to_registration_map_);
+  scoped_refptr<ServiceWorkerRegistrationObject> client_registration =
+      scope_to_registration_map_->MatchServiceWorkerRegistration(
+          client->ObtainStorageKey(), client->creation_url());
+  if (client_registration.get() && client_registration->active_worker()) {
+    client->context()->set_active_service_worker(
+        client_registration->active_worker());
+  } else {
+    client->context()->set_active_service_worker(nullptr);
+  }
+}
+
 void ServiceWorkerJobs::UnregisterWebContext(web::Context* context) {
   DCHECK_NE(nullptr, context);
   if (base::MessageLoop::current() != message_loop()) {
@@ -2708,12 +2870,49 @@
   DCHECK_EQ(message_loop(), base::MessageLoop::current());
   DCHECK_EQ(1, web_context_registrations_.count(context));
   web_context_registrations_.erase(context);
-  HandleServiceWorkerClientUnload(context->environment_settings());
+  HandleServiceWorkerClientUnload(context);
+  PrepareForClientShutdown(context);
   if (web_context_registrations_.empty()) {
     web_context_registrations_cleared_.Signal();
   }
 }
 
+void ServiceWorkerJobs::PrepareForClientShutdown(web::Context* client) {
+  DCHECK(client);
+  if (!client) return;
+  DCHECK(base::MessageLoop::current() == message_loop());
+  // Note: This could be rewritten to use the decomposition declaration
+  // 'const auto& [scope, queue]' after switching to C++17.
+  for (const auto& entry : job_queue_map_) {
+    const std::string& scope = entry.first;
+    const std::unique_ptr<JobQueue>& queue = entry.second;
+    DCHECK(queue.get());
+    queue->PrepareForClientShutdown(client);
+  }
+}
+
+void ServiceWorkerJobs::JobQueue::PrepareForClientShutdown(
+    web::Context* client) {
+  for (const auto& job : jobs_) {
+    PrepareJobForClientShutdown(job, client);
+  }
+}
+
+void ServiceWorkerJobs::JobQueue::PrepareJobForClientShutdown(
+    const std::unique_ptr<Job>& job, web::Context* client) {
+  DCHECK(job);
+  if (!job) return;
+  base::AutoLock lock(job->equivalent_jobs_promise_mutex);
+  if (client == job->client) {
+    job->promise.reset();
+    job->client = nullptr;
+  }
+  for (const auto& equivalent_job : job->equivalent_jobs) {
+    // Recurse for the equivalent jobs.
+    PrepareJobForClientShutdown(equivalent_job, client);
+  }
+}
+
 ServiceWorkerJobs::JobPromiseType::JobPromiseType(
     std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference)
     : promise_bool_reference_(std::move(promise_reference)) {}
diff --git a/cobalt/worker/service_worker_jobs.h b/cobalt/worker/service_worker_jobs.h
index 9245421..1b18ff4 100644
--- a/cobalt/worker/service_worker_jobs.h
+++ b/cobalt/worker/service_worker_jobs.h
@@ -18,7 +18,6 @@
 #include <deque>
 #include <map>
 #include <memory>
-#include <queue>
 #include <set>
 #include <string>
 #include <utility>
@@ -37,8 +36,8 @@
 #include "cobalt/script/promise.h"
 #include "cobalt/script/script_value.h"
 #include "cobalt/script/script_value_factory.h"
+#include "cobalt/web/context.h"
 #include "cobalt/web/dom_exception.h"
-#include "cobalt/web/environment_settings.h"
 #include "cobalt/web/web_settings.h"
 #include "cobalt/worker/client_query_options.h"
 #include "cobalt/worker/frame_type.h"
@@ -102,7 +101,7 @@
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-job
   struct Job {
     Job(JobType type, const url::Origin& storage_key, const GURL& scope_url,
-        const GURL& script_url, web::EnvironmentSettings* client,
+        const GURL& script_url, web::Context* client,
         std::unique_ptr<JobPromiseType> promise)
         : type(type),
           storage_key(storage_key),
@@ -124,12 +123,13 @@
     GURL scope_url;
     GURL script_url;
     ServiceWorkerUpdateViaCache update_via_cache;
-    web::EnvironmentSettings* client;
+    web::Context* client;
     GURL referrer;
     std::unique_ptr<JobPromiseType> promise;
     JobQueue* containing_job_queue = nullptr;
     std::deque<std::unique_ptr<Job>> equivalent_jobs;
     bool force_bypass_cache_flag = false;
+    bool no_promise_okay = false;
 
     // Custom, not in the spec.
     //
@@ -151,13 +151,13 @@
     }
     void Enqueue(std::unique_ptr<Job> job) {
       base::AutoLock lock(mutex_);
-      jobs_.push(std::move(job));
+      jobs_.push_back(std::move(job));
     }
     std::unique_ptr<Job> Dequeue() {
       base::AutoLock lock(mutex_);
       std::unique_ptr<Job> job;
       job.swap(jobs_.front());
-      jobs_.pop();
+      jobs_.pop_front();
       return job;
     }
     Job* FirstItem() {
@@ -174,19 +174,26 @@
           job, std::move(lock));
     }
 
+    // Ensure no references are kept to JS objects for a client that is about to
+    // be shutdown.
+    void PrepareForClientShutdown(web::Context* client);
+
+    // Helper method for PrepareForClientShutdown to help with recursion to
+    // equivalent jobs.
+    void PrepareJobForClientShutdown(const std::unique_ptr<Job>& job,
+                                     web::Context* client);
+
    private:
     base::Lock mutex_;
-    std::queue<std::unique_ptr<Job>> jobs_;
+    std::deque<std::unique_ptr<Job>> jobs_;
   };
 
   ServiceWorkerJobs(web::WebSettings* web_settings,
                     network::NetworkModule* network_module,
                     web::UserAgentPlatformInfo* platform_info,
-                    base::MessageLoop* message_loop);
+                    base::MessageLoop* message_loop, const GURL& url);
   ~ServiceWorkerJobs();
 
-  void Stop();
-
   base::MessageLoop* message_loop() { return message_loop_; }
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#start-register-algorithm
@@ -194,28 +201,28 @@
                      const GURL& script_url,
                      std::unique_ptr<script::ValuePromiseWrappable::Reference>
                          promise_reference,
-                     web::EnvironmentSettings* client, const WorkerType& type,
+                     web::Context* client, const WorkerType& type,
                      const ServiceWorkerUpdateViaCache& update_via_cache);
 
-  void MaybeResolveReadyPromiseSubSteps(web::EnvironmentSettings* client);
+  void MaybeResolveReadyPromiseSubSteps(web::Context* client);
 
   // Sub steps (8) of ServiceWorkerContainer.getRegistration().
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#navigator-service-worker-getRegistration
   void GetRegistrationSubSteps(
       const url::Origin& storage_key, const GURL& client_url,
-      web::EnvironmentSettings* client,
+      web::Context* client,
       std::unique_ptr<script::ValuePromiseWrappable::Reference>
           promise_reference);
 
   void GetRegistrationsSubSteps(
-      const url::Origin& storage_key, web::EnvironmentSettings* client,
+      const url::Origin& storage_key, web::Context* client,
       std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
           promise_reference);
 
   // Sub steps (2) of ServiceWorkerGlobalScope.skipWaiting().
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dom-serviceworkerglobalscope-skipwaiting
   void SkipWaitingSubSteps(
-      web::Context* client_context, ServiceWorkerObject* service_worker,
+      web::Context* worker_context, ServiceWorkerObject* service_worker,
       std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference);
 
   // Sub steps for ExtendableEvent.WaitUntil().
@@ -225,7 +232,7 @@
   // Parallel sub steps (2) for algorithm for Clients.get(id):
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#clients-get
   void ClientsGetSubSteps(
-      web::Context* client_context,
+      web::Context* worker_context,
       ServiceWorkerObject* associated_service_worker,
       std::unique_ptr<script::ValuePromiseWrappable::Reference>
           promise_reference,
@@ -234,14 +241,14 @@
   // Algorithm for Resolve Get Client Promise:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#resolve-get-client-promise
   void ResolveGetClientPromise(
-      web::EnvironmentSettings* client, web::Context* promise_context,
+      web::Context* client, web::Context* worker_context,
       std::unique_ptr<script::ValuePromiseWrappable::Reference>
           promise_reference);
 
   // Parallel sub steps (2) for algorithm for Clients.matchAll():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#clients-matchall
   void ClientsMatchAllSubSteps(
-      web::Context* client_context,
+      web::Context* worker_context,
       ServiceWorkerObject* associated_service_worker,
       std::unique_ptr<script::ValuePromiseSequenceWrappable::Reference>
           promise_reference,
@@ -250,31 +257,38 @@
   // Parallel sub steps (3) for algorithm for Clients.claim():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dom-clients-claim
   void ClaimSubSteps(
-      web::Context* client_context,
+      web::Context* worker_context,
       ServiceWorkerObject* associated_service_worker,
       std::unique_ptr<script::ValuePromiseVoid::Reference> promise_reference);
 
   // Parallel sub steps (6) for algorithm for ServiceWorker.postMessage():
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#service-worker-postmessage-options
   void ServiceWorkerPostMessageSubSteps(
-      ServiceWorkerObject* service_worker,
-      web::EnvironmentSettings* incumbent_settings,
+      ServiceWorkerObject* service_worker, web::Context* incumbent_client,
       std::unique_ptr<script::DataBuffer> serialize_result);
 
   // Registration of web contexts that may have service workers.
   void RegisterWebContext(web::Context* context);
   void UnregisterWebContext(web::Context* context);
   bool IsWebContextRegistered(web::Context* context) {
+    DCHECK(base::MessageLoop::current() == message_loop());
     return web_context_registrations_.end() !=
            web_context_registrations_.find(context);
   }
 
+  // Ensure no references are kept to JS objects for a client that is about to
+  // be shutdown.
+  void PrepareForClientShutdown(web::Context* client);
+
+  // Set the active worker for a client if there is a matching service worker.
+  void SetActiveWorker(web::EnvironmentSettings* client);
+
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#create-job
   std::unique_ptr<Job> CreateJob(
       JobType type, const url::Origin& storage_key, const GURL& scope_url,
       const GURL& script_url,
       std::unique_ptr<script::ValuePromiseWrappable::Reference> promise,
-      web::EnvironmentSettings* client) {
+      web::Context* client) {
     return CreateJob(type, storage_key, scope_url, script_url,
                      JobPromiseType::Create(std::move(promise)), client);
   }
@@ -282,31 +296,48 @@
       JobType type, const url::Origin& storage_key, const GURL& scope_url,
       const GURL& script_url,
       std::unique_ptr<script::ValuePromiseBool::Reference> promise,
-      web::EnvironmentSettings* client) {
+      web::Context* client) {
     return CreateJob(type, storage_key, scope_url, script_url,
                      JobPromiseType::Create(std::move(promise)), client);
   }
-  std::unique_ptr<Job> CreateJob(JobType type, const url::Origin& storage_key,
-                                 const GURL& scope_url, const GURL& script_url,
-                                 std::unique_ptr<JobPromiseType> promise,
-                                 web::EnvironmentSettings* client);
+  std::unique_ptr<Job> CreateJobWithoutPromise(JobType type,
+                                               const url::Origin& storage_key,
+                                               const GURL& scope_url,
+                                               const GURL& script_url) {
+    auto job = CreateJob(type, storage_key, scope_url, script_url,
+                         std::unique_ptr<JobPromiseType>(), /*client=*/nullptr);
+    job->no_promise_okay = true;
+    return job;
+  }
+  std::unique_ptr<Job> CreateJob(
+      JobType type, const url::Origin& storage_key, const GURL& scope_url,
+      const GURL& script_url, std::unique_ptr<JobPromiseType> promise = nullptr,
+      web::Context* client = nullptr);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#schedule-job
   void ScheduleJob(std::unique_ptr<Job> job);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#activation-algorithm
-  void Activate(scoped_refptr<ServiceWorkerRegistrationObject> registration);
+  void Activate(ServiceWorkerRegistrationObject* registration);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#clear-registration-algorithm
-  void ClearRegistration(
-      scoped_refptr<ServiceWorkerRegistrationObject> registration);
+  void ClearRegistration(ServiceWorkerRegistrationObject* registration);
+
+  // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#soft-update
+  void SoftUpdate(ServiceWorkerRegistrationObject* registration,
+                  bool force_bypass_cache);
+
+  void EnsureServiceWorkerStarted(const url::Origin& storage_key,
+                                  const GURL& client_url,
+                                  base::WaitableEvent* done_event);
 
  private:
   // State used for the 'Update' algorithm.
   struct UpdateJobState : public base::RefCounted<UpdateJobState> {
-    UpdateJobState(Job* job,
-                   scoped_refptr<ServiceWorkerRegistrationObject> registration,
-                   ServiceWorkerObject* newest_worker)
+    UpdateJobState(
+        Job* job,
+        const scoped_refptr<ServiceWorkerRegistrationObject>& registration,
+        ServiceWorkerObject* newest_worker)
         : job(job), registration(registration), newest_worker(newest_worker) {}
     Job* job;
     scoped_refptr<ServiceWorkerRegistrationObject> registration;
@@ -351,7 +382,7 @@
   enum RegistrationState { kInstalling, kWaiting, kActive };
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-job-equivalent
-  bool EquivalentJobs(Job* one, Job* two);
+  bool ReturnJobsAreEquivalent(Job* one, Job* two);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#run-job-algorithm
   void RunJob(JobQueue* job_queue);
@@ -378,7 +409,6 @@
                                 scoped_refptr<ServiceWorkerObject> worker,
                                 bool run_result);
 
-
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#unregister-algorithm
   void Unregister(Job* job);
 
@@ -386,21 +416,17 @@
   void RejectJobPromise(Job* job, const PromiseErrorData& error_data);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#resolve-job-promise-algorithm
-  void ResolveJobPromise(Job* job,
-                         scoped_refptr<ServiceWorkerRegistrationObject> value) {
+  void ResolveJobPromise(
+      Job* job, const scoped_refptr<ServiceWorkerRegistrationObject>& value) {
     ResolveJobPromise(job, false, value);
   }
-  void ResolveJobPromise(
-      Job* job, bool value,
-      scoped_refptr<ServiceWorkerRegistrationObject> registration = nullptr);
+  void ResolveJobPromise(Job* job, bool value,
+                         const scoped_refptr<ServiceWorkerRegistrationObject>&
+                             registration = nullptr);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#finish-job-algorithm
   void FinishJob(Job* job);
 
-  // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#get-newest-worker
-  ServiceWorker* GetNewestWorker(
-      scoped_refptr<ServiceWorkerRegistrationObject> registration);
-
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#run-service-worker-algorithm
   // The return value is a 'Completion or failure'.
   // A failure is signaled by returning nullptr. Otherwise, the returned string
@@ -410,38 +436,42 @@
                                 bool force_bypass_cache = false);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#installation-algorithm
-  void Install(Job* job, scoped_refptr<ServiceWorkerObject> worker,
-               scoped_refptr<ServiceWorkerRegistrationObject> registration);
+  void Install(
+      Job* job, const scoped_refptr<ServiceWorkerObject>& worker,
+      const scoped_refptr<ServiceWorkerRegistrationObject>& registration);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#try-activate-algorithm
-  void TryActivate(scoped_refptr<ServiceWorkerRegistrationObject> registration);
+  void TryActivate(ServiceWorkerRegistrationObject* registration);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#service-worker-has-no-pending-events
   bool ServiceWorkerHasNoPendingEvents(ServiceWorkerObject* worker);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#update-registration-state-algorithm
   void UpdateRegistrationState(
-      scoped_refptr<ServiceWorkerRegistrationObject> registration,
-      RegistrationState target, scoped_refptr<ServiceWorkerObject> source);
+      ServiceWorkerRegistrationObject* registration, RegistrationState target,
+      const scoped_refptr<ServiceWorkerObject>& source);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#update-state-algorithm
   void UpdateWorkerState(ServiceWorkerObject* worker, ServiceWorkerState state);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#on-client-unload-algorithm
-  void HandleServiceWorkerClientUnload(web::EnvironmentSettings* client);
+  void HandleServiceWorkerClientUnload(web::Context* client);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#terminate-service-worker
   void TerminateServiceWorker(ServiceWorkerObject* worker);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#notify-controller-change-algorithm
-  void NotifyControllerChange(web::EnvironmentSettings* client);
+  void NotifyControllerChange(web::Context* client);
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#try-clear-registration-algorithm
-  void TryClearRegistration(
-      scoped_refptr<ServiceWorkerRegistrationObject> registration);
+  void TryClearRegistration(ServiceWorkerRegistrationObject* registration);
 
   bool IsAnyClientUsingRegistration(
-      scoped_refptr<ServiceWorkerRegistrationObject> registration);
+      ServiceWorkerRegistrationObject* registration);
+
+  // Returns false when the timeout is reached.
+  bool WaitForAsynchronousExtensions(
+      const scoped_refptr<ServiceWorkerRegistrationObject>& registration);
 
   // FetcherFactory that is used to create a fetcher according to URL.
   std::unique_ptr<loader::FetcherFactory> fetcher_factory_;
@@ -457,10 +487,6 @@
   base::WaitableEvent web_context_registrations_cleared_ = {
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED};
-
-  base::WaitableEvent done_event_ = {
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::SIGNALED};
 };
 
 }  // namespace worker
diff --git a/cobalt/worker/service_worker_object.cc b/cobalt/worker/service_worker_object.cc
index 7981e68..b16feb6 100644
--- a/cobalt/worker/service_worker_object.cc
+++ b/cobalt/worker/service_worker_object.cc
@@ -54,10 +54,13 @@
   if (web_agent_) {
     DCHECK(message_loop());
     DCHECK(web_context_);
-    web_agent_->WaitUntilDone();
-    web_agent_->Stop();
-    web_agent_.reset();
+    std::unique_ptr<web::Agent> web_agent(std::move(web_agent_));
+    DCHECK(web_agent);
+    DCHECK(!web_agent_);
+    web_agent->WaitUntilDone();
     web_context_ = nullptr;
+    web_agent->Stop();
+    web_agent.reset();
   }
 }
 
@@ -94,6 +97,14 @@
   return entry != script_resource_map_.end() ? &entry->second : nullptr;
 }
 
+void ServiceWorkerObject::SetScriptResourceHasEverBeenEvaluated(
+    const GURL& url) {
+  auto entry = script_resource_map_.find(url);
+  if (entry != script_resource_map_.end()) {
+    entry->second.has_ever_been_evaluated = true;
+  }
+}
+
 void ServiceWorkerObject::PurgeScriptResourceMap() {
   // Steps 13-15 of Algorithm for Install:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#installation-algorithm
@@ -136,9 +147,10 @@
 bool ServiceWorkerObject::ShouldSkipEvent(base::Token event_name) {
   // Algorithm for Should Skip Event:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#should-skip-event-algorithm
-  // TODO(b/229622132): Implementing this algorithm will improve performance.
-  NOTIMPLEMENTED();
-  return false;
+  // 1. If serviceWorker’s set of event types to handle does not contain
+  // eventName, then the user agent may return true.
+  return (set_of_event_types_to_handle_.find(event_name) ==
+          set_of_event_types_to_handle_.end());
 }
 
 void ServiceWorkerObject::Initialize(web::Context* context) {
@@ -177,10 +189,11 @@
   //      origin to an implementation-defined value, target browsing context to
   //      null, and active service worker to null.
 
-  web_context_->setup_environment_settings(worker_settings);
+  web_context_->SetupEnvironmentSettings(worker_settings);
   web_context_->environment_settings()->set_creation_url(script_url_);
   scoped_refptr<ServiceWorkerGlobalScope> service_worker_global_scope =
-      new ServiceWorkerGlobalScope(web_context_->environment_settings(), this);
+      new ServiceWorkerGlobalScope(web_context_->environment_settings(),
+                                   options_.global_scope_options, this);
   worker_global_scope_ = service_worker_global_scope;
   web_context_->global_environment()->CreateGlobalObject(
       service_worker_global_scope, web_context_->environment_settings());
@@ -223,6 +236,7 @@
     DLOG(WARNING) << "Warning: No Content Security Header received for the "
                      "service worker.";
   }
+  web_context_->SetupFinished();
   // 8.11. If serviceWorker is an active worker, and there are any tasks queued
   //       in serviceWorker’s containing service worker registration’s task
   //       queues, queue them to serviceWorker’s event loop’s task queues in the
@@ -263,11 +277,32 @@
   // 8.16. Set serviceWorker’s start status to evaluationStatus.
   start_status_.reset(new std::string(retval));
   // 8.17. If script’s has ever been evaluated flag is unset, then:
-  // 8.17.1. For each eventType of settingsObject’s global object's associated
-  //         list of event listeners' event types:
-  // 8.17.1.1. Append eventType to workerGlobalScope’s associated service
-  //           worker's set of event types to handle.
-  // 8.17.1.2. Set script’s has ever been evaluated flag.
+  if (!script_resource->has_ever_been_evaluated) {
+    // 8.17.1. For each eventType of settingsObject’s global object's associated
+    //         list of event listeners' event types:
+    auto event_types =
+        service_worker_global_scope->event_listener_event_types();
+    for (auto& event_type : event_types) {
+      // 8.17.1.1. Append eventType to workerGlobalScope’s associated service
+      //           worker's set of event types to handle.
+      service_worker_global_scope->service_worker_object()
+          ->set_of_event_types_to_handle()
+          .insert(event_type);
+    }
+    // 8.17.2. Set script’s has ever been evaluated flag.
+    SetScriptResourceHasEverBeenEvaluated(script_url_);
+
+    if (event_types.empty()) {
+      // NOTE: If the global object’s associated list of event listeners does
+      // not have any event listener added at this moment, the service worker’s
+      // set of event types to handle remains an empty set. The user agents are
+      // encouraged to show a warning that the event listeners must be added on
+      // the very first evaluation of the worker script.
+      DLOG(WARNING) << "ServiceWorkerGlobalScope's event listeners must be "
+                       "added on the first evaluation of the worker script.";
+    }
+    event_types.clear();
+  }
   // 8.18. Run the responsible event loop specified by settingsObject until it
   //       is destroyed.
   // 8.19. Empty workerGlobalScope’s list of active timers.
diff --git a/cobalt/worker/service_worker_object.h b/cobalt/worker/service_worker_object.h
index dfa4117..21094cf 100644
--- a/cobalt/worker/service_worker_object.h
+++ b/cobalt/worker/service_worker_object.h
@@ -57,10 +57,10 @@
  public:
   // Worker Options needed at thread run time.
   struct Options {
-    Options(
-        const std::string& name, web::WebSettings* web_settings,
-        network::NetworkModule* network_module,
-        ServiceWorkerRegistrationObject* containing_service_worker_registration)
+    Options(const std::string& name, web::WebSettings* web_settings,
+            network::NetworkModule* network_module,
+            const scoped_refptr<ServiceWorkerRegistrationObject>&
+                containing_service_worker_registration)
         : name(name),
           containing_service_worker_registration(
               containing_service_worker_registration) {
@@ -70,6 +70,7 @@
 
     std::string name;
     web::Agent::Options web_options;
+    web::WindowOrWorkerGlobalScope::Options global_scope_options;
     ServiceWorkerRegistrationObject* containing_service_worker_registration;
   };
 
@@ -101,7 +102,7 @@
   void AppendToSetOfUsedScripts(const GURL& url) {
     set_of_used_scripts_.insert(url);
   }
-  std::set<GURL> set_of_used_scripts() { return set_of_used_scripts_; }
+  std::set<GURL>& set_of_used_scripts() { return set_of_used_scripts_; }
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-script-resource-map
   void set_script_resource_map(ScriptResourceMap&& resource_map) {
@@ -110,6 +111,7 @@
   void SetScriptResource(const GURL& url, std::string* resource);
   bool HasScriptResource() const;
   const ScriptResource* LookupScriptResource(const GURL& url) const;
+  void SetScriptResourceHasEverBeenEvaluated(const GURL& url);
 
   // Steps 13-15 of Algorithm for Install.
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#installation-algorithm
@@ -119,8 +121,8 @@
   }
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#service-worker-start-status
-  void set_start_status(std::string* start_status) {
-    start_status_.reset(start_status);
+  void set_start_status(std::unique_ptr<std::string> start_status) {
+    start_status_.reset(start_status.release());
   }
   std::string* start_status() const { return start_status_.get(); }
 
@@ -146,6 +148,10 @@
 
   std::string options_name() { return options_.name; }
 
+  std::set<base::Token>& set_of_event_types_to_handle() {
+    return set_of_event_types_to_handle_;
+  }
+
  private:
   // Called by ObtainWebAgentAndWaitUntilDone to perform initialization required
   // on the dedicated thread.
@@ -193,6 +199,9 @@
   starboard::atomic_bool start_failed_;
 
   scoped_refptr<WorkerGlobalScope> worker_global_scope_;
+
+  // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-set-of-event-types-to-handle
+  std::set<base::Token> set_of_event_types_to_handle_;
 };
 
 }  // namespace worker
diff --git a/cobalt/worker/service_worker_persistent_settings.cc b/cobalt/worker/service_worker_persistent_settings.cc
index 96be7fa..ba47191 100644
--- a/cobalt/worker/service_worker_persistent_settings.cc
+++ b/cobalt/worker/service_worker_persistent_settings.cc
@@ -29,8 +29,8 @@
 #include "cobalt/script/exception_message.h"
 #include "cobalt/script/promise.h"
 #include "cobalt/script/script_value.h"
-#include "cobalt/web/context.h"
-#include "cobalt/web/environment_settings.h"
+#include "cobalt/web/cache_utils.h"
+#include "cobalt/worker/service_worker_consts.h"
 #include "cobalt/worker/service_worker_jobs.h"
 #include "cobalt/worker/service_worker_registration_object.h"
 #include "cobalt/worker/service_worker_update_via_cache.h"
@@ -45,7 +45,6 @@
 
 namespace {
 // ServiceWorkerRegistrationMap persistent settings keys.
-const char kSettingsJson[] = "service_worker_settings.json";
 const char kSettingsKeyList[] = "key_list";
 
 // ServiceWorkerRegistrationObject persistent settings keys.
@@ -55,16 +54,17 @@
 const char kSettingsUpdateViaCacheModeKey[] = "update_via_cache_mode";
 const char kSettingsWaitingWorkerKey[] = "waiting_worker";
 const char kSettingsActiveWorkerKey[] = "active_worker";
+const char kSettingsLastUpdateCheckTimeKey[] = "last_update_check_time";
 
 // ServicerWorkerObject persistent settings keys.
 const char kSettingsOptionsNameKey[] = "options_name";
-const char kSettingsServiceWorkerStateKey[] = "service_worker_state";
 const char kSettingsScriptUrlKey[] = "script_url";
 const char kSettingsScriptResourceMapScriptUrlsKey[] =
     "script_resource_map_script_urls";
 const char kSettingsSetOfUsedScriptsKey[] = "set_of_used_scripts";
 const char kSettingsSkipWaitingKey[] = "skip_waiting";
 const char kSettingsClassicScriptsImportedKey[] = "classic_scripts_imported";
+const char kSettingsRawHeadersKey[] = "raw_headers";
 
 bool CheckPersistentValue(
     std::string key_string, std::string settings_key,
@@ -86,8 +86,8 @@
 ServiceWorkerPersistentSettings::ServiceWorkerPersistentSettings(
     const Options& options)
     : options_(options) {
-  persistent_settings_.reset(
-      new cobalt::persistent_storage::PersistentSettings(kSettingsJson));
+  persistent_settings_.reset(new cobalt::persistent_storage::PersistentSettings(
+      ServiceWorkerConsts::kSettingsJson));
   persistent_settings_->ValidatePersistentSettings();
   DCHECK(persistent_settings_);
 
@@ -112,7 +112,7 @@
         persistent_settings_->GetPersistentSettingAsDictionary(key_string);
     if (dict.empty()) {
       DLOG(INFO) << "Key: " << key_string << " does not exist in "
-                 << kSettingsJson;
+                 << ServiceWorkerConsts::kSettingsJson;
       continue;
     }
     if (!CheckPersistentValue(key_string, kSettingsStorageKeyKey, dict,
@@ -121,6 +121,12 @@
     url::Origin storage_key =
         url::Origin::Create(GURL(dict[kSettingsStorageKeyKey]->GetString()));
 
+    // Only add persisted workers to the registration_map
+    // if their storage_key matches the origin of the initial_url.
+    if (!storage_key.IsSameOriginWith(url::Origin::Create(options_.url))) {
+      continue;
+    }
+
     if (!CheckPersistentValue(key_string, kSettingsScopeUrlKey, dict,
                               base::Value::Type::STRING))
       continue;
@@ -148,20 +154,40 @@
                               base::Value::Type::DICTIONARY)) {
       worker_key = kSettingsActiveWorkerKey;
       if (!CheckPersistentValue(key_string, worker_key, dict,
-                                base::Value::Type::DICTIONARY)) {
-        // Neither the waiting_worker or active_worker were correctly read
-        // from persistent settings.
+                                base::Value::Type::DICTIONARY))
         continue;
-      }
     }
-    if (!ReadServiceWorkerObjectSettings(registration, key_string,
-                                         std::move(dict[worker_key]),
-                                         worker_key)) {
+    if (!ReadServiceWorkerObjectSettings(
+            registration, key_string, std::move(dict[worker_key]), worker_key))
       continue;
+
+    if (CheckPersistentValue(key_string, kSettingsLastUpdateCheckTimeKey, dict,
+                             base::Value::Type::STRING)) {
+      int64_t last_update_check_time =
+          std::atol(dict[kSettingsLastUpdateCheckTimeKey]->GetString().c_str());
+      registration->set_last_update_check_time(
+          base::Time::FromDeltaSinceWindowsEpoch(
+              base::TimeDelta::FromMicroseconds(last_update_check_time)));
     }
 
     key_set_.insert(key_string);
     registration_map.insert(std::make_pair(key, registration));
+    registration->set_is_persisted(true);
+
+    options_.service_worker_jobs->message_loop()->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ServiceWorkerJobs::Activate,
+                       base::Unretained(options_.service_worker_jobs),
+                       registration));
+
+    auto job = options_.service_worker_jobs->CreateJobWithoutPromise(
+        ServiceWorkerJobs::JobType::kUpdate, storage_key, scope,
+        registration->waiting_worker()->script_url());
+    options_.service_worker_jobs->message_loop()->task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
+                       base::Unretained(options_.service_worker_jobs),
+                       std::move(job)));
   }
 }
 
@@ -184,11 +210,6 @@
   if (script_url_value == nullptr) return false;
   worker->set_script_url(GURL(script_url_value->GetString()));
 
-  base::Value* state_value = value_dict->FindKeyOfType(
-      kSettingsServiceWorkerStateKey, base::Value::Type::INTEGER);
-  if (state_value == nullptr) return false;
-  worker->set_state(static_cast<ServiceWorkerState>(state_value->GetInt()));
-
   base::Value* skip_waiting_value = value_dict->FindKeyOfType(
       kSettingsSkipWaitingKey, base::Value::Type::BOOLEAN);
   if (skip_waiting_value == nullptr) return false;
@@ -222,16 +243,27 @@
     if (script_url_value.is_string()) {
       auto script_url_string = script_url_value.GetString();
       auto script_url = GURL(script_url_string);
-      std::unique_ptr<std::vector<uint8_t>> data =
-          cache_->Retrieve(disk_cache::ResourceType::kServiceWorkerScript,
-                           cache_->CreateKey(key_string + script_url_string));
+      std::unique_ptr<std::vector<uint8_t>> data = cache_->Retrieve(
+          disk_cache::ResourceType::kServiceWorkerScript,
+          web::cache_utils::GetKey(key_string + script_url_string));
       if (data == nullptr) {
         return false;
       }
-      std::string script_string(data->begin(), data->end());
-      auto result = script_resource_map.insert(std::make_pair(
-          script_url,
-          ScriptResource(std::make_unique<std::string>(script_string))));
+      auto script_resource = ScriptResource(std::make_unique<std::string>(
+          std::string(data->begin(), data->end())));
+      if (script_url == worker->script_url()) {
+        // Get the persistent headers for the ServiceWorkerObject script_url_.
+        // This is used in ServiceWorkerObject::Initialize().
+        base::Value* raw_header_value = value_dict->FindKeyOfType(
+            kSettingsRawHeadersKey, base::Value::Type::STRING);
+        if (raw_header_value == nullptr) return false;
+        const scoped_refptr<net::HttpResponseHeaders> headers =
+            scoped_refptr<net::HttpResponseHeaders>(
+                new net::HttpResponseHeaders(raw_header_value->GetString()));
+        script_resource.headers = headers;
+      }
+      auto result = script_resource_map.insert(
+          std::make_pair(script_url, std::move(script_resource)));
       DCHECK(result.second);
     }
   }
@@ -240,11 +272,8 @@
   }
   worker->set_script_resource_map(std::move(script_resource_map));
 
-  if (worker_key_string == kSettingsWaitingWorkerKey) {
-    registration->set_waiting_worker(worker);
-  } else {
-    registration->set_active_worker(worker);
-  }
+  registration->set_waiting_worker(worker);
+
   return true;
 }
 
@@ -302,6 +331,12 @@
       kSettingsUpdateViaCacheModeKey,
       std::make_unique<base::Value>(registration->update_via_cache_mode()));
 
+  dict.try_emplace(kSettingsLastUpdateCheckTimeKey,
+                   std::make_unique<base::Value>(
+                       std::to_string(registration->last_update_check_time()
+                                          .ToDeltaSinceWindowsEpoch()
+                                          .InMicroseconds())));
+
   persistent_settings_->SetPersistentSetting(
       key_string, std::make_unique<base::Value>(dict));
 }
@@ -316,10 +351,6 @@
       kSettingsOptionsNameKey,
       std::make_unique<base::Value>(service_worker_object->options_name()));
 
-  dict.try_emplace(
-      kSettingsServiceWorkerStateKey,
-      std::make_unique<base::Value>(service_worker_object->state()));
-
   dict.try_emplace(kSettingsScriptUrlKey,
                    std::make_unique<base::Value>(
                        service_worker_object->script_url().spec()));
@@ -353,8 +384,17 @@
     std::vector<uint8_t> data(resource.begin(), resource.end());
     cache_->Store(
         disk_cache::ResourceType::kServiceWorkerScript,
-        cache_->CreateKey(registration_key_string + script_url_string), data,
+        web::cache_utils::GetKey(registration_key_string + script_url_string),
+        data,
         /* metadata */ base::nullopt);
+
+    if (script_url_string == service_worker_object->script_url().spec()) {
+      // Persist the raw headers from the ServiceWorkerObject script_url_
+      // ScriptResource headers.
+      dict.try_emplace(kSettingsRawHeadersKey,
+                       std::make_unique<base::Value>(
+                           script_resource.second.headers->raw_headers()));
+    }
   }
   dict.try_emplace(kSettingsScriptResourceMapScriptUrlsKey,
                    std::make_unique<base::Value>(std::move(script_urls_value)));
@@ -408,8 +448,9 @@
       auto script_url_value = std::move(script_urls_list[i]);
       if (script_url_value.is_string()) {
         auto script_url_string = script_url_value.GetString();
-        cache_->Delete(disk_cache::ResourceType::kServiceWorkerScript,
-                       cache_->CreateKey(key_string + script_url_string));
+        cache_->Delete(
+            disk_cache::ResourceType::kServiceWorkerScript,
+            web::cache_utils::GetKey(key_string + script_url_string));
       }
     }
   }
diff --git a/cobalt/worker/service_worker_persistent_settings.h b/cobalt/worker/service_worker_persistent_settings.h
index b260d76..efda66f 100644
--- a/cobalt/worker/service_worker_persistent_settings.h
+++ b/cobalt/worker/service_worker_persistent_settings.h
@@ -33,7 +33,6 @@
 #include "cobalt/script/promise.h"
 #include "cobalt/script/script_value.h"
 #include "cobalt/script/script_value_factory.h"
-#include "cobalt/web/environment_settings.h"
 #include "cobalt/web/web_settings.h"
 #include "cobalt/worker/service_worker_registration_object.h"
 #include "cobalt/worker/service_worker_update_via_cache.h"
@@ -49,15 +48,17 @@
     Options(web::WebSettings* web_settings,
             network::NetworkModule* network_module,
             web::UserAgentPlatformInfo* platform_info,
-            ServiceWorkerJobs* service_worker_jobs)
+            ServiceWorkerJobs* service_worker_jobs, const GURL& url)
         : web_settings(web_settings),
           network_module(network_module),
           platform_info(platform_info),
-          service_worker_jobs(service_worker_jobs) {}
+          service_worker_jobs(service_worker_jobs),
+          url(url) {}
     web::WebSettings* web_settings;
     network::NetworkModule* network_module;
     web::UserAgentPlatformInfo* platform_info;
     ServiceWorkerJobs* service_worker_jobs;
+    const GURL& url;
   };
 
   explicit ServiceWorkerPersistentSettings(const Options& options);
diff --git a/cobalt/worker/service_worker_registration.cc b/cobalt/worker/service_worker_registration.cc
index f5c4ee6..4e30763 100644
--- a/cobalt/worker/service_worker_registration.cc
+++ b/cobalt/worker/service_worker_registration.cc
@@ -50,7 +50,9 @@
           ->script_value_factory()
           ->CreateInterfacePromise<scoped_refptr<ServiceWorkerRegistration>>();
   std::unique_ptr<script::ValuePromiseWrappable::Reference> promise_reference(
-      new script::ValuePromiseWrappable::Reference(this, promise));
+      new script::ValuePromiseWrappable::Reference(
+          environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+          promise));
   // Perform the rest of the steps in a task, because the promise has to be
   // returned before we can safely reject or resolve it.
   base::MessageLoop::current()->task_runner()->PostTask(
@@ -112,16 +114,14 @@
   std::unique_ptr<ServiceWorkerJobs::Job> job = jobs->CreateJob(
       ServiceWorkerJobs::JobType::kUpdate, registration_->storage_key(),
       registration_->scope_url(), newest_worker->script_url(),
-      std::move(promise_reference), environment_settings());
+      std::move(promise_reference), environment_settings()->context());
   DCHECK(!promise_reference);
 
   // 7. Set job’s worker type to newestWorker’s type.
   // Cobalt only supports 'classic' worker type.
 
   // 8. Invoke Schedule Job with job.
-  jobs->message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
-                                base::Unretained(jobs), std::move(job)));
+  jobs->ScheduleJob(std::move(job));
   DCHECK(!job.get());
 }
 
@@ -136,40 +136,39 @@
                                           ->script_value_factory()
                                           ->CreateBasicPromise<bool>();
   std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference(
-      new script::ValuePromiseBool::Reference(this, promise));
+      new script::ValuePromiseBool::Reference(
+          environment_settings()->context()->GetWindowOrWorkerGlobalScope(),
+          promise));
 
   // Perform the rest of the steps in a task, so that unregister doesn't race
   // past any previously submitted update requests.
   base::MessageLoop::current()->task_runner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&ServiceWorkerRegistration::UnregisterTask,
-                     base::Unretained(this), std::move(promise_reference)));
+      base::BindOnce(
+          [](worker::ServiceWorkerJobs* jobs, const url::Origin& storage_key,
+             const GURL& scope_url,
+             std::unique_ptr<script::ValuePromiseBool::Reference>
+                 promise_reference,
+             web::Context* client) {
+            // 3. Let job be the result of running Create Job with unregister,
+            //    registration’s storage key, registration’s scope url, null,
+            //    promise, and this's relevant settings object.
+            std::unique_ptr<ServiceWorkerJobs::Job> job = jobs->CreateJob(
+                ServiceWorkerJobs::JobType::kUnregister, storage_key, scope_url,
+                GURL(), std::move(promise_reference), client);
+            DCHECK(!promise_reference);
+
+            // 4. Invoke Schedule Job with job.
+            jobs->ScheduleJob(std::move(job));
+            DCHECK(!job.get());
+          },
+          environment_settings()->context()->service_worker_jobs(),
+          registration_->storage_key(), registration_->scope_url(),
+          std::move(promise_reference), environment_settings()->context()));
   // 5. Return promise.
   return promise;
 }
 
-void ServiceWorkerRegistration::UnregisterTask(
-    std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference) {
-  // Algorithm for unregister():
-  //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#navigator-service-worker-unregister
-  // 3. Let job be the result of running Create Job with unregister,
-  //    registration’s storage key, registration’s scope url, null, promise, and
-  //    this's relevant settings object.
-  worker::ServiceWorkerJobs* jobs =
-      environment_settings()->context()->service_worker_jobs();
-  std::unique_ptr<ServiceWorkerJobs::Job> job = jobs->CreateJob(
-      ServiceWorkerJobs::JobType::kUnregister, registration_->storage_key(),
-      registration_->scope_url(), GURL(), std::move(promise_reference),
-      environment_settings());
-  DCHECK(!promise_reference);
-
-  // 4. Invoke Schedule Job with job.
-  jobs->message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&ServiceWorkerJobs::ScheduleJob,
-                                base::Unretained(jobs), std::move(job)));
-  DCHECK(!job.get());
-}
-
 std::string ServiceWorkerRegistration::scope() const {
   return registration_->scope_url().spec();
 }
diff --git a/cobalt/worker/service_worker_registration.h b/cobalt/worker/service_worker_registration.h
index 202647c..cd7795f 100644
--- a/cobalt/worker/service_worker_registration.h
+++ b/cobalt/worker/service_worker_registration.h
@@ -80,9 +80,6 @@
   void UpdateTask(std::unique_ptr<script::ValuePromiseWrappable::Reference>
                       promise_reference);
 
-  void UnregisterTask(
-      std::unique_ptr<script::ValuePromiseBool::Reference> promise_reference);
-
   scoped_refptr<worker::ServiceWorkerRegistrationObject> registration_;
   scoped_refptr<ServiceWorker> installing_;
   scoped_refptr<ServiceWorker> waiting_;
diff --git a/cobalt/worker/service_worker_registration_map.cc b/cobalt/worker/service_worker_registration_map.cc
index d495b0f..e8d0340 100644
--- a/cobalt/worker/service_worker_registration_map.cc
+++ b/cobalt/worker/service_worker_registration_map.cc
@@ -23,13 +23,12 @@
 
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/trace_event/trace_event.h"
 #include "cobalt/script/exception_message.h"
 #include "cobalt/script/promise.h"
 #include "cobalt/script/script_value.h"
-#include "cobalt/web/context.h"
-#include "cobalt/web/environment_settings.h"
 #include "cobalt/worker/service_worker_jobs.h"
 #include "cobalt/worker/service_worker_registration_object.h"
 #include "cobalt/worker/service_worker_update_via_cache.h"
@@ -44,12 +43,14 @@
 
 // Returns the serialized URL excluding the fragment.
 std::string SerializeExcludingFragment(const GURL& url) {
-  url::Replacements<char> replacements;
+  GURL::Replacements replacements;
+  replacements.ClearUsername();
+  replacements.ClearPassword();
+  replacements.ClearQuery();
   replacements.ClearRef();
-  GURL no_fragment_url = url.ReplaceComponents(replacements);
-  DCHECK(!no_fragment_url.has_ref() || no_fragment_url.ref().empty());
-  DCHECK(!no_fragment_url.is_empty());
-  return no_fragment_url.spec();
+  return base::TrimString(url.ReplaceComponents(replacements).spec(), "/",
+                          base::TrimPositions::TRIM_TRAILING)
+      .as_string();
 }
 
 }  // namespace
@@ -59,6 +60,11 @@
   service_worker_persistent_settings_.reset(
       new ServiceWorkerPersistentSettings(options));
   DCHECK(service_worker_persistent_settings_);
+
+  ReadPersistentSettings();
+}
+
+void ServiceWorkerRegistrationMap::ReadPersistentSettings() {
   service_worker_persistent_settings_->ReadServiceWorkerRegistrationMapSettings(
       registration_map_);
 }
@@ -232,6 +238,7 @@
   // is not this service worker registration.
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#dfn-service-worker-registration-unregistered
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (!registration) return true;
   std::string scope_string =
       SerializeExcludingFragment(registration->scope_url());
   RegistrationMapKey registration_key(registration->storage_key(),
@@ -280,12 +287,9 @@
 }
 
 void ServiceWorkerRegistrationMap::AbortAllActive() {
-  for (auto& entry : registration_map_) {
-    const scoped_refptr<ServiceWorkerRegistrationObject>& registration =
-        entry.second;
-    if (registration->active_worker()) {
-      registration->active_worker()->Abort();
-    }
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  for (auto entry : registration_map_) {
+    entry.second->AbortAll();
   }
 }
 
diff --git a/cobalt/worker/service_worker_registration_map.h b/cobalt/worker/service_worker_registration_map.h
index 850c5c0..f998319 100644
--- a/cobalt/worker/service_worker_registration_map.h
+++ b/cobalt/worker/service_worker_registration_map.h
@@ -29,7 +29,6 @@
 #include "cobalt/script/promise.h"
 #include "cobalt/script/script_value.h"
 #include "cobalt/script/script_value_factory.h"
-#include "cobalt/web/environment_settings.h"
 #include "cobalt/worker/service_worker_persistent_settings.h"
 #include "cobalt/worker/service_worker_registration_object.h"
 #include "cobalt/worker/service_worker_update_via_cache.h"
@@ -46,6 +45,7 @@
  public:
   explicit ServiceWorkerRegistrationMap(
       const ServiceWorkerPersistentSettings::Options& options);
+  ~ServiceWorkerRegistrationMap() { AbortAllActive(); }
 
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#get-registration-algorithm
   scoped_refptr<ServiceWorkerRegistrationObject> GetRegistration(
@@ -78,6 +78,8 @@
   // registration's active_worker or waiting_worker are updated.
   void PersistRegistration(const url::Origin& storage_key, const GURL& scope);
 
+  void ReadPersistentSettings();
+
  private:
   // ThreadChecker for use by the methods operating on the registration map.
   THREAD_CHECKER(thread_checker_);
diff --git a/cobalt/worker/service_worker_registration_object.cc b/cobalt/worker/service_worker_registration_object.cc
index ab444e9..b720645 100644
--- a/cobalt/worker/service_worker_registration_object.cc
+++ b/cobalt/worker/service_worker_registration_object.cc
@@ -28,33 +28,55 @@
     const ServiceWorkerUpdateViaCache& update_via_cache_mode)
     : storage_key_(storage_key),
       scope_url_(scope_url),
-      update_via_cache_mode_(update_via_cache_mode) {}
+      update_via_cache_mode_(update_via_cache_mode),
+      last_update_check_time_(base::Time()),
+      is_persisted_(false) {}
 
-ServiceWorkerObject* ServiceWorkerRegistrationObject::GetNewestWorker() {
+ServiceWorkerRegistrationObject::~ServiceWorkerRegistrationObject() {
+  AbortAll();
+}
+
+void ServiceWorkerRegistrationObject::AbortAll() {
+  if (!done_event()->IsSignaled()) {
+    done_event()->Signal();
+  }
+  if (installing_worker()) {
+    installing_worker()->Abort();
+  }
+  if (waiting_worker()) {
+    waiting_worker()->Abort();
+  }
+  if (active_worker()) {
+    active_worker()->Abort();
+  }
+}
+
+scoped_refptr<ServiceWorkerObject>
+ServiceWorkerRegistrationObject::GetNewestWorker() {
   // Algorithm for Get Newest Worker:
   //   https://www.w3.org/TR/2022/CRD-service-workers-20220712/#get-newest-worker
   // 1. Run the following steps atomically.
   base::AutoLock lock(mutex_);
-
-  // 2. Let newestWorker be null.
-  ServiceWorkerObject* newest_worker = nullptr;
-
-  // 3. If registration’s installing worker is not null, set newestWorker to
-  // registration’s installing worker.
   if (installing_worker_) {
-    newest_worker = installing_worker_;
-    // 4. Else if registration’s waiting worker is not null, set newestWorker to
-    // registration’s waiting worker.
+    // 3. If registration’s installing worker is not null, set newestWorker to
+    //    registration’s installing worker.
+    // 6. Return newestWorker.
+    return installing_worker_;
   } else if (waiting_worker_) {
-    newest_worker = waiting_worker_;
-    // 5. Else if registration’s active worker is not null, set newestWorker to
-    // registration’s active worker.
+    // 4. Else if registration’s waiting worker is not null, set newestWorker to
+    //    registration’s waiting worker.
+    // 6. Return newestWorker.
+    return waiting_worker_;
   } else if (active_worker_) {
-    newest_worker = active_worker_;
+    // 5. Else if registration’s active worker is not null, set newestWorker to
+    //    registration’s active worker.
+    // 6. Return newestWorker.
+    return active_worker_;
   }
 
+  // 2. Let newestWorker be null.
   // 6. Return newestWorker.
-  return newest_worker;
+  return nullptr;
 }
 
 }  // namespace worker
diff --git a/cobalt/worker/service_worker_registration_object.h b/cobalt/worker/service_worker_registration_object.h
index 0a399e0..f3785a1 100644
--- a/cobalt/worker/service_worker_registration_object.h
+++ b/cobalt/worker/service_worker_registration_object.h
@@ -42,39 +42,63 @@
   ServiceWorkerRegistrationObject(
       const url::Origin& storage_key, const GURL& scope_url,
       const ServiceWorkerUpdateViaCache& update_via_cache_mode);
-  ~ServiceWorkerRegistrationObject() {}
+  ~ServiceWorkerRegistrationObject();
+
+  void AbortAll();
 
   const url::Origin& storage_key() const { return storage_key_; }
+
   const GURL& scope_url() const { return scope_url_; }
+
   void set_update_via_cache_mode(
       const ServiceWorkerUpdateViaCache& update_via_cache_mode) {
     update_via_cache_mode_ = update_via_cache_mode;
   }
+
   const ServiceWorkerUpdateViaCache& update_via_cache_mode() const {
     return update_via_cache_mode_;
   }
 
-  void set_installing_worker(scoped_refptr<ServiceWorkerObject> worker) {
+  void set_installing_worker(const scoped_refptr<ServiceWorkerObject>& worker) {
     installing_worker_ = worker;
   }
   const scoped_refptr<ServiceWorkerObject>& installing_worker() const {
     return installing_worker_;
   }
-  void set_waiting_worker(scoped_refptr<ServiceWorkerObject> worker) {
+  void set_waiting_worker(const scoped_refptr<ServiceWorkerObject>& worker) {
     waiting_worker_ = worker;
   }
   const scoped_refptr<ServiceWorkerObject>& waiting_worker() const {
     return waiting_worker_;
   }
-  void set_active_worker(scoped_refptr<ServiceWorkerObject> worker) {
+  void set_active_worker(const scoped_refptr<ServiceWorkerObject>& worker) {
     active_worker_ = worker;
   }
   const scoped_refptr<ServiceWorkerObject>& active_worker() const {
     return active_worker_;
   }
 
+  // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#service-worker-registration-stale
+  bool stale() const {
+    return !last_update_check_time_.is_null() &&
+           (base::Time::Now() - last_update_check_time_).InSeconds() >
+               kStaleServiceWorkerRegistrationTimeout;
+  }
+
+  base::Time last_update_check_time() const { return last_update_check_time_; }
+  void set_last_update_check_time(base::Time time) {
+    last_update_check_time_ = time;
+  }
+
   // https://www.w3.org/TR/2022/CRD-service-workers-20220712/#get-newest-worker
-  ServiceWorkerObject* GetNewestWorker();
+  scoped_refptr<ServiceWorkerObject> GetNewestWorker();
+
+  const int kStaleServiceWorkerRegistrationTimeout = 86400;
+
+  base::WaitableEvent* done_event() { return &done_event_; }
+
+  bool is_persisted() const { return is_persisted_; }
+  void set_is_persisted(bool value) { is_persisted_ = value; }
 
  private:
   // This lock is to allow atomic operations on the registration object.
@@ -86,6 +110,14 @@
   scoped_refptr<ServiceWorkerObject> installing_worker_;
   scoped_refptr<ServiceWorkerObject> waiting_worker_;
   scoped_refptr<ServiceWorkerObject> active_worker_;
+
+  base::Time last_update_check_time_;
+
+  base::WaitableEvent done_event_ = {
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::SIGNALED};
+
+  bool is_persisted_;
 };
 
 }  // namespace worker
diff --git a/cobalt/worker/testing/BUILD.gn b/cobalt/worker/testing/BUILD.gn
index e91994b..ac54117 100644
--- a/cobalt/worker/testing/BUILD.gn
+++ b/cobalt/worker/testing/BUILD.gn
@@ -28,6 +28,7 @@
     "//cobalt/script",
     "//cobalt/web",
     "//cobalt/web:dom_exception",
+    "//cobalt/web:stat_tracker",
     "//cobalt/web/testing:web_testing",
     "//cobalt/worker",
     "//testing/gmock",
diff --git a/cobalt/worker/testing/test_with_javascript.h b/cobalt/worker/testing/test_with_javascript.h
index e40483d..e540d2f 100644
--- a/cobalt/worker/testing/test_with_javascript.h
+++ b/cobalt/worker/testing/test_with_javascript.h
@@ -28,7 +28,9 @@
 #include "cobalt/script/source_code.h"
 #include "cobalt/script/testing/mock_exception_state.h"
 #include "cobalt/web/context.h"
+#include "cobalt/web/stat_tracker.h"
 #include "cobalt/web/testing/stub_web_context.h"
+#include "cobalt/web/window_or_worker_global_scope.h"
 #include "cobalt/worker/dedicated_worker_global_scope.h"
 #include "cobalt/worker/service_worker_global_scope.h"
 #include "cobalt/worker/worker_settings.h"
@@ -42,15 +44,17 @@
 template <class TypeIdProvider>
 class TestWithJavaScriptBase : public TypeIdProvider {
  public:
-  TestWithJavaScriptBase() {
+  TestWithJavaScriptBase() : stat_tracker_("TestWithJavaScriptBase", "Test") {
     web_context_.reset(new web::testing::StubWebContext());
-    web_context_->setup_environment_settings(new WorkerSettings());
+    web_context_->SetupEnvironmentSettings(new WorkerSettings());
     web_context_->environment_settings()->set_creation_url(GURL("about:blank"));
+    web::WindowOrWorkerGlobalScope::Options global_scope_options;
+    global_scope_options.stat_tracker = &stat_tracker_;
 
     if (TypeIdProvider::GetGlobalScopeTypeId() ==
         base::GetTypeId<DedicatedWorkerGlobalScope>()) {
-      dedicated_worker_global_scope_ =
-          new DedicatedWorkerGlobalScope(web_context_->environment_settings());
+      dedicated_worker_global_scope_ = new DedicatedWorkerGlobalScope(
+          web_context_->environment_settings(), global_scope_options);
       dedicated_worker_global_scope_->set_name("TestWithJavaScriptBase");
       web_context_->global_environment()->CreateGlobalObject(
           dedicated_worker_global_scope_, web_context_->environment_settings());
@@ -66,11 +70,13 @@
               web_context_->network_module(),
               containing_service_worker_registration_));
       service_worker_global_scope_ = new ServiceWorkerGlobalScope(
-          web_context_->environment_settings(), service_worker_object_);
+          web_context_->environment_settings(), global_scope_options,
+          service_worker_object_);
       web_context_->global_environment()->CreateGlobalObject(
           service_worker_global_scope_, web_context_->environment_settings());
       worker_global_scope_ = service_worker_global_scope_.get();
     }
+    web_context_->SetupFinished();
   }
 
   ~TestWithJavaScriptBase() { ClearWebContext(); }
@@ -93,6 +99,10 @@
     return web_context_.get();
   }
 
+  web::EnvironmentSettings* environment_settings() const {
+    return web_context()->environment_settings();
+  }
+
   scoped_refptr<script::GlobalEnvironment> global_environment() const {
     DCHECK(this->web_context());
     return this->web_context()->global_environment();
@@ -137,6 +147,7 @@
       containing_service_worker_registration_;
   scoped_refptr<ServiceWorkerGlobalScope> service_worker_global_scope_;
   ::testing::StrictMock<script::testing::MockExceptionState> exception_state_;
+  web::StatTracker stat_tracker_;
 };
 
 template <class GlobalScope>
diff --git a/cobalt/worker/worker.cc b/cobalt/worker/worker.cc
index a27476f..633861d 100644
--- a/cobalt/worker/worker.cc
+++ b/cobalt/worker/worker.cc
@@ -39,10 +39,6 @@
 namespace cobalt {
 namespace worker {
 
-namespace {
-bool PermitAnyURL(const GURL&, bool) { return true; }
-}  // namespace
-
 Worker::Worker(const char* name, const Options& options) : options_(options) {
   // Algorithm for 'run a worker'
   //   https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#run-a-worker
@@ -99,7 +95,7 @@
   //   https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-worker-environment-settings-object
   worker_settings->set_origin(
       options_.outside_context->environment_settings()->GetOrigin());
-  web_context_->setup_environment_settings(worker_settings);
+  web_context_->SetupEnvironmentSettings(worker_settings);
   // From algorithm for to setup up a worker environment settings object:
   //   https://html.spec.whatwg.org/commit-snapshots/465a6b672c703054de278b0f8133eb3ad33d93f4/#set-up-a-worker-environment-settings-object
   // 5. Set settings object's creation URL to worker global scope's url.
@@ -108,8 +104,9 @@
   // 8. Let worker global scope be the global object of realm execution
   //    context's Realm component.
   scoped_refptr<DedicatedWorkerGlobalScope> dedicated_worker_global_scope =
-      new DedicatedWorkerGlobalScope(web_context_->environment_settings(),
-                                     false);
+      new DedicatedWorkerGlobalScope(
+          web_context_->environment_settings(), options_.global_scope_options,
+          /*parent_cross_origin_isolated_capability*/ false);
   worker_global_scope_ = dedicated_worker_global_scope;
   // 9. Set up a worker environment settings object with realm execution
   //    context, outside settings, and unsafeWorkerCreationTime, and let
@@ -156,6 +153,7 @@
   // "worker" otherwise.
   // 14. Obtain script
 
+  web_context_->SetupFinished();
   Obtain();
 }
 
diff --git a/cobalt/worker/worker.h b/cobalt/worker/worker.h
index 9d7043c..9d8d779 100644
--- a/cobalt/worker/worker.h
+++ b/cobalt/worker/worker.h
@@ -57,6 +57,7 @@
   // Worker Options needed at thread run time.
   struct Options {
     web::Agent::Options web_options;
+    web::WindowOrWorkerGlobalScope::Options global_scope_options;
 
     // Holds the source location where the worker was constructed.
     base::SourceLocation construction_location;
diff --git a/cobalt/worker/worker_global_scope.cc b/cobalt/worker/worker_global_scope.cc
index d9025b9..150313e 100644
--- a/cobalt/worker/worker_global_scope.cc
+++ b/cobalt/worker/worker_global_scope.cc
@@ -41,7 +41,6 @@
 namespace worker {
 
 namespace {
-bool PermitAnyURL(const GURL& url, bool) { return true; }
 
 class ScriptLoader : public base::MessageLoop::DestructionObserver {
  public:
@@ -93,7 +92,7 @@
     script_loader_factory_.reset();
   }
 
-  void Load(const loader::Origin& origin,
+  void Load(web::CspDelegate* csp_delegate, const loader::Origin& origin,
             const std::vector<GURL>& resolved_urls) {
     TRACE_EVENT0("cobalt::worker", "ScriptLoader::Load()");
     number_of_loads_ = resolved_urls.size();
@@ -105,20 +104,23 @@
     for (int i = 0; i < resolved_urls.size(); ++i) {
       const GURL& url = resolved_urls[i];
       thread_->message_loop()->task_runner()->PostTask(
-          FROM_HERE, base::BindOnce(&ScriptLoader::LoaderTask,
-                                    base::Unretained(this), &loaders_[i],
-                                    origin, url, &contents_[i], &errors_[i]));
+          FROM_HERE,
+          base::BindOnce(&ScriptLoader::LoaderTask, base::Unretained(this),
+                         csp_delegate, &loaders_[i], origin, url, &contents_[i],
+                         &errors_[i]));
     }
     load_finished_.Wait();
   }
 
-  void LoaderTask(std::unique_ptr<loader::Loader>* loader,
+  void LoaderTask(web::CspDelegate* csp_delegate,
+                  std::unique_ptr<loader::Loader>* loader,
                   const loader::Origin& origin, const GURL& url,
                   std::unique_ptr<std::string>* content,
                   std::unique_ptr<std::string>* error) {
     TRACE_EVENT0("cobalt::worker", "ScriptLoader::LoaderTask()");
-    // Todo: implement csp check (b/225037465)
-    csp::SecurityCallback csp_callback = base::Bind(&PermitAnyURL);
+    csp::SecurityCallback csp_callback =
+        base::Bind(&web::CspDelegate::CanLoad, base::Unretained(csp_delegate),
+                   web::CspDelegate::kWorker);
 
     bool skip_fetch_intercept =
         context_->GetWindowOrWorkerGlobalScope()->IsServiceWorker();
@@ -186,14 +188,10 @@
 
 }  // namespace
 
-WorkerGlobalScope::WorkerGlobalScope(script::EnvironmentSettings* settings)
-    : web::WindowOrWorkerGlobalScope(
-          settings, /*stat_tracker=*/NULL,
-          // Using default options for CSP
-          web::WindowOrWorkerGlobalScope::Options(
-              // TODO (b/233788170): once application state is
-              // available, update this to use the actual state.
-              base::ApplicationState::kApplicationStateStarted)),
+WorkerGlobalScope::WorkerGlobalScope(
+    script::EnvironmentSettings* settings,
+    const web::WindowOrWorkerGlobalScope::Options& options)
+    : web::WindowOrWorkerGlobalScope(settings, options),
       location_(new WorkerLocation(settings->creation_url())),
       navigator_(new WorkerNavigator(settings)) {
   set_navigator_base(navigator_);
@@ -286,9 +284,8 @@
   web::EnvironmentSettings* settings = environment_settings();
   const GURL& base_url = settings->base_url();
   loader::Origin origin = loader::Origin(base_url.GetOrigin());
-  // TODO(b/241801523): Apply CSP.
   ScriptLoader script_loader(settings->context());
-  script_loader.Load(origin, request_urls);
+  script_loader.Load(csp_delegate(), origin, request_urls);
 
   for (int index = 0; index < request_urls.size(); ++index) {
     const auto& error = script_loader.GetError(index);
@@ -378,9 +375,8 @@
   //      object, passing along any custom perform the fetch steps provided.
   //      If this succeeds, let script be the result. Otherwise, rethrow the
   //      exception.
-  // TODO(b/241801523): Apply CSP.
   ScriptLoader script_loader(settings->context());
-  script_loader.Load(origin, request_urls);
+  script_loader.Load(csp_delegate(), origin, request_urls);
 
   // 5. For each url in the resulting URL records, run these substeps:
   int content_lookup_index = 0;
diff --git a/cobalt/worker/worker_global_scope.h b/cobalt/worker/worker_global_scope.h
index e387991..d3780d9 100644
--- a/cobalt/worker/worker_global_scope.h
+++ b/cobalt/worker/worker_global_scope.h
@@ -55,6 +55,7 @@
       : content(std::move(content)), headers(headers) {}
   std::unique_ptr<std::string> content;
   scoped_refptr<net::HttpResponseHeaders> headers;
+  bool has_ever_been_evaluated = false;
 };
 
 using ScriptResourceMap = std::map<GURL, ScriptResource>;
@@ -70,7 +71,9 @@
   using ResponseCallback =
       base::Callback<std::string*(const GURL& url, std::string*)>;
 
-  explicit WorkerGlobalScope(script::EnvironmentSettings* settings);
+  explicit WorkerGlobalScope(
+      script::EnvironmentSettings* settings,
+      const web::WindowOrWorkerGlobalScope::Options& options);
   WorkerGlobalScope(const WorkerGlobalScope&) = delete;
   WorkerGlobalScope& operator=(const WorkerGlobalScope&) = delete;
 
diff --git a/cobalt/xhr/xml_http_request.cc b/cobalt/xhr/xml_http_request.cc
index 0a9d4ed..ee5ea3a 100644
--- a/cobalt/xhr/xml_http_request.cc
+++ b/cobalt/xhr/xml_http_request.cc
@@ -357,6 +357,7 @@
       upload_listener_(false),
       with_credentials_(false),
       xhr_(xhr),
+      will_destroy_current_message_loop_(false),
       active_requests_count_(0),
       http_status_(0),
       redirect_times_(0),
@@ -367,6 +368,7 @@
       timeout_ms_(0),
       upload_complete_(false) {
   DCHECK(environment_settings());
+  base::MessageLoop::current()->AddDestructionObserver(this);
 }
 
 void XMLHttpRequestImpl::Abort() {
@@ -394,7 +396,6 @@
                               const base::Optional<std::string>& password,
                               script::ExceptionState* exception_state) {
   TRACK_MEMORY_SCOPE("XHR");
-
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   XMLHttpRequest::State previous_state = state_;
@@ -516,17 +517,11 @@
                                ->IsServiceWorker();
   if (!in_service_worker && method_ == net::URLFetcher::GET) {
     loader::FetchInterceptorCoordinator::GetInstance()->TryIntercept(
-        request_url_,
-        std::make_unique<
-            base::OnceCallback<void(std::unique_ptr<std::string>)>>(
-            base::BindOnce(&XMLHttpRequestImpl::SendIntercepted,
-                           base::Unretained(this))),
-        std::make_unique<base::OnceCallback<void(const net::LoadTimingInfo&)>>(
-            base::BindOnce(&XMLHttpRequestImpl::ReportLoadTimingInfo,
-                           base::Unretained(this))),
-        std::make_unique<base::OnceClosure>(base::BindOnce(
-            &XMLHttpRequestImpl::SendFallback, base::Unretained(this),
-            request_body, exception_state)));
+        request_url_, /*main_resource=*/false, request_headers_, task_runner_,
+        base::BindOnce(&XMLHttpRequestImpl::SendIntercepted, AsWeakPtr()),
+        base::BindOnce(&XMLHttpRequestImpl::ReportLoadTimingInfo, AsWeakPtr()),
+        base::BindOnce(&XMLHttpRequestImpl::SendFallback, AsWeakPtr(),
+                       request_body, exception_state));
     return;
   }
   SendFallback(request_body, exception_state);
@@ -534,10 +529,13 @@
 
 void XMLHttpRequestImpl::SendIntercepted(
     std::unique_ptr<std::string> response) {
+  if (will_destroy_current_message_loop_.load()) {
+    return;
+  }
   if (task_runner_ != base::MessageLoop::current()->task_runner()) {
-    task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(&XMLHttpRequestImpl::SendIntercepted,
-                                  base::Unretained(this), std::move(response)));
+    task_runner_->PostTask(FROM_HERE,
+                           base::BindOnce(&XMLHttpRequestImpl::SendIntercepted,
+                                          AsWeakPtr(), std::move(response)));
     return;
   }
   sent_ = true;
@@ -599,6 +597,9 @@
 void XMLHttpRequestImpl::SendFallback(
     const base::Optional<XMLHttpRequest::RequestBodyType>& request_body,
     script::ExceptionState* exception_state) {
+  if (will_destroy_current_message_loop_.load()) {
+    return;
+  }
   if (task_runner_ != base::MessageLoop::current()->task_runner()) {
     task_runner_->PostTask(
         FROM_HERE,
@@ -1204,6 +1205,10 @@
   this->StartRequest(request_body_text_);
 }
 
+void XMLHttpRequestImpl::WillDestroyCurrentMessageLoop() {
+  will_destroy_current_message_loop_.store(true);
+}
+
 void XMLHttpRequestImpl::ReportLoadTimingInfo(
     const net::LoadTimingInfo& timing_info) {
   load_timing_info_ = timing_info;
diff --git a/cobalt/xhr/xml_http_request.h b/cobalt/xhr/xml_http_request.h
index 30c606d..21231fd 100644
--- a/cobalt/xhr/xml_http_request.h
+++ b/cobalt/xhr/xml_http_request.h
@@ -21,6 +21,8 @@
 #include <vector>
 
 #include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/optional.h"
 #include "base/timer/timer.h"
 #include "cobalt/dom/document.h"
@@ -44,6 +46,7 @@
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "starboard/atomic.h"
 #include "url/gurl.h"
 
 namespace cobalt {
@@ -220,12 +223,18 @@
 };
 
 
-class XMLHttpRequestImpl {
+class XMLHttpRequestImpl
+    : public base::SupportsWeakPtr<XMLHttpRequestImpl>,
+      public base::MessageLoopCurrent::DestructionObserver {
  public:
   explicit XMLHttpRequestImpl(XMLHttpRequest* xhr);
   XMLHttpRequestImpl(const XMLHttpRequestImpl&) = delete;
   XMLHttpRequestImpl& operator=(const XMLHttpRequestImpl&) = delete;
-  virtual ~XMLHttpRequestImpl() {}
+  virtual ~XMLHttpRequestImpl() {
+    if (!will_destroy_current_message_loop_.load()) {
+      base::MessageLoop::current()->RemoveDestructionObserver(this);
+    }
+  }
 
   void Abort();
   void Open(const std::string& method, const std::string& url, bool async,
@@ -298,6 +307,9 @@
                                 int64 total);
   void OnRedirect(const net::HttpResponseHeaders& headers);
 
+  // base::MessageLoopCurrent::DestructionObserver
+  void WillDestroyCurrentMessageLoop();
+
   // Called from bindings layer to tie objects' lifetimes to this XHR instance.
   XMLHttpRequestUpload* upload_or_null() { return upload_.get(); }
 
@@ -335,6 +347,7 @@
   bool upload_listener_;
   bool with_credentials_;
   XMLHttpRequest* xhr_;
+  starboard::atomic_bool will_destroy_current_message_loop_;
 
   // A corspreflight instance for potentially sending preflight
   // request and performing cors check for all cross origin requests.
@@ -448,7 +461,11 @@
   explicit DOMXMLHttpRequestImpl(XMLHttpRequest* xhr);
   DOMXMLHttpRequestImpl(const DOMXMLHttpRequestImpl&) = delete;
   DOMXMLHttpRequestImpl& operator=(const DOMXMLHttpRequestImpl&) = delete;
-  ~DOMXMLHttpRequestImpl() override {}
+  ~DOMXMLHttpRequestImpl() override {
+    if (!will_destroy_current_message_loop_.load()) {
+      base::MessageLoop::current()->RemoveDestructionObserver(this);
+    }
+  }
 
   scoped_refptr<dom::Document> response_xml(
       script::ExceptionState* exception_state) override;
diff --git a/download_resources.py b/download_resources.py
index 688f4e8..db26837 100644
--- a/download_resources.py
+++ b/download_resources.py
@@ -16,7 +16,6 @@
 
 import logging
 import os
-import platform
 import subprocess
 try:
   import urllib.request as urllib
@@ -26,25 +25,6 @@
 from tools import download_from_gcs
 
 
-def DownloadClangFormat(force=False):
-  clang_format_sha_path = os.path.join('buildtools', '{}', 'clang-format')
-
-  system = platform.system()
-  if system == 'Linux':
-    clang_format_sha_path = clang_format_sha_path.format('linux64')
-  elif system == 'Darwin':
-    clang_format_sha_path = clang_format_sha_path.format('mac')
-  elif system == 'Windows':
-    clang_format_sha_path = clang_format_sha_path.format('win') + '.exe'
-  else:
-    logging.error('Unknown system: %s', system)
-    return
-
-  download_from_gcs.MaybeDownloadFileFromGcs('chromium-clang-format',
-                                             clang_format_sha_path + '.sha1',
-                                             clang_format_sha_path, force)
-
-
 def DownloadGerritCommitMsgHook(force=False):
   git_dir = subprocess.check_output(['git', 'rev-parse', '--git-common-dir'
                                     ]).strip().decode('utf-8')
@@ -78,5 +58,4 @@
   logging.basicConfig(
       level=logging.INFO, format=logging_format, datefmt='%H:%M:%S')
 
-  DownloadClangFormat()
   DownloadGerritCommitMsgHook()
diff --git a/net/base/io_buffer.cc b/net/base/io_buffer.cc
index d198c93..c2ffac6 100644
--- a/net/base/io_buffer.cc
+++ b/net/base/io_buffer.cc
@@ -137,8 +137,16 @@
 void GrowableIOBuffer::SetCapacity(int capacity) {
   DCHECK_GE(capacity, 0);
   // realloc will crash if it fails.
-  real_data_.reset(
-      static_cast<char*>(SbMemoryReallocate(real_data_.release(), capacity)));
+  // Calling reallocate with size 0 and a non-null pointer causes memory leaks
+  // on many platforms, since it may return nullptr while also not deallocating
+  // the previously allocated memory.
+  if (real_data_ && capacity == 0) {
+    SbMemoryDeallocate(real_data_.release());
+    real_data_.reset();
+  } else {
+    real_data_.reset(
+        static_cast<char*>(SbMemoryReallocate(real_data_.release(), capacity)));
+  }
   capacity_ = capacity;
   if (offset_ > capacity)
     set_offset(capacity);
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index 4216187..a5b1354 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -208,6 +208,10 @@
   return response_writer_.get();
 }
 
+const HttpRequestHeaders& TestURLFetcher::GetRequestHeaders() const {
+  return fake_extra_request_headers_;
+}
+
 HttpResponseHeaders* TestURLFetcher::GetResponseHeaders() const {
   return fake_response_headers_.get();
 }
diff --git a/net/url_request/test_url_fetcher_factory.h b/net/url_request/test_url_fetcher_factory.h
index ae2dd54..880d078 100644
--- a/net/url_request/test_url_fetcher_factory.h
+++ b/net/url_request/test_url_fetcher_factory.h
@@ -138,6 +138,7 @@
 #if defined(STARBOARD)
   URLFetcherResponseWriter* GetResponseWriter() const override;
 #endif
+  const HttpRequestHeaders& GetRequestHeaders() const override;
   HttpResponseHeaders* GetResponseHeaders() const override;
   HostPortPair GetSocketAddress() const override;
   const ProxyServer& ProxyServerUsed() const override;
diff --git a/net/url_request/url_fetcher.h b/net/url_request/url_fetcher.h
index 0606693..5bc635f 100644
--- a/net/url_request/url_fetcher.h
+++ b/net/url_request/url_fetcher.h
@@ -24,7 +24,7 @@
 class SequencedTaskRunner;
 class TaskRunner;
 class TimeDelta;
-}
+}  // namespace base
 
 namespace url {
 class Origin;
@@ -82,9 +82,7 @@
  public:
   // Imposible http response code. Used to signal that no http response code
   // was received.
-  enum ResponseCode {
-    RESPONSE_CODE_INVALID = -1
-  };
+  enum ResponseCode { RESPONSE_CODE_INVALID = -1 };
 
   enum RequestType {
     GET,
@@ -324,6 +322,9 @@
   virtual URLFetcherResponseWriter* GetResponseWriter() const = 0;
 #endif
 
+  // Retrieve the request headers from the request.
+  virtual const HttpRequestHeaders& GetRequestHeaders() const = 0;
+
   // Retrieve the response headers from the request.  Must only be called after
   // the OnURLFetchComplete callback has run.
   virtual HttpResponseHeaders* GetResponseHeaders() const = 0;
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 6cdcfec..0d77b78 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -365,6 +365,10 @@
   response_writer_ = std::move(response_writer);
 }
 
+const HttpRequestHeaders& URLFetcherCore::GetRequestHeaders() const {
+  return extra_request_headers_;
+}
+
 HttpResponseHeaders* URLFetcherCore::GetResponseHeaders() const {
   return response_headers_.get();
 }
diff --git a/net/url_request/url_fetcher_core.h b/net/url_request/url_fetcher_core.h
index 4359ac5..02048d1 100644
--- a/net/url_request/url_fetcher_core.h
+++ b/net/url_request/url_fetcher_core.h
@@ -123,6 +123,7 @@
     return response_writer_.get();
   }
 #endif
+  const HttpRequestHeaders& GetRequestHeaders() const;
   HttpResponseHeaders* GetResponseHeaders() const;
   HostPortPair GetSocketAddress() const;
   const ProxyServer& ProxyServerUsed() const;
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index 41e88ec..b651ce4 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -156,6 +156,10 @@
 }
 #endif
 
+const HttpRequestHeaders& URLFetcherImpl::GetRequestHeaders() const {
+  return core_->GetRequestHeaders();
+}
+
 HttpResponseHeaders* URLFetcherImpl::GetResponseHeaders() const {
   return core_->GetResponseHeaders();
 }
diff --git a/net/url_request/url_fetcher_impl.h b/net/url_request/url_fetcher_impl.h
index 3ad8bea..21aafed 100644
--- a/net/url_request/url_fetcher_impl.h
+++ b/net/url_request/url_fetcher_impl.h
@@ -84,6 +84,7 @@
 #if defined(STARBOARD)
   URLFetcherResponseWriter* GetResponseWriter() const override;
 #endif
+  const HttpRequestHeaders& GetRequestHeaders() const override;
   HttpResponseHeaders* GetResponseHeaders() const override;
   HostPortPair GetSocketAddress() const override;
   const ProxyServer& ProxyServerUsed() const override;
diff --git a/requirements.txt b/requirements.txt
index 2732a91..66ef3fe 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
+clang-format
 cpplint<2
 pre-commit<3
 pylint<3
diff --git a/starboard/android/apk/app/src/app/AndroidManifest.xml b/starboard/android/apk/app/src/app/AndroidManifest.xml
index 9c4e11a..c95982d 100644
--- a/starboard/android/apk/app/src/app/AndroidManifest.xml
+++ b/starboard/android/apk/app/src/app/AndroidManifest.xml
@@ -49,6 +49,7 @@
       android:theme="@style/CobaltTheme">
       <meta-data android:name="cobalt.APP_URL" android:value="https://www.youtube.com/tv"/>
       <meta-data android:name="cobalt.SPLASH_URL" android:value="h5vcc-embedded://cobalt_splash_screen.html"/>
+      <meta-data android:name="cobalt.EVERGREEN_LITE" android:value="false"/>
       <meta-data android:name="android.app.lib_name" android:value="coat"/>
       <intent-filter>
         <action android:name="android.intent.action.MAIN"/>
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AdvertisingId.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AdvertisingId.java
index bde7982..983eec6 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AdvertisingId.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/AdvertisingId.java
@@ -17,6 +17,7 @@
 import static dev.cobalt.util.Log.TAG;
 
 import android.content.Context;
+import androidx.annotation.GuardedBy;
 import com.google.android.gms.ads.identifier.AdvertisingIdClient;
 import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
 import com.google.android.gms.common.GooglePlayServicesRepairableException;
@@ -29,27 +30,28 @@
 public class AdvertisingId {
   private final Context context;
   private final ExecutorService singleThreadExecutor;
-  private long lastRefreshed;
-  private final long cacheTtlMs = 1000 * 60 * 10; // 10 minutes.
-  private AdvertisingIdClient.Info advertisingIdInfo;
+
+  @GuardedBy("advertisingIdInfoLock")
+  private volatile AdvertisingIdClient.Info advertisingIdInfo;
+  // Controls access to advertisingIdInfo
+  private final Object advertisingIdInfoLock = new Object();
 
   public AdvertisingId(Context context) {
     this.context = context;
-    this.lastRefreshed = 0;
     this.singleThreadExecutor = Executors.newSingleThreadExecutor();
+    this.advertisingIdInfo = null;
     refresh();
   }
 
-  private void refresh() {
-    if (System.currentTimeMillis() - lastRefreshed < cacheTtlMs) {
-      // Cache is up to date.
-      return;
-    }
+  public void refresh() {
     singleThreadExecutor.execute(
         () -> {
           try {
-            advertisingIdInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
-            lastRefreshed = System.currentTimeMillis();
+            // The following statement may be slow.
+            AdvertisingIdClient.Info info = AdvertisingIdClient.getAdvertisingIdInfo(context);
+            synchronized (advertisingIdInfoLock) {
+              advertisingIdInfo = info;
+            }
             Log.i(TAG, "Successfully retrieved Advertising ID (IfA).");
           } catch (IOException
               | GooglePlayServicesNotAvailableException
@@ -61,20 +63,24 @@
 
   public String getId() {
     String result = "";
-    if (lastRefreshed != 0) {
-      result = advertisingIdInfo.getId();
-      refresh();
+    synchronized (advertisingIdInfoLock) {
+      if (advertisingIdInfo != null) {
+        result = advertisingIdInfo.getId();
+      }
     }
+    refresh();
     Log.d(TAG, "Returning IfA getId: " + result);
     return result;
   }
 
   public boolean isLimitAdTrackingEnabled() {
     boolean result = false;
-    if (lastRefreshed != 0) {
-      result = advertisingIdInfo.isLimitAdTrackingEnabled();
-      refresh();
+    synchronized (advertisingIdInfoLock) {
+      if (advertisingIdInfo != null) {
+        result = advertisingIdInfo.isLimitAdTrackingEnabled();
+      }
     }
+    refresh();
     Log.d(TAG, "Returning IfA LimitedAdTrackingEnabled: " + Boolean.toString(result));
     return result;
   }
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
index eae0f49..0592441 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
@@ -62,6 +62,9 @@
   private static final String META_FORCE_MIGRATION_FOR_STORAGE_PARTITIONING =
       "cobalt.force_migration_for_storage_partitioning";
 
+  private static final String EVERGREEN_LITE = "--evergreen_lite";
+  private static final java.lang.String META_DATA_EVERGREEN_LITE = "cobalt.EVERGREEN_LITE";
+
   @SuppressWarnings("unused")
   private CobaltA11yHelper a11yHelper;
 
@@ -220,7 +223,9 @@
     boolean hasSplashUrlArg = hasArg(args, SPLASH_URL_ARG);
     // If the splash screen topics arg isn't specified, get it from AndroidManifest.xml.
     boolean hasSplashTopicsArg = hasArg(args, SPLASH_TOPICS_ARG);
-    if (!hasUrlArg || !hasSplashUrlArg || !hasSplashTopicsArg) {
+    // If the Evergreen-Lite arg isn't specified, get it from AndroidManifest.xml.
+    boolean hasEvergreenLiteArg = hasArg(args, EVERGREEN_LITE);
+    if (!hasUrlArg || !hasSplashUrlArg || !hasSplashTopicsArg || !hasEvergreenLiteArg) {
       try {
         ActivityInfo ai =
             getPackageManager()
@@ -244,6 +249,9 @@
               args.add(SPLASH_TOPICS_ARG + splashTopics);
             }
           }
+          if (!hasEvergreenLiteArg && ai.metaData.getBoolean(META_DATA_EVERGREEN_LITE)) {
+            args.add(EVERGREEN_LITE);
+          }
           if (ai.metaData.getBoolean(META_FORCE_MIGRATION_FOR_STORAGE_PARTITIONING)) {
             args.add(FORCE_MIGRATION_FOR_STORAGE_PARTITIONING);
           }
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
index a950322..e1cf4f7 100644
--- a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -80,6 +80,7 @@
   private NetworkStatus networkStatus;
   private ResourceOverlay resourceOverlay;
   private AdvertisingId advertisingId;
+  private VolumeStateReceiver volumeStateReceiver;
 
   static {
     // Even though NativeActivity already loads our library from C++,
@@ -104,6 +105,7 @@
 
   private final HashMap<String, CobaltService.Factory> cobaltServiceFactories = new HashMap<>();
   private final HashMap<String, CobaltService> cobaltServices = new HashMap<>();
+  private final HashMap<String, String> crashContext = new HashMap<>();
 
   private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("America/Los_Angeles");
   private final long timeNanosecondsPerMicrosecond = 1000;
@@ -135,6 +137,7 @@
     this.networkStatus = new NetworkStatus(appContext);
     this.resourceOverlay = new ResourceOverlay(appContext);
     this.advertisingId = new AdvertisingId(appContext);
+    this.volumeStateReceiver = new VolumeStateReceiver(appContext);
   }
 
   private native boolean nativeInitialize();
@@ -227,6 +230,7 @@
     for (CobaltService service : cobaltServices.values()) {
       service.beforeStartOrResume();
     }
+    advertisingId.refresh();
   }
 
   @SuppressWarnings("unused")
@@ -817,4 +821,15 @@
       activity.reportFullyDrawn();
     }
   }
+
+  @SuppressWarnings("unused")
+  @UsedByNative
+  public void setCrashContext(String key, String value) {
+    Log.i(TAG, "setCrashContext Called: " + key + ", " + value);
+    crashContext.put(key, value);
+  }
+
+  public HashMap<String, String> getCrashContext() {
+    return this.crashContext;
+  }
 }
diff --git a/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VolumeStateReceiver.java b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VolumeStateReceiver.java
new file mode 100644
index 0000000..c2b94c3
--- /dev/null
+++ b/starboard/android/apk/app/src/main/java/dev/cobalt/coat/VolumeStateReceiver.java
@@ -0,0 +1,47 @@
+package dev.cobalt.coat;
+
+import static dev.cobalt.util.Log.TAG;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+/** VolumeStateReceiver monitors Android media broadcast to capture volume button events. */
+final class VolumeStateReceiver extends BroadcastReceiver {
+
+  public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
+  public static final String EXTRA_VOLUME_STREAM_VALUE = "android.media.EXTRA_VOLUME_STREAM_VALUE";
+  public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
+      "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+
+  public static final String STREAM_MUTE_CHANGED_ACTION =
+      "android.media.STREAM_MUTE_CHANGED_ACTION";
+
+  VolumeStateReceiver(Context appContext) {
+    IntentFilter filter = new IntentFilter();
+    filter.addAction(VOLUME_CHANGED_ACTION);
+    filter.addAction(STREAM_MUTE_CHANGED_ACTION);
+    appContext.registerReceiver(this, filter);
+  }
+
+  @Override
+  public void onReceive(Context context, Intent intent) {
+    if (intent.getAction().equals(VOLUME_CHANGED_ACTION)) {
+      int newVolume = intent.getIntExtra(EXTRA_VOLUME_STREAM_VALUE, 0);
+      int oldVolume = intent.getIntExtra(EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
+
+      int volumeDelta = newVolume - oldVolume;
+      Log.d(TAG, "VolumeStateReceiver capture volume changed, volumeDelta:" + volumeDelta);
+      nativeVolumeChanged(volumeDelta);
+    } else if (intent.getAction().equals(STREAM_MUTE_CHANGED_ACTION)) {
+      Log.d(TAG, "VolumeStateReceiver capture mute changed.");
+      nativeMuteChanged();
+    }
+  }
+
+  private native void nativeVolumeChanged(int volumeDelta);
+
+  private native void nativeMuteChanged();
+}
diff --git a/starboard/android/shared/BUILD.gn b/starboard/android/shared/BUILD.gn
index 806a67b..ca4c2e2 100644
--- a/starboard/android/shared/BUILD.gn
+++ b/starboard/android/shared/BUILD.gn
@@ -324,6 +324,8 @@
     "configuration.h",
     "configuration_constants.cc",
     "configuration_public.h",
+    "crash_handler.cc",
+    "crash_handler.h",
     "decode_target_create.cc",
     "decode_target_create.h",
     "decode_target_get_info.cc",
@@ -367,6 +369,8 @@
     "log_is_tty.cc",
     "log_raw.cc",
     "main.cc",
+    "max_output_buffers_lookup_table.cc",
+    "max_output_buffers_lookup_table.h",
     "media_capabilities_cache.cc",
     "media_capabilities_cache.h",
     "media_codec_bridge.cc",
@@ -487,11 +491,10 @@
   }
 
   if (sb_is_evergreen_compatible) {
-    public_deps += [ "//starboard/elf_loader:evergreen_config" ]
-
-    if (!sb_evergreen_compatible_enable_lite) {
-      public_deps += [ "//starboard/loader_app:pending_restart" ]
-    }
+    public_deps += [
+       "//starboard/elf_loader:evergreen_config",
+       "//starboard/loader_app:pending_restart",
+    ]
   }
 
   if (sb_evergreen_compatible_use_libunwind) {
diff --git a/starboard/android/shared/application_android.cc b/starboard/android/shared/application_android.cc
index cc8344b..18bf1fc 100644
--- a/starboard/android/shared/application_android.cc
+++ b/starboard/android/shared/application_android.cc
@@ -19,6 +19,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <string>
 #include <vector>
 
@@ -33,6 +34,7 @@
 #include "starboard/common/mutex.h"
 #include "starboard/common/string.h"
 #include "starboard/event.h"
+#include "starboard/key.h"
 #include "starboard/shared/starboard/audio_sink/audio_sink_internal.h"
 
 namespace starboard {
@@ -182,12 +184,21 @@
 }
 
 Event* ApplicationAndroid::WaitForSystemEventWithTimeout(SbTime time) {
+  // Limit the polling time in case some non-system event is injected.
+  const int kMaxPollingTimeMillisecond = 10;
+
   // Convert from microseconds to milliseconds, taking the ceiling value.
   // If we take the floor, or round, then we end up busy looping every time
   // the next event time is less than one millisecond.
   int timeout_millis = (time + kSbTimeMillisecond - 1) / kSbTimeMillisecond;
   int looper_events;
-  int ident = ALooper_pollAll(timeout_millis, NULL, &looper_events, NULL);
+  int ident = ALooper_pollAll(
+      std::min(std::max(timeout_millis, 0), kMaxPollingTimeMillisecond), NULL,
+      &looper_events, NULL);
+
+  // Ignore new system events while processing one.
+  handle_system_events_ = false;
+
   switch (ident) {
     case kLooperIdAndroidCommand:
       ProcessAndroidCommand();
@@ -197,6 +208,8 @@
       break;
   }
 
+  handle_system_events_ = true;
+
   // Always return NULL since we already dispatched our own system events.
   return NULL;
 }
@@ -275,12 +288,16 @@
       // early in SendAndroidCommand().
       {
         ScopedLock lock(android_command_mutex_);
-        // Cobalt can't keep running without a window, even if the Activity
-        // hasn't stopped yet. Block until conceal event has been processed.
+// Cobalt can't keep running without a window, even if the Activity
+// hasn't stopped yet. Block until conceal event has been processed.
 
-        // Only process injected events -- don't check system events since
-        // that may try to acquire the already-locked android_command_mutex_.
+// Only process injected events -- don't check system events since
+// that may try to acquire the already-locked android_command_mutex_.
+#if SB_API_VERSION >= 13
         InjectAndProcess(kSbEventTypeConceal, /* checkSystemEvents */ false);
+#else
+        InjectAndProcess(kSbEventTypeSuspend, /* checkSystemEvents */ false);
+#endif
 
         if (window_) {
           window_->native_window = NULL;
@@ -357,6 +374,7 @@
   // If there's a window, sync the app state to the Activity lifecycle.
   if (native_window_) {
     switch (sync_state) {
+#if SB_API_VERSION >= 13
       case AndroidCommand::kStart:
         Inject(new Event(kSbEventTypeReveal, NULL, NULL));
         break;
@@ -369,6 +387,20 @@
       case AndroidCommand::kStop:
         Inject(new Event(kSbEventTypeConceal, NULL, NULL));
         break;
+#else
+      case AndroidCommand::kStart:
+        Inject(new Event(kSbEventTypeResume, NULL, NULL));
+        break;
+      case AndroidCommand::kResume:
+        Inject(new Event(kSbEventTypeUnpause, NULL, NULL));
+        break;
+      case AndroidCommand::kPause:
+        Inject(new Event(kSbEventTypePause, NULL, NULL));
+        break;
+      case AndroidCommand::kStop:
+        Inject(new Event(kSbEventTypeSuspend, NULL, NULL));
+        break;
+#endif
       default:
         break;
     }
@@ -705,6 +737,20 @@
   return value;
 }
 
+extern "C" SB_EXPORT_PLATFORM void
+Java_dev_cobalt_coat_VolumeStateReceiver_nativeVolumeChanged(JNIEnv* env,
+                                                             jobject jcaller,
+                                                             jint volumeDelta) {
+  SbKey key = volumeDelta > 0 ? SbKey::kSbKeyVolumeUp : SbKey::kSbKeyVolumeDown;
+  ApplicationAndroid::Get()->SendKeyboardInject(key);
+}
+
+extern "C" SB_EXPORT_PLATFORM void
+Java_dev_cobalt_coat_VolumeStateReceiver_nativeMuteChanged(JNIEnv* env,
+                                                           jobject jcaller) {
+  ApplicationAndroid::Get()->SendKeyboardInject(SbKey::kSbKeyVolumeMute);
+}
+
 }  // namespace shared
 }  // namespace android
 }  // namespace starboard
diff --git a/starboard/android/shared/application_android.h b/starboard/android/shared/application_android.h
index 6ae871e..6cdb792 100644
--- a/starboard/android/shared/application_android.h
+++ b/starboard/android/shared/application_android.h
@@ -76,8 +76,13 @@
   bool OnSearchRequested();
   void HandleDeepLink(const char* link_url);
   void SendTTSChangedEvent() {
+#if SB_API_VERSION >= 13
     Inject(new Event(kSbEventTypeAccessibilityTextToSpeechSettingsChanged,
                      nullptr, nullptr));
+#else
+    Inject(new Event(kSbEventTypeAccessiblityTextToSpeechSettingsChanged,
+                     nullptr, nullptr));
+#endif
   }
 
   void SendAndroidCommand(AndroidCommand::CommandType type, void* data);
@@ -125,7 +130,7 @@
   void OnSuspend() override;
 
   // --- QueueApplication overrides ---
-  bool MayHaveSystemEvents() override { return true; }
+  bool MayHaveSystemEvents() override { return handle_system_events_; }
   Event* WaitForSystemEventWithTimeout(SbTime time) override;
   void WakeSystemEventWait() override;
 
@@ -139,6 +144,10 @@
   int keyboard_inject_readfd_;
   int keyboard_inject_writefd_;
 
+  // In certain situations, the Starboard thread should not try to process new
+  // system events (e.g. while one is being processed).
+  bool handle_system_events_ = true;
+
   // Synchronization for commands that change availability of Android resources
   // such as the input and/or native_window_.
   Mutex android_command_mutex_;
diff --git a/starboard/android/shared/audio_decoder.cc b/starboard/android/shared/audio_decoder.cc
index fb81100..46a6a5c 100644
--- a/starboard/android/shared/audio_decoder.cc
+++ b/starboard/android/shared/audio_decoder.cc
@@ -54,6 +54,9 @@
 
 namespace {
 
+using std::placeholders::_1;
+using std::placeholders::_2;
+
 SbMediaAudioSampleType GetSupportedSampleType() {
   SB_DCHECK(SbAudioSinkIsAudioSampleTypeSupported(
       kSbMediaAudioSampleTypeInt16Deprecated));
@@ -94,7 +97,8 @@
   output_cb_ = output_cb;
   error_cb_ = error_cb;
 
-  media_decoder_->Initialize(error_cb_);
+  media_decoder_->Initialize(
+      std::bind(&AudioDecoder::ReportError, this, _1, _2));
 }
 
 void AudioDecoder::Decode(const InputBuffers& input_buffers,
@@ -177,7 +181,8 @@
       new MediaDecoder(this, audio_codec_, audio_sample_info_, drm_system_));
   if (media_decoder_->is_valid()) {
     if (error_cb_) {
-      media_decoder_->Initialize(error_cb_);
+      media_decoder_->Initialize(
+          std::bind(&AudioDecoder::ReportError, this, _1, _2));
     }
     return true;
   }
@@ -195,7 +200,12 @@
   if (dequeue_output_result.num_bytes > 0) {
     ScopedJavaByteBuffer byte_buffer(
         media_codec_bridge->GetOutputBuffer(dequeue_output_result.index));
-    SB_DCHECK(!byte_buffer.IsNull());
+
+    if (byte_buffer.IsNull()) {
+      ReportError(kSbPlayerErrorDecode,
+                  "Failed to process audio output buffer.");
+      return;
+    }
 
     int16_t* data = static_cast<int16_t*>(IncrementPointerByBytes(
         byte_buffer.address(), dequeue_output_result.offset));
@@ -250,6 +260,17 @@
   output_channel_count_ = output_format.channel_count;
 }
 
+void AudioDecoder::ReportError(SbPlayerError error,
+                               const std::string& error_message) {
+  SB_DCHECK(error_cb_);
+
+  if (!error_cb_) {
+    return;
+  }
+
+  error_cb_(kSbPlayerErrorDecode, error_message);
+}
+
 }  // namespace shared
 }  // namespace android
 }  // namespace starboard
diff --git a/starboard/android/shared/audio_decoder.h b/starboard/android/shared/audio_decoder.h
index f9968b4..6564efd 100644
--- a/starboard/android/shared/audio_decoder.h
+++ b/starboard/android/shared/audio_decoder.h
@@ -18,6 +18,7 @@
 #include <jni.h>
 
 #include <queue>
+#include <string>
 
 #include "starboard/android/shared/drm_system.h"
 #include "starboard/android/shared/media_codec_bridge.h"
@@ -69,6 +70,8 @@
   bool Tick(MediaCodecBridge* media_codec_bridge) override { return false; }
   void OnFlushing() override {}
 
+  void ReportError(SbPlayerError error, const std::string& error_message);
+
   SbMediaAudioCodec audio_codec_;
   AudioSampleInfo audio_sample_info_;
   SbMediaAudioSampleType sample_type_;
diff --git a/starboard/android/shared/crash_handler.cc b/starboard/android/shared/crash_handler.cc
new file mode 100644
index 0000000..566bb0c
--- /dev/null
+++ b/starboard/android/shared/crash_handler.cc
@@ -0,0 +1,51 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cobalt/extension/crash_handler.h"
+#include "starboard/android/shared/crash_handler.h"
+#include "starboard/android/shared/jni_env_ext.h"
+#include "starboard/android/shared/jni_utils.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+using starboard::android::shared::JniEnvExt;
+
+bool OverrideCrashpadAnnotations(CrashpadAnnotations* crashpad_annotations) {
+  return false;  // Deprecated
+}
+
+bool SetString(const char* key, const char* value) {
+  JniEnvExt* env = JniEnvExt::Get();
+  ScopedLocalJavaRef<jstring> j_key(env->NewStringStandardUTFOrAbort(key));
+  ScopedLocalJavaRef<jstring> j_value(env->NewStringStandardUTFOrAbort(value));
+  env->CallStarboardVoidMethodOrAbort("setCrashContext",
+                                      "(Ljava/lang/String;Ljava/lang/String;)V",
+                                      j_key.Get(), j_value.Get());
+  return true;
+}
+
+const CobaltExtensionCrashHandlerApi kCrashHandlerApi = {
+    kCobaltExtensionCrashHandlerName, 2, &OverrideCrashpadAnnotations,
+    &SetString,
+};
+
+const void* GetCrashHandlerApi() {
+  return &kCrashHandlerApi;
+}
+
+}  // namespace shared
+}  // namespace android
+}  // namespace starboard
diff --git a/starboard/android/shared/crash_handler.h b/starboard/android/shared/crash_handler.h
new file mode 100644
index 0000000..fda4859
--- /dev/null
+++ b/starboard/android/shared/crash_handler.h
@@ -0,0 +1,28 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_ANDROID_SHARED_CRASH_HANDLER_H_
+#define STARBOARD_ANDROID_SHARED_CRASH_HANDLER_H_
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+const void* GetCrashHandlerApi();
+
+}  // namespace shared
+}  // namespace android
+}  // namespace starboard
+
+#endif  // STARBOARD_ANDROID_SHARED_CRASH_HANDLER_H_
diff --git a/starboard/android/shared/input_events_generator.cc b/starboard/android/shared/input_events_generator.cc
index 17805e9..81f153e 100644
--- a/starboard/android/shared/input_events_generator.cc
+++ b/starboard/android/shared/input_events_generator.cc
@@ -100,6 +100,10 @@
       input_device, "getMotionRange",
       "(I)Landroid/view/InputDevice$MotionRange;", axis));
 
+  if (motion_range.Get() == NULL) {
+    return 0.0f;
+  }
+
   float flat =
       env->CallFloatMethodOrAbort(motion_range.Get(), "getFlat", "()F");
 
diff --git a/starboard/android/shared/jni_env_ext.h b/starboard/android/shared/jni_env_ext.h
index 5a9bde9..3060918 100644
--- a/starboard/android/shared/jni_env_ext.h
+++ b/starboard/android/shared/jni_env_ext.h
@@ -139,7 +139,7 @@
     const jstring charset = NewStringUTF("UTF-8");
     AbortOnException();
     const jbyteArray byte_array = NewByteArrayFromRaw(
-        reinterpret_cast<const jbyte*>(bytes), strlen(bytes));
+        reinterpret_cast<const jbyte*>(bytes), (bytes ? strlen(bytes) : 0U));
     AbortOnException();
     jstring result = static_cast<jstring>(NewObjectOrAbort(
         "java/lang/String", "([BLjava/lang/String;)V", byte_array, charset));
diff --git a/starboard/android/shared/max_output_buffers_lookup_table.cc b/starboard/android/shared/max_output_buffers_lookup_table.cc
new file mode 100644
index 0000000..0d817bd
--- /dev/null
+++ b/starboard/android/shared/max_output_buffers_lookup_table.cc
@@ -0,0 +1,98 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/android/shared/max_output_buffers_lookup_table.h"
+
+#include "starboard/common/log.h"
+#include "starboard/common/string.h"
+#include "starboard/once.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+bool VideoOutputFormat::operator<(const VideoOutputFormat& key) const {
+  if (codec_ != key.codec_) {
+    return codec_ < key.codec_;
+  } else if (output_width_ != key.output_width_) {
+    return output_width_ < key.output_width_;
+  } else if (output_height_ != key.output_height_) {
+    return output_height_ < key.output_height_;
+  } else if (is_hdr_ != key.is_hdr_) {
+    return is_hdr_ < key.is_hdr_;
+  } else {
+    return false;
+  }
+}
+
+std::string VideoOutputFormat::ToString() const {
+  std::string info = FormatString("Video codec  = %d res = [%d x %d]", codec_,
+                                  output_width_, output_height_);
+  if (is_hdr_) {
+    info += "+ HDR";
+  }
+  return info;
+}
+
+SB_ONCE_INITIALIZE_FUNCTION(MaxMediaCodecOutputBuffersLookupTable,
+                            MaxMediaCodecOutputBuffersLookupTable::GetInstance);
+
+std::string MaxMediaCodecOutputBuffersLookupTable::DumpContent() const {
+  std::string table_content =
+      "[Preroll] MaxMediaCodecOutputBuffersLookupTable:\n";
+  for (const auto& item : lookup_table_) {
+    table_content += item.first.ToString();
+    table_content +=
+        FormatString(": max output video frame capacity = %d\n", item.second);
+  }
+  return table_content;
+}
+
+int MaxMediaCodecOutputBuffersLookupTable::GetMaxOutputVideoBuffers(
+    const VideoOutputFormat& format) const {
+  ScopedLock scoped_lock(mutex_);
+
+  auto iter = lookup_table_.find(format);
+  if (iter == lookup_table_.end() || !enable_) {
+    return -1;
+  } else {
+    return iter->second;
+  }
+}
+
+void MaxMediaCodecOutputBuffersLookupTable::SetEnabled(bool enable) {
+  ScopedLock scoped_lock(mutex_);
+
+  enable_ = enable;
+}
+
+void MaxMediaCodecOutputBuffersLookupTable::UpdateMaxOutputBuffers(
+    const VideoOutputFormat& format,
+    int max_num_of_frames) {
+  ScopedLock scoped_lock(mutex_);
+
+  if (!enable_) {
+    return;
+  }
+
+  int max_output_buffer_record = lookup_table_[format];
+  if (max_num_of_frames > max_output_buffer_record) {
+    lookup_table_[format] = max_num_of_frames;
+    SB_DLOG(INFO) << DumpContent();
+  }
+}
+
+}  // namespace shared
+}  // namespace android
+}  // namespace starboard
diff --git a/starboard/android/shared/max_output_buffers_lookup_table.h b/starboard/android/shared/max_output_buffers_lookup_table.h
new file mode 100644
index 0000000..4dddc5d
--- /dev/null
+++ b/starboard/android/shared/max_output_buffers_lookup_table.h
@@ -0,0 +1,75 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef STARBOARD_ANDROID_SHARED_MAX_OUTPUT_BUFFERS_LOOKUP_TABLE_H_
+#define STARBOARD_ANDROID_SHARED_MAX_OUTPUT_BUFFERS_LOOKUP_TABLE_H_
+
+#include <functional>
+#include <map>
+#include <string>
+
+#include "starboard/common/mutex.h"
+#include "starboard/media.h"
+
+namespace starboard {
+namespace android {
+namespace shared {
+
+class VideoOutputFormat {
+ public:
+  VideoOutputFormat(SbMediaVideoCodec codec,
+                    int output_width,
+                    int output_height,
+                    bool is_hdr)
+      : codec_(codec),
+        output_width_(output_width),
+        output_height_(output_height),
+        is_hdr_(is_hdr) {}
+
+  bool operator<(const VideoOutputFormat& key) const;
+
+  std::string ToString() const;
+
+ private:
+  SbMediaVideoCodec codec_;
+  int output_width_;
+  int output_height_;
+  bool is_hdr_;
+};
+
+class MaxMediaCodecOutputBuffersLookupTable {
+ public:
+  static MaxMediaCodecOutputBuffersLookupTable* GetInstance();
+
+  int GetMaxOutputVideoBuffers(const VideoOutputFormat& format) const;
+
+  void SetEnabled(bool enable);
+
+  void UpdateMaxOutputBuffers(const VideoOutputFormat& format,
+                              int max_num_of_frames);
+
+ private:
+  std::string DumpContent() const;
+
+  bool enable_ = true;
+
+  Mutex mutex_;
+  std::map<VideoOutputFormat, int> lookup_table_;
+};
+
+}  // namespace shared
+}  // namespace android
+}  // namespace starboard
+
+#endif  // STARBOARD_ANDROID_SHARED_MAX_OUTPUT_BUFFERS_LOOKUP_TABLE_H_
diff --git a/starboard/android/shared/media_is_video_supported.cc b/starboard/android/shared/media_is_video_supported.cc
index 9b8fcf5..8aa3101 100644
--- a/starboard/android/shared/media_is_video_supported.cc
+++ b/starboard/android/shared/media_is_video_supported.cc
@@ -14,12 +14,14 @@
 
 #include "starboard/shared/starboard/media/media_support_internal.h"
 
+#include "starboard/android/shared/max_output_buffers_lookup_table.h"
 #include "starboard/android/shared/media_capabilities_cache.h"
 #include "starboard/android/shared/media_common.h"
 #include "starboard/configuration.h"
 #include "starboard/media.h"
 #include "starboard/shared/starboard/media/media_util.h"
 
+using starboard::android::shared::MaxMediaCodecOutputBuffersLookupTable;
 using starboard::android::shared::MediaCapabilitiesCache;
 using starboard::android::shared::SupportedVideoCodecToMimeType;
 using starboard::shared::starboard::media::IsSDRVideo;
@@ -88,6 +90,14 @@
     if (mime_type->GetParamBoolValue("disablecache", false)) {
       MediaCapabilitiesCache::GetInstance()->SetCacheEnabled(false);
     }
+
+    if (!mime_type->ValidateBoolParameter("disabledynamicprerollframecount")) {
+      return false;
+    }
+    if (mime_type->GetParamBoolValue("disabledynamicprerollframecount",
+                                     false)) {
+      MaxMediaCodecOutputBuffersLookupTable::GetInstance()->SetEnabled(false);
+    }
   }
 
   if (must_support_tunnel_mode && decode_to_texture_required) {
diff --git a/starboard/android/shared/platform_service.cc b/starboard/android/shared/platform_service.cc
index 0670bc8..6bd54fa 100644
--- a/starboard/android/shared/platform_service.cc
+++ b/starboard/android/shared/platform_service.cc
@@ -14,6 +14,8 @@
 
 #include "starboard/android/shared/platform_service.h"
 
+#include <memory>
+
 #include "cobalt/extension/platform_service.h"
 #include "starboard/android/shared/jni_env_ext.h"
 #include "starboard/android/shared/jni_utils.h"
@@ -30,6 +32,10 @@
     if (name) {
       delete name;
     }
+    if (cobalt_service) {
+      starboard::android::shared::JniEnvExt::Get()->DeleteGlobalRef(
+          cobalt_service);
+    }
   }
 } CobaltExtensionPlatformServicePrivate;
 
@@ -72,7 +78,7 @@
     delete static_cast<CobaltExtensionPlatformServicePrivate*>(service);
     return kCobaltExtensionPlatformServiceInvalid;
   }
-  service->cobalt_service = cobalt_service;
+  service->cobalt_service = env->ConvertLocalRefToGlobalRef(cobalt_service);
   return service;
 }
 
@@ -99,20 +105,20 @@
   ScopedLocalJavaRef<jbyteArray> data_byte_array;
   data_byte_array.Reset(
       env->NewByteArrayFromRaw(reinterpret_cast<const jbyte*>(data), length));
-  jobject j_response_from_client =
+  ScopedLocalJavaRef<jobject> j_response_from_client(
       static_cast<jbyteArray>(env->CallObjectMethodOrAbort(
           service->cobalt_service, "receiveFromClient",
           "([B)Ldev/cobalt/coat/CobaltService$ResponseToClient;",
-          data_byte_array.Get()));
+          data_byte_array.Get())));
   if (!j_response_from_client) {
     *invalid_state = true;
     *output_length = 0;
     return 0;
   }
-  *invalid_state =
-      env->GetBooleanFieldOrAbort(j_response_from_client, "invalidState", "Z");
+  *invalid_state = env->GetBooleanFieldOrAbort(j_response_from_client.Get(),
+                                               "invalidState", "Z");
   ScopedLocalJavaRef<jbyteArray> j_out_data_array(static_cast<jbyteArray>(
-      env->GetObjectFieldOrAbort(j_response_from_client, "data", "[B")));
+      env->GetObjectFieldOrAbort(j_response_from_client.Get(), "data", "[B")));
   *output_length = env->GetArrayLength(j_out_data_array.Get());
   char* output = new char[*output_length];
   env->GetByteArrayRegion(j_out_data_array.Get(), 0, *output_length,
@@ -144,10 +150,11 @@
   }
 
   jsize length = env->GetArrayLength(j_data);
-  char* data = new char[length];
-  env->GetByteArrayRegion(j_data, 0, length, reinterpret_cast<jbyte*>(data));
+  std::unique_ptr<char[]> data(new char[length]);
+  env->GetByteArrayRegion(j_data, 0, length,
+                          reinterpret_cast<jbyte*>(data.get()));
 
-  service->receive_callback(service->context, data, length);
+  service->receive_callback(service->context, data.get(), length);
 }
 
 const void* GetPlatformServiceApi() {
diff --git a/starboard/android/shared/player_components_factory.h b/starboard/android/shared/player_components_factory.h
index 6d26909..92a2b78 100644
--- a/starboard/android/shared/player_components_factory.h
+++ b/starboard/android/shared/player_components_factory.h
@@ -100,15 +100,22 @@
                   tunnel_mode_audio_session_id, enable_audio_device_callback,
                   enable_pcm_content_type_movie, false, /* is_web_audio */
                   context);
-            }) {}
+            }),
+        tunnel_mode_audio_session_id_(tunnel_mode_audio_session_id) {}
 
  private:
   bool IsAudioSampleTypeSupported(
       SbMediaAudioSampleType audio_sample_type) const override {
-    // Currently the implementation only supports tunnel mode with int16 audio
-    // samples.
-    return audio_sample_type == kSbMediaAudioSampleTypeInt16Deprecated;
+    if (tunnel_mode_audio_session_id_ != -1) {
+      // Currently the implementation only supports tunnel mode with int16 audio
+      // samples.
+      return audio_sample_type == kSbMediaAudioSampleTypeInt16Deprecated;
+    }
+
+    return SbAudioSinkIsAudioSampleTypeSupported(audio_sample_type);
   }
+
+  const int tunnel_mode_audio_session_id_;
 };
 
 class AudioRendererSinkCallbackStub
diff --git a/starboard/android/shared/player_create.cc b/starboard/android/shared/player_create.cc
index a79fa48..480a728 100644
--- a/starboard/android/shared/player_create.cc
+++ b/starboard/android/shared/player_create.cc
@@ -16,7 +16,6 @@
 
 #include "starboard/player.h"
 
-#include "starboard/android/shared/video_decoder.h"
 #include "starboard/android/shared/video_window.h"
 #include "starboard/common/log.h"
 #include "starboard/common/media.h"
@@ -31,7 +30,6 @@
 using starboard::shared::starboard::player::filter::
     FilterBasedPlayerWorkerHandler;
 using starboard::shared::starboard::player::PlayerWorker;
-using starboard::android::shared::VideoDecoder;
 
 SbPlayer SbPlayerCreate(SbWindow window,
                         const SbPlayerCreationParam* creation_param,
@@ -179,25 +177,19 @@
     return kSbPlayerInvalid;
   }
 
-  if (strlen(max_video_capabilities) == 0) {
-    // Check the availability of hardware video decoder. Main player must use a
-    // hardware codec, but Android doesn't support multiple concurrent hardware
-    // codecs. Since it's not safe to have multiple hardware codecs, we only
-    // support one main player on Android, which can be either in punch out mode
-    // or decode to target mode.
-    const int kMaxNumberOfHardwareDecoders = 1;
-    auto number_of_hardware_decoders =
-        VideoDecoder::number_of_hardware_decoders();
-    if (number_of_hardware_decoders >= kMaxNumberOfHardwareDecoders) {
-      error_message = starboard::FormatString(
-          "Number of hardware decoders (%d) is equal to or exceeds the max "
-          "number of hardware decoders supported by this platform (%d)",
-          number_of_hardware_decoders, kMaxNumberOfHardwareDecoders);
-      SB_LOG(ERROR) << error_message << ".";
-      player_error_func(kSbPlayerInvalid, context, kSbPlayerErrorDecode,
-                        error_message.c_str());
-      return kSbPlayerInvalid;
-    }
+  // Android doesn't support multiple concurrent hardware decoders, so we can't
+  // have more than one primary player. And as secondary player is disabled on
+  // android, we simply check the number of active players here.
+  const int kMaxNumberOfPlayers = 1;
+  if (SbPlayerPrivate::number_of_players() >= kMaxNumberOfPlayers) {
+    error_message = starboard::FormatString(
+        "Failed to create a new player. Platform cannot support more than %d "
+        "players.",
+        kMaxNumberOfPlayers);
+    SB_LOG(ERROR) << error_message << ".";
+    player_error_func(kSbPlayerInvalid, context, kSbPlayerErrorDecode,
+                      error_message.c_str());
+    return kSbPlayerInvalid;
   }
 
   if (creation_param->output_mode != kSbPlayerOutputModeDecodeToTexture &&
diff --git a/starboard/android/shared/speech_synthesis_speak.cc b/starboard/android/shared/speech_synthesis_speak.cc
index b571951..23865f0 100644
--- a/starboard/android/shared/speech_synthesis_speak.cc
+++ b/starboard/android/shared/speech_synthesis_speak.cc
@@ -21,6 +21,9 @@
 using starboard::android::shared::ScopedLocalJavaRef;
 
 void SbSpeechSynthesisSpeak(const char* text) {
+  if (!text) {
+    return;
+  }
   JniEnvExt* env = JniEnvExt::Get();
   ScopedLocalJavaRef<jobject> j_tts_helper(
       env->CallStarboardObjectMethodOrAbort(
@@ -28,6 +31,6 @@
           "()Ldev/cobalt/coat/CobaltTextToSpeechHelper;"));
   ScopedLocalJavaRef<jstring> j_text_string(
       env->NewStringStandardUTFOrAbort(text));
-  env->CallVoidMethodOrAbort(j_tts_helper.Get(),
-      "speak", "(Ljava/lang/String;)V", j_text_string.Get());
+  env->CallVoidMethodOrAbort(j_tts_helper.Get(), "speak",
+                             "(Ljava/lang/String;)V", j_text_string.Get());
 }
diff --git a/starboard/android/shared/system_get_extensions.cc b/starboard/android/shared/system_get_extensions.cc
index 9d817f1..3f5e876 100644
--- a/starboard/android/shared/system_get_extensions.cc
+++ b/starboard/android/shared/system_get_extensions.cc
@@ -14,18 +14,34 @@
 
 #include "starboard/system.h"
 
+#if SB_IS(EVERGREEN_COMPATIBLE)
+#include "starboard/elf_loader/evergreen_config.h"  // nogncheck
+#endif
 #include "cobalt/extension/configuration.h"
+#include "cobalt/extension/crash_handler.h"
 #include "cobalt/extension/graphics.h"
 #include "cobalt/extension/media_session.h"
 #include "cobalt/extension/platform_service.h"
 #include "starboard/android/shared/android_media_session_client.h"
 #include "starboard/android/shared/configuration.h"
+#include "starboard/android/shared/crash_handler.h"
 #include "starboard/android/shared/graphics.h"
 #include "starboard/android/shared/platform_service.h"
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 
 const void* SbSystemGetExtension(const char* name) {
+#if SB_IS(EVERGREEN_COMPATIBLE)
+  const starboard::elf_loader::EvergreenConfig* evergreen_config =
+      starboard::elf_loader::EvergreenConfig::GetInstance();
+  if (evergreen_config != NULL &&
+      evergreen_config->custom_get_extension_ != NULL) {
+    const void* ext = evergreen_config->custom_get_extension_(name);
+    if (ext != NULL) {
+      return ext;
+    }
+  }
+#endif
   if (strcmp(name, kCobaltExtensionPlatformServiceName) == 0) {
     return starboard::android::shared::GetPlatformServiceApi();
   }
@@ -38,5 +54,8 @@
   if (strcmp(name, kCobaltExtensionGraphicsName) == 0) {
     return starboard::android::shared::GetGraphicsApi();
   }
+  if (strcmp(name, kCobaltExtensionCrashHandlerName) == 0) {
+    return starboard::android::shared::GetCrashHandlerApi();
+  }
   return NULL;
 }
diff --git a/starboard/android/shared/test_filters.py b/starboard/android/shared/test_filters.py
index e68339f..fca2878 100644
--- a/starboard/android/shared/test_filters.py
+++ b/starboard/android/shared/test_filters.py
@@ -43,7 +43,8 @@
         'PlayerComponentsTests/PlayerComponentsTest.EOSWithoutInput/*',
 
         # The e/eac3 audio time reporting during pause will be revisitied.
-        'PlayerComponentsTests/PlayerComponentsTest.Pause/15',
+        'PlayerComponentsTests/PlayerComponentsTest.Pause/*ac3*',
+        'PlayerComponentsTests/PlayerComponentsTest.Pause/*ec3*',
     ],
     'nplb': [
         # This test is failing because localhost is not defined for IPv6 in
diff --git a/starboard/android/shared/video_decoder.cc b/starboard/android/shared/video_decoder.cc
index e84cf2e..d1ce65f 100644
--- a/starboard/android/shared/video_decoder.cc
+++ b/starboard/android/shared/video_decoder.cc
@@ -52,21 +52,29 @@
 
 class VideoFrameImpl : public VideoFrame {
  public:
+  typedef std::function<void()> VideoFrameReleaseCallback;
+
   VideoFrameImpl(const DequeueOutputResult& dequeue_output_result,
-                 MediaCodecBridge* media_codec_bridge)
+                 MediaCodecBridge* media_codec_bridge,
+                 const VideoFrameReleaseCallback& release_callback)
       : VideoFrame(dequeue_output_result.flags & BUFFER_FLAG_END_OF_STREAM
                        ? kMediaTimeEndOfStream
                        : dequeue_output_result.presentation_time_microseconds),
         dequeue_output_result_(dequeue_output_result),
         media_codec_bridge_(media_codec_bridge),
-        released_(false) {
+        released_(false),
+        release_callback_(release_callback) {
     SB_DCHECK(media_codec_bridge_);
+    SB_DCHECK(release_callback_);
   }
 
   ~VideoFrameImpl() {
     if (!released_) {
       media_codec_bridge_->ReleaseOutputBuffer(dequeue_output_result_.index,
                                                false);
+      if (!is_end_of_stream()) {
+        release_callback_();
+      }
     }
   }
 
@@ -76,12 +84,14 @@
     released_ = true;
     media_codec_bridge_->ReleaseOutputBufferAtTimestamp(
         dequeue_output_result_.index, release_time_in_nanoseconds);
+    release_callback_();
   }
 
  private:
   DequeueOutputResult dequeue_output_result_;
   MediaCodecBridge* media_codec_bridge_;
   volatile bool released_;
+  const VideoFrameReleaseCallback release_callback_;
 };
 
 const SbTime kInitialPrerollTimeout = 250 * kSbTimeMillisecond;
@@ -174,8 +184,6 @@
   VideoFrameTracker* frame_tracker_;
 };
 
-int VideoDecoder::number_of_hardware_decoders_ = 0;
-
 class VideoDecoder::Sink : public VideoDecoder::VideoRendererSink {
  public:
   bool Render() {
@@ -235,7 +243,8 @@
       require_software_codec_(max_video_capabilities &&
                               strlen(max_video_capabilities) > 0),
       force_big_endian_hdr_metadata_(force_big_endian_hdr_metadata),
-      force_improved_support_check_(force_improved_support_check) {
+      force_improved_support_check_(force_improved_support_check),
+      number_of_preroll_frames_(kInitialPrerollFrameCount) {
   SB_DCHECK(error_message);
 
   if (tunnel_mode_audio_session_id != -1) {
@@ -253,9 +262,6 @@
   if (require_software_codec_) {
     SB_DCHECK(output_mode_ == kSbPlayerOutputModeDecodeToTexture);
   }
-  if (!require_software_codec_) {
-    number_of_hardware_decoders_++;
-  }
 
   if (video_codec_ != kSbMediaVideoCodecAv1) {
     if (!InitializeCodec(error_message)) {
@@ -274,10 +280,6 @@
   } else {
     ClearVideoWindow(false);
   }
-
-  if (!require_software_codec_) {
-    number_of_hardware_decoders_--;
-  }
 }
 
 scoped_refptr<VideoDecoder::VideoRendererSink> VideoDecoder::GetSink() {
@@ -327,7 +329,7 @@
   if (input_buffer_written_ > 0 && first_buffer_timestamp_ != 0) {
     return kNonInitialPrerollFrameCount;
   }
-  return kInitialPrerollFrameCount;
+  return number_of_preroll_frames_;
 }
 
 SbTime VideoDecoder::GetPrerollTimeout() const {
@@ -458,9 +460,14 @@
   TeardownCodec();
   CancelPendingJobs();
 
+  // After TeardownCodec, buffered_output_frames_ should equal to 0.
+  SB_DCHECK(buffered_output_frames_ == 0);
+
   tunnel_mode_prerolling_.store(true);
   tunnel_mode_frame_rendered_.store(false);
   input_buffer_written_ = 0;
+  decoded_output_frames_ = 0;
+  output_format_ = starboard::nullopt;
   end_of_stream_written_ = false;
   video_fps_ = 0;
   pending_input_buffers_.clear();
@@ -724,9 +731,27 @@
 
   bool is_end_of_stream =
       dequeue_output_result.flags & BUFFER_FLAG_END_OF_STREAM;
+  if (!is_end_of_stream) {
+    ++decoded_output_frames_;
+    if (output_format_) {
+      ++buffered_output_frames_;
+      // We have to wait until we feed enough inputs to the decoder and receive
+      // enough outputs before update |max_buffered_output_frames_|. Otherwise,
+      // |max_buffered_output_frames_| may be updated to a very small number
+      // when we receive the first few outputs.
+      if (decoded_output_frames_ > kInitialPrerollFrameCount &&
+          buffered_output_frames_ > max_buffered_output_frames_) {
+        max_buffered_output_frames_ = buffered_output_frames_;
+        MaxMediaCodecOutputBuffersLookupTable::GetInstance()
+            ->UpdateMaxOutputBuffers(output_format_.value(),
+                                     max_buffered_output_frames_);
+      }
+    }
+  }
   decoder_status_cb_(
       is_end_of_stream ? kBufferFull : kNeedMoreInput,
-      new VideoFrameImpl(dequeue_output_result, media_codec_bridge));
+      new VideoFrameImpl(dequeue_output_result, media_codec_bridge,
+                         std::bind(&VideoDecoder::OnVideoFrameRelease, this)));
 }
 
 void VideoDecoder::RefreshOutputFormat(MediaCodecBridge* media_codec_bridge) {
@@ -739,6 +764,29 @@
       media_codec_bridge->GetOutputDimensions();
   frame_width_ = output_dimensions.width;
   frame_height_ = output_dimensions.height;
+
+  if (tunnel_mode_audio_session_id_ != -1) {
+    return;
+  }
+  if (first_output_format_changed_) {
+    // After resolution changes, the output buffers may have frames of different
+    // resolutions. In that case, it's hard to determine the max supported
+    // output buffers. So, we reset |output_format_| to null here to skip max
+    // output buffers check.
+    output_format_ = starboard::nullopt;
+    return;
+  }
+  output_format_ = VideoOutputFormat(video_codec_, output_dimensions.width,
+                                     output_dimensions.height,
+                                     (color_metadata_ ? true : false));
+  first_output_format_changed_ = true;
+  auto max_output_buffers =
+      MaxMediaCodecOutputBuffersLookupTable::GetInstance()
+          ->GetMaxOutputVideoBuffers(output_format_.value());
+  if (max_output_buffers > 0 &&
+      max_output_buffers < kInitialPrerollFrameCount) {
+    number_of_preroll_frames_ = max_output_buffers;
+  }
 }
 
 bool VideoDecoder::Tick(MediaCodecBridge* media_codec_bridge) {
@@ -928,6 +976,13 @@
            kNeedMoreInputCheckIntervalInTunnelMode);
 }
 
+void VideoDecoder::OnVideoFrameRelease() {
+  if (output_format_) {
+    --buffered_output_frames_;
+    SB_DCHECK(buffered_output_frames_ >= 0);
+  }
+}
+
 void VideoDecoder::OnSurfaceDestroyed() {
   if (!BelongsToCurrentThread()) {
     // Wait until codec is stopped.
diff --git a/starboard/android/shared/video_decoder.h b/starboard/android/shared/video_decoder.h
index 19a8b82..a22a4df 100644
--- a/starboard/android/shared/video_decoder.h
+++ b/starboard/android/shared/video_decoder.h
@@ -16,10 +16,12 @@
 #define STARBOARD_ANDROID_SHARED_VIDEO_DECODER_H_
 
 #include <atomic>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "starboard/android/shared/drm_system.h"
+#include "starboard/android/shared/max_output_buffers_lookup_table.h"
 #include "starboard/android/shared/media_codec_bridge.h"
 #include "starboard/android/shared/media_decoder.h"
 #include "starboard/android/shared/video_frame_tracker.h"
@@ -55,10 +57,6 @@
 
   class Sink;
 
-  static int number_of_hardware_decoders() {
-    return number_of_hardware_decoders_;
-  }
-
   VideoDecoder(SbMediaVideoCodec video_codec,
                SbDrmSystem drm_system,
                SbPlayerOutputMode output_mode,
@@ -117,11 +115,11 @@
   void OnTunnelModePrerollTimeout();
   void OnTunnelModeCheckForNeedMoreInput();
 
+  void OnVideoFrameRelease();
+
   void OnSurfaceDestroyed() override;
   void ReportError(SbPlayerError error, const std::string& error_message);
 
-  static int number_of_hardware_decoders_;
-
   // These variables will be initialized inside ctor or Initialize() and will
   // not be changed during the life time of this class.
   const SbMediaVideoCodec video_codec_;
@@ -197,6 +195,15 @@
 
   std::vector<scoped_refptr<InputBuffer>> pending_input_buffers_;
   int video_fps_ = 0;
+
+  // The variables below are used to calculate platform max supported MediaCodec
+  // output buffers.
+  int decoded_output_frames_ = 0;
+  int buffered_output_frames_ = 0;
+  int max_buffered_output_frames_ = 0;
+  bool first_output_format_changed_ = false;
+  optional<VideoOutputFormat> output_format_;
+  size_t number_of_preroll_frames_;
 };
 
 }  // namespace shared
diff --git a/starboard/build/config/BUILD.gn b/starboard/build/config/BUILD.gn
index f407ee5..1f773b0 100644
--- a/starboard/build/config/BUILD.gn
+++ b/starboard/build/config/BUILD.gn
@@ -156,10 +156,6 @@
       defines += [ "SB_IS_EVERGREEN_COMPATIBLE_LIBUNWIND=1" ]
     }
 
-    if (sb_evergreen_compatible_enable_lite) {
-      defines += [ "SB_IS_EVERGREEN_COMPATIBLE_LITE=1" ]
-    }
-
     defines += [
       "STARBOARD_ATOMIC_INCLUDE=\"$starboard_path/atomic_public.h\"",
       "STARBOARD_CONFIGURATION_INCLUDE=\"$starboard_path/configuration_public.h\"",
diff --git a/starboard/build/config/base_configuration.gni b/starboard/build/config/base_configuration.gni
index bcd37d2..33b3763 100644
--- a/starboard/build/config/base_configuration.gni
+++ b/starboard/build/config/base_configuration.gni
@@ -48,9 +48,6 @@
   # Whether to use the libunwind library on Evergreen compatible platform.
   sb_evergreen_compatible_use_libunwind = false
 
-  # Whether to adopt Evergreen Lite on the Evergreen compatible platform.
-  sb_evergreen_compatible_enable_lite = false
-
   # Whether to generate the whole package containing both Loader app and Cobalt
   # core on the Evergreen compatible platform.
   sb_evergreen_compatible_package = false
diff --git a/starboard/build/config/build_assertions.gni b/starboard/build/config/build_assertions.gni
index 4162c0e..1b6844f 100644
--- a/starboard/build/config/build_assertions.gni
+++ b/starboard/build/config/build_assertions.gni
@@ -21,6 +21,3 @@
 assert(
     !sb_evergreen_compatible_use_libunwind || sb_is_evergreen_compatible,
     "Can only specify sb_evergreen_compatible_use_libunwind on an evergreen-compatible platform.")
-
-assert(!sb_evergreen_compatible_enable_lite || sb_is_evergreen_compatible,
-       "Can only enable evergreen lite on an evergreen-comptaible platform.")
diff --git a/starboard/build/doc/migration_changes.md b/starboard/build/doc/migration_changes.md
index 650d107..c63a3bf 100644
--- a/starboard/build/doc/migration_changes.md
+++ b/starboard/build/doc/migration_changes.md
@@ -20,7 +20,6 @@
 `sb_evergreen` (0/1)                      | `sb_is_evergreen` (true/false)                       | `//starboard/build/config/base_configuration.gni`
 `sb_evergreen_compatible` (0/1)           | `sb_is_evergreen_compatible` (true/false)            | `//starboard/build/config/base_configuration.gni`
 `sb_evergreen_compatible_libunwind` (0/1) | `sb_evergreen_compatible_use_libunwind` (true/false) | `//starboard/build/config/base_configuration.gni`
-`sb_evergreen_compatible_lite` (0/1)      | `sb_evergreen_compatible_enable_lite` (true/false)   | `//starboard/build/config/base_configuration.gni`
 `sb_disable_cpp14_audit`                  | (none)                                               |
 `sb_disable_microphone_idl`               | (none)                                               |
 `starboard_path`                          | (none)                                               |
diff --git a/starboard/decode_target.h b/starboard/decode_target.h
index b347070..353a565 100644
--- a/starboard/decode_target.h
+++ b/starboard/decode_target.h
@@ -342,8 +342,10 @@
 // must be called on a thread with the context
 SB_EXPORT void SbDecodeTargetRelease(SbDecodeTarget decode_target);
 
-// Writes all information about |decode_target| into |out_info|.  Returns false
-// if the provided |out_info| structure is not zero initialized.
+// Writes all information about |decode_target| into |out_info|.
+// The |decode_target| must not be kSbDecodeTargetInvalid.
+// The |out_info| pointer must not be NULL.
+// Returns false if the provided |out_info| structure is not zero initialized.
 SB_EXPORT bool SbDecodeTargetGetInfo(SbDecodeTarget decode_target,
                                      SbDecodeTargetInfo* out_info);
 
@@ -356,7 +358,9 @@
     SbDecodeTargetGraphicsContextProvider* provider,
     SbDecodeTargetGlesContextRunnerTarget target,
     void* target_context) {
-  provider->gles_context_runner(provider, target, target_context);
+  if (provider) {
+    provider->gles_context_runner(provider, target, target_context);
+  }
 }
 
 // This function is just an implementation detail of
diff --git a/starboard/drm.h b/starboard/drm.h
index 6eb68d0..1fcebb0 100644
--- a/starboard/drm.h
+++ b/starboard/drm.h
@@ -228,7 +228,7 @@
 // Creates a new DRM system that can be used when constructing an SbPlayer or an
 // SbDecoder.
 //
-// This function returns kSbDrmSystemInvalid if |key_system| is unsupported.
+// This function returns |kSbDrmSystemInvalid| if |key_system| is unsupported.
 //
 // Also see the documentation of SbDrmGenerateSessionUpdateRequest() and
 // SbDrmUpdateSession() for more details.
@@ -284,7 +284,7 @@
 //
 // |drm_system|: The DRM system that defines the key system used for the session
 // update request payload as well as the callback function that is called as a
-// result of the function being called.
+// result of the function being called. Must not be |kSbDrmSystemInvalid|.
 //
 // |ticket|: The opaque ID that allows to distinguish callbacks from multiple
 // concurrent calls to SbDrmGenerateSessionUpdateRequest(), which will be passed
@@ -293,9 +293,10 @@
 // may result in undefined behavior. The value |kSbDrmTicketInvalid| must not be
 // used.
 //
-// |type|: The case-sensitive type of the session update request payload.
-// |initialization_data|: The data for which the session update request payload
-// is created.
+// |type|: The case-sensitive type of the session update request payload. Must
+//   not be NULL.
+// |initialization_data|: The data for which the session update
+//   request payload is created. Must not be NULL.
 // |initialization_data_size|: The size of the session update request payload.
 SB_EXPORT void SbDrmGenerateSessionUpdateRequest(
     SbDrmSystem drm_system,
@@ -307,8 +308,9 @@
 // Update session with |key|, in |drm_system|'s key system, from the license
 // server response. Calls |session_updated_callback| with |context| and whether
 // the update succeeded. |context| may be used to route callbacks back to an
-// object instance.
+// object instance. The |key| must not be NULL.
 //
+// |drm_system| must not be |kSbDrmSystemInvalid|.
 // |ticket| is the opaque ID that allows to distinguish callbacks from multiple
 // concurrent calls to SbDrmUpdateSession(), which will be passed to
 // |session_updated_callback| as-is. It is the responsibility of the caller to
@@ -320,6 +322,7 @@
 //
 // |drm_system|'s |session_updated_callback| may called either from the current
 // thread before this function returns or from another thread.
+// The |session_id| must not be NULL.
 SB_EXPORT void SbDrmUpdateSession(SbDrmSystem drm_system,
                                   int ticket,
                                   const void* key,
@@ -328,6 +331,9 @@
                                   int session_id_size);
 
 // Clear any internal states/resources related to the specified |session_id|.
+//
+// |drm_system| must not be |kSbDrmSystemInvalid|.
+// |session_id| must not be NULL.
 SB_EXPORT void SbDrmCloseSession(SbDrmSystem drm_system,
                                  const void* session_id,
                                  int session_id_size);
@@ -337,6 +343,7 @@
 // during the life time of |drm_system|.
 //
 // |drm_system|: The DRM system to check if its server certificate is updatable.
+// Must not be |kSbDrmSystemInvalid|.
 SB_EXPORT bool SbDrmIsServerCertificateUpdatable(SbDrmSystem drm_system);
 
 // Update the server certificate of |drm_system|.  The function can be called
@@ -345,14 +352,15 @@
 // Note that this function should only be called after
 // |SbDrmIsServerCertificateUpdatable| is called first and returned true.
 //
-// |drm_system|: The DRM system whose server certificate is being updated.
+// |drm_system|: The DRM system whose server certificate is being updated. Must
+//   not be |kSbDrmSystemInvalid|.
 // |ticket|: The opaque ID that allows to distinguish callbacks from multiple
-// concurrent calls to SbDrmUpdateServerCertificate(), which will be passed to
-// |server_certificate_updated_callback| as-is. It is the responsibility of the
-// caller to establish ticket uniqueness, issuing multiple requests with the
-// same ticket may result in undefined behavior. The value |kSbDrmTicketInvalid|
-// must not be used.
-// |certificate|: Pointer to the server certificate data.
+//   concurrent calls to SbDrmUpdateServerCertificate(), which will be passed to
+//   |server_certificate_updated_callback| as-is. It is the responsibility of
+//   the caller to establish ticket uniqueness, issuing multiple requests with
+//   the same ticket may result in undefined behavior. The value
+//   |kSbDrmTicketInvalid| must not be used.
+// |certificate|: Pointer to the server certificate data. Must not be NULL.
 // |certificate_size|: Size of the server certificate data.
 SB_EXPORT void SbDrmUpdateServerCertificate(SbDrmSystem drm_system,
                                             int ticket,
@@ -379,7 +387,8 @@
 // It should return NULL when there is no metrics support in the underlying drm
 // system, or when the drm system implementation fails to retrieve the metrics.
 //
-// The caller will never set |size| to NULL.
+// |drm_system| must not be |kSbDrmSystemInvalid|.
+// |size| must not be NULL.
 SB_EXPORT const void* SbDrmGetMetrics(SbDrmSystem drm_system, int* size);
 
 // Destroys |drm_system|, which implicitly removes all keys installed in it and
@@ -391,7 +400,8 @@
 // result, if this function is called from a callback that is passed to
 // SbDrmCreateSystem(), a deadlock will occur.
 //
-// |drm_system|: The DRM system to be destroyed.
+// |drm_system|: The DRM system to be destroyed. Must not be
+//   |kSbDrmSystemInvalid|.
 SB_EXPORT void SbDrmDestroySystem(SbDrmSystem drm_system);
 
 #ifdef __cplusplus
diff --git a/starboard/event.h b/starboard/event.h
index 9d6e367..5b49a29 100644
--- a/starboard/event.h
+++ b/starboard/event.h
@@ -516,7 +516,7 @@
 // This function may be called from any thread, but |callback| is always
 // called from the main Starboard thread, queued with other pending events.
 //
-// |callback|: The callback function to be called.
+// |callback|: The callback function to be called. Must not be NULL.
 // |context|: The context that is passed to the |callback| function.
 // |delay|: The minimum number of microseconds to wait before calling the
 // |callback| function. Set |delay| to |0| to call the callback as soon as
diff --git a/starboard/evergreen/shared/launcher.py b/starboard/evergreen/shared/launcher.py
index e6f331d..d22f416 100644
--- a/starboard/evergreen/shared/launcher.py
+++ b/starboard/evergreen/shared/launcher.py
@@ -19,7 +19,6 @@
 
 from starboard.tools import abstract_launcher
 from starboard.tools import paths
-from starboard.tools import port_symlink
 
 _BASE_STAGING_DIRECTORY = 'evergreen_staging'
 _CRASHPAD_TARGET = 'crashpad_handler'
@@ -80,9 +79,9 @@
     # The relationship of loader platforms and configurations to evergreen
     # platforms and configurations is many-to-many. We need a separate directory
     # for each of them, i.e. linux-x64x11_debug__evergreen-x64_gold.
-    self.combined_config = '{}_{}__{}_{}'.format(self.loader_platform,
-                                                 self.loader_config, platform,
-                                                 config)
+    loader_build_name = f'{self.loader_platform}_{self.loader_config}'
+    target_build_name = f'{platform}_{config}'
+    self.combined_config = f'{loader_build_name}__{target_build_name}'
 
     self.staging_directory = os.path.join(
         os.path.dirname(self.out_directory), _BASE_STAGING_DIRECTORY,
@@ -94,8 +93,9 @@
 
     # Ensure the path, relative to the content of the ELF Loader, to the
     # Evergreen target and its content are passed as command line switches.
-    library_path_param = '--evergreen_library=app/{}/lib/lib{}'.format(
-        self.target_name, self.target_name)
+    library_path_value = os.path.join('app', self.target_name, 'lib',
+                                      f'lib{self.target_name}')
+    library_path_param = f'--evergreen_library={library_path_value}'
     if self.use_compressed_library:
       if self.target_name != 'cobalt':
         raise ValueError(
@@ -106,7 +106,7 @@
 
     target_command_line_params = [
         library_path_param,
-        '--evergreen_content=app/{}/content'.format(self.target_name)
+        f'--evergreen_content=app/{self.target_name}/content'
     ]
 
     if self.target_command_line_params:
@@ -172,16 +172,13 @@
       shutil.rmtree(self.staging_directory)
     os.makedirs(self.staging_directory)
 
-    if os.path.exists(os.path.join(self.loader_out_directory, 'install')):
-      # TODO: Make the Linux launcher run from the install_directory
-      if 'linux' in self.loader_platform:
-        self._StageTargetsAndContentsGnLinux()
-      else:
-        self._StageTargetsAndContentsGnRaspi()
+    # TODO(b/267568637): Make the Linux launcher run from the install_directory.
+    if 'linux' in self.loader_platform:
+      self._StageTargetsAndContentsLinux()
     else:
-      self._StageTargetsAndContentsGyp()
+      self._StageTargetsAndContentsRaspi()
 
-  def _StageTargetsAndContentsGnLinux(self):
+  def _StageTargetsAndContentsLinux(self):
     """Stage targets and their contents for GN builds for Linux platforms."""
     content_subdir = os.path.join('usr', 'share', 'cobalt')
 
@@ -211,14 +208,14 @@
     target_content_dst = os.path.join(target_staging_dir, 'content')
     shutil.copytree(target_content_src, target_content_dst)
 
-    shlib_name = 'lib{}'.format(self.target_name)
+    shlib_name = f'lib{self.target_name}'
     shlib_name += '.lz4' if self.use_compressed_library else '.so'
     target_binary_src = os.path.join(target_install_path, 'lib', shlib_name)
     target_binary_dst = os.path.join(target_staging_dir, 'lib', shlib_name)
     os.makedirs(os.path.join(target_staging_dir, 'lib'))
     shutil.copy(target_binary_src, target_binary_dst)
 
-  def _StageTargetsAndContentsGnRaspi(self):
+  def _StageTargetsAndContentsRaspi(self):
     """Stage targets and their contents for GN builds for Raspi platforms."""
     # TODO(b/218889313): `content` is hardcoded on raspi and must be in the same
     # directory as the binaries.
@@ -265,50 +262,13 @@
     target_content_dst = os.path.join(target_staging_dir, 'content')
     shutil.copytree(target_content_src, target_content_dst)
 
-    shlib_name = 'lib{}'.format(self.target_name)
+    shlib_name = f'lib{self.target_name}'
     shlib_name += '.lz4' if self.use_compressed_library else '.so'
     target_binary_src = os.path.join(target_install_path, 'lib', shlib_name)
     target_binary_dst = os.path.join(target_staging_dir, 'lib', shlib_name)
     os.makedirs(os.path.join(target_staging_dir, 'lib'))
     shutil.copy(target_binary_src, target_binary_dst)
 
-  def _StageTargetsAndContentsGyp(self):
-    """Stage targets and their contents for GYP builds."""
-    # <outpath>/deploy/elf_loader_sandbox
-    staging_directory_loader = os.path.join(self.staging_directory, 'deploy',
-                                            self.loader_target)
-
-    # <outpath>/deploy/elf_loader_sandbox/content/app/nplb/
-    staging_directory_evergreen = os.path.join(staging_directory_loader,
-                                               'content', 'app',
-                                               self.target_name)
-
-    # Make a hard copy of the ELF Loader's install_directory in the location
-    # specified by |staging_directory_loader|. A symbolic link here would cause
-    # future symbolic links to fall through to the original out-directories.
-    shutil.copytree(
-        os.path.join(self.loader_out_directory, 'deploy', self.loader_target),
-        staging_directory_loader)
-    shutil.copy(
-        os.path.join(self.loader_out_directory, 'deploy', _CRASHPAD_TARGET,
-                     _CRASHPAD_TARGET), staging_directory_loader)
-
-    port_symlink.MakeSymLink(
-        os.path.join(self.out_directory, 'deploy', self.target_name),
-        staging_directory_evergreen)
-
-    # TODO: Make the Linux launcher run from the install_directory, no longer
-    #       create these symlinks, and remove the NOTE from the docstring.
-    port_symlink.MakeSymLink(
-        os.path.join(staging_directory_loader, self.loader_target),
-        os.path.join(self.staging_directory, self.loader_target))
-    port_symlink.MakeSymLink(
-        os.path.join(staging_directory_loader, _CRASHPAD_TARGET),
-        os.path.join(self.staging_directory, _CRASHPAD_TARGET))
-    port_symlink.MakeSymLink(
-        os.path.join(staging_directory_loader, 'content'),
-        os.path.join(self.staging_directory, 'content'))
-
   def SupportsSuspendResume(self):
     return self.launcher.SupportsSuspendResume()
 
diff --git a/starboard/evergreen/testing/linux/deploy_cobalt.sh b/starboard/evergreen/testing/linux/deploy_cobalt.sh
index a461fae..1c3c73e 100755
--- a/starboard/evergreen/testing/linux/deploy_cobalt.sh
+++ b/starboard/evergreen/testing/linux/deploy_cobalt.sh
@@ -20,14 +20,7 @@
     exit 1
   fi
 
-  declare staging_dir=""
-  if [[ -e "${OUT}/deploy/loader_app" ]]; then
-    # Expected after launcher is run for a GYP build.
-    staging_dir="${OUT}/deploy/loader_app"
-  else
-    # Expected after launcher is run for a GN build.
-    staging_dir="${OUT}"
-  fi
+  staging_dir="${OUT}"
 
   echo " Checking '${staging_dir}'"
 
diff --git a/starboard/evergreen/testing/raspi/deploy_cobalt.sh b/starboard/evergreen/testing/raspi/deploy_cobalt.sh
index 9012f3c..930b417 100755
--- a/starboard/evergreen/testing/raspi/deploy_cobalt.sh
+++ b/starboard/evergreen/testing/raspi/deploy_cobalt.sh
@@ -20,14 +20,7 @@
     exit 1
   fi
 
-  declare staging_dir=""
-  if [[ -e "${OUT}/deploy/loader_app" ]]; then
-    # Expected after launcher is run for a GYP build.
-    staging_dir="${OUT}/deploy/loader_app"
-  else
-    # Expected after launcher is run for a GN build.
-    staging_dir="${OUT}/install/loader_app"
-  fi
+  staging_dir="${OUT}/install/loader_app"
 
   echo " Checking '${staging_dir}'"
 
diff --git a/starboard/image.h b/starboard/image.h
index 80ede0e..6352b6e 100644
--- a/starboard/image.h
+++ b/starboard/image.h
@@ -35,7 +35,7 @@
 //       return;
 //     }
 //
-//     SbDecodeTarget result_target = SbDecodeImage(provider, data, data_size,
+//     SbDecodeTarget result_target = SbImageDecode(provider, data, data_size,
 //                                                  mime_type, format);
 //
 
@@ -52,15 +52,16 @@
 #endif
 
 // Whether the current platform supports hardware accelerated decoding an
-// image of mime type |mime_type| into SbDecodeTargetFormat |format|.  The
-// result of this function must not change over the course of the program,
-// which means that the results of this function may be cached indefinitely.
+// image of mime type |mime_type| into SbDecodeTargetFormat |format|. The
+// |mime_type| must not be NULL. The result of this function must not change
+// over the course of the program, which means that the results of this function
+// may be cached indefinitely.
 SB_EXPORT bool SbImageIsDecodeSupported(const char* mime_type,
                                         SbDecodeTargetFormat format);
 
 // Attempt to decode encoded |mime_type| image data |data| of size |data_size|
 // into an SbDecodeTarget of SbDecodeFormatType |format|, possibly using
-// SbDecodeTargetProvider |provider|, if it is non-null.  Thus, four following
+// SbDecodeTargetProvider |provider|, if it is non-null. Thus, four following
 // scenarios regarding the provider may happen:
 //
 //   1. The provider is required by the |SbImageDecode| implementation and no
@@ -73,7 +74,8 @@
 //      desires.
 //   4. The provider is not required and is not passed in.  The implementation
 //      will proceed forward.
-//
+// The |data| pointer must not be NULL.
+// The |mime_type| string must not be NULL.
 // Thus, it is NOT safe for clients of this API to assume that the |provider|
 // it passes in will be called.  Finally, if the decode succeeds, a new
 // SbDecodeTarget will be allocated. If |mime_type| image decoding for the
diff --git a/starboard/linux/shared/BUILD.gn b/starboard/linux/shared/BUILD.gn
index ec8ce53..f097404 100644
--- a/starboard/linux/shared/BUILD.gn
+++ b/starboard/linux/shared/BUILD.gn
@@ -32,11 +32,10 @@
   ]
 
   if (sb_is_evergreen_compatible) {
-    public_deps += [ "//starboard/elf_loader:evergreen_config" ]
-
-    if (!sb_evergreen_compatible_enable_lite) {
-      public_deps += [ "//starboard/loader_app:pending_restart" ]
-    }
+    public_deps += [
+      "//starboard/elf_loader:evergreen_config",
+      "//starboard/loader_app:pending_restart",
+    ]
   }
 
   if (sb_evergreen_compatible_use_libunwind) {
diff --git a/starboard/linux/x64x11/system_get_property_impl.cc b/starboard/linux/x64x11/system_get_property_impl.cc
index aa33def..7442064 100644
--- a/starboard/linux/x64x11/system_get_property_impl.cc
+++ b/starboard/linux/x64x11/system_get_property_impl.cc
@@ -14,6 +14,8 @@
 
 #include "starboard/linux/x64x11/system_get_property_impl.h"
 
+#include <string>
+
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/linux/x64x11/system_properties.h"
@@ -58,31 +60,53 @@
     return false;
   }
 
+  std::string env_value;
   switch (property_id) {
     case kSbSystemPropertyBrandName:
-      return CopyStringAndTestIfSuccess(out_value, value_length, kBrandName);
+      env_value = GetEnvironment("COBALT_TESTING_BRAND_NAME");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kBrandName : env_value.c_str());
     case kSbSystemPropertyCertificationScope:
       if (kCertificationScope[0] == '\0')
         return false;
       return CopyStringAndTestIfSuccess(out_value, value_length,
                                         kCertificationScope);
     case kSbSystemPropertyChipsetModelNumber:
-      return CopyStringAndTestIfSuccess(out_value, value_length,
-                                        kChipsetModelNumber);
+      env_value = GetEnvironment("COBALT_TESTING_CHIPSET_MODEL_NUMBER");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kChipsetModelNumber : env_value.c_str());
     case kSbSystemPropertyFirmwareVersion:
-      return CopyStringAndTestIfSuccess(out_value, value_length,
-                                        kFirmwareVersion);
+      env_value = GetEnvironment("COBALT_TESTING_FIRMWARE_VERSION");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kFirmwareVersion : env_value.c_str());
     case kSbSystemPropertyFriendlyName:
-      return CopyStringAndTestIfSuccess(out_value, value_length, kFriendlyName);
+      env_value = GetEnvironment("COBALT_TESTING_FRIENDLY_NAME");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kFriendlyName : env_value.c_str());
     case kSbSystemPropertyModelName:
-      return CopyStringAndTestIfSuccess(out_value, value_length, kModelName);
+      env_value = GetEnvironment("COBALT_TESTING_MODEL_NAME");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kModelName : env_value.c_str());
     case kSbSystemPropertyModelYear:
-      return CopyStringAndTestIfSuccess(out_value, value_length, kModelYear);
+      env_value = GetEnvironment("COBALT_TESTING_MODEL_YEAR");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kModelYear : env_value.c_str());
     case kSbSystemPropertyPlatformName:
-      return CopyStringAndTestIfSuccess(out_value, value_length, kPlatformName);
+      env_value = GetEnvironment("COBALT_TESTING_PLATFORM_NAME");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kPlatformName : env_value.c_str());
     case kSbSystemPropertySystemIntegratorName:
-      return CopyStringAndTestIfSuccess(out_value, value_length,
-                                        kSystemIntegratorName);
+      env_value = GetEnvironment("COBALT_TESTING_SYSTEM_INTEGRATOR_NAME");
+      return CopyStringAndTestIfSuccess(
+          out_value, value_length,
+          env_value.empty() ? kSystemIntegratorName : env_value.c_str());
     case kSbSystemPropertySpeechApiKey:
     case kSbSystemPropertyUserAgentAuxField:
       return false;
diff --git a/starboard/loader_app/BUILD.gn b/starboard/loader_app/BUILD.gn
index 71c898c..764f33b 100644
--- a/starboard/loader_app/BUILD.gn
+++ b/starboard/loader_app/BUILD.gn
@@ -63,6 +63,18 @@
     outputs =
         [ "$sb_static_contents_output_data_dir/app/cobalt/lib/libcobalt.so" ]
   }
+  copy("copy_loader_app_manifest") {
+    install_content = true
+    if (target_cpu == "arm" && arm_float_abi == "softfp") {
+      sources = [ "$root_out_dir/../evergreen-$target_cpu-${arm_float_abi}_$build_type/manifest.json" ]
+    } else if (target_cpu == "arm64") {
+      sources =
+          [ "$root_out_dir/../evergreen-$target_cpu_$build_type/manifest.json" ]
+    } else {
+      sources = []
+    }
+    outputs = [ "$sb_static_contents_output_data_dir/app/cobalt/manifest.json" ]
+  }
 }
 
 target(final_executable_type, "loader_app") {
@@ -87,10 +99,12 @@
       data_deps += [
         ":copy_loader_app_content",
         ":copy_loader_app_lib",
+        ":copy_loader_app_manifest",
       ]
       deps += [
         ":copy_loader_app_content",
         ":copy_loader_app_lib",
+        ":copy_loader_app_manifest",
       ]
     }
   }
@@ -209,12 +223,9 @@
 
   deps = [
     ":installation_store_proto",
+    ":pending_restart",
     "//starboard",
   ]
-
-  if (!sb_evergreen_compatible_enable_lite) {
-    deps += [ ":pending_restart" ]
-  }
 }
 
 target(gtest_target_type, "installation_manager_test") {
@@ -222,13 +233,12 @@
   sources = [
     "//starboard/common/test_main.cc",
     "installation_manager_test.cc",
+    "pending_restart_test.cc",
   ]
-  if (sb_evergreen_compatible_enable_lite) {
-    sources += [ "pending_restart_test.cc" ]
-  }
   deps = [
     ":installation_manager",
     ":installation_store_proto",
+    ":pending_restart",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/starboard/log.h b/starboard/log.h
index e31c73c..e1cf08d 100644
--- a/starboard/log.h
+++ b/starboard/log.h
@@ -47,7 +47,8 @@
 //   that passing |kSbLogPriorityFatal| does not terminate the program. Such a
 //   policy must be enforced at the application level. In fact, |priority| may
 //   be completely ignored on many platforms.
-// |message|: The message to be logged. No formatting is required to be done
+// |message|: The message to be logged. Must not be NULL. No formatting is
+// required to be done
 //   on the value, including newline termination. That said, platforms can
 //   adjust the message to be more suitable for their output method by
 //   wrapping the text, stripping unprintable characters, etc.
@@ -57,7 +58,7 @@
 // from an asynchronous signal handler (e.g. a |SIGSEGV| handler). It should not
 // do any additional formatting.
 //
-// |message|: The message to be logged.
+// |message|: The message to be logged. Must not be NULL.
 SB_EXPORT void SbLogRaw(const char* message);
 
 // Dumps the stack of the current thread to the log in an async-signal-safe
diff --git a/starboard/nplb/drm_create_system_test.cc b/starboard/nplb/drm_create_system_test.cc
index bb548d0..e324fdd 100644
--- a/starboard/nplb/drm_create_system_test.cc
+++ b/starboard/nplb/drm_create_system_test.cc
@@ -35,7 +35,10 @@
                     << " is NOT valid.";
     }
     any_supported_key_systems |= SbDrmSystemIsValid(drm_system);
-    SbDrmDestroySystem(drm_system);
+
+    if (SbDrmSystemIsValid(drm_system)) {
+      SbDrmDestroySystem(drm_system);
+    }
   }
   EXPECT_TRUE(any_supported_key_systems) << " no DRM key systems supported";
 }
@@ -50,7 +53,6 @@
           DummySessionKeyStatusesChangedFunc, DummyServerCertificateUpdatedFunc,
           DummySessionClosedFunc);
       EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
-      SbDrmDestroySystem(drm_system);
     }
     {
       SbDrmSystem drm_system = SbDrmCreateSystem(
@@ -58,7 +60,6 @@
           NULL /*session_updated_func */, DummySessionKeyStatusesChangedFunc,
           DummyServerCertificateUpdatedFunc, DummySessionClosedFunc);
       EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
-      SbDrmDestroySystem(drm_system);
     }
     {
       SbDrmSystem drm_system = SbDrmCreateSystem(
@@ -66,7 +67,6 @@
           DummySessionUpdatedFunc, NULL /* session_key_statuses_changed_func */,
           DummyServerCertificateUpdatedFunc, DummySessionClosedFunc);
       EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
-      SbDrmDestroySystem(drm_system);
     }
     {
       SbDrmSystem drm_system = SbDrmCreateSystem(
@@ -74,7 +74,6 @@
           DummySessionUpdatedFunc, DummySessionKeyStatusesChangedFunc,
           NULL /* server_certificate_updated_func */, DummySessionClosedFunc);
       EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
-      SbDrmDestroySystem(drm_system);
     }
     {
       SbDrmSystem drm_system = SbDrmCreateSystem(
@@ -82,7 +81,6 @@
           DummySessionUpdatedFunc, DummySessionKeyStatusesChangedFunc,
           DummyServerCertificateUpdatedFunc, NULL /* session_closed_func */);
       EXPECT_FALSE(SbDrmSystemIsValid(drm_system));
-      SbDrmDestroySystem(drm_system);
     }
   }
 }
diff --git a/starboard/nplb/drm_get_metrics_test.cc b/starboard/nplb/drm_get_metrics_test.cc
index 484c1bc..7716641 100644
--- a/starboard/nplb/drm_get_metrics_test.cc
+++ b/starboard/nplb/drm_get_metrics_test.cc
@@ -40,20 +40,6 @@
   }
 }
 
-TEST(SbDrmGetMetricsTest, RainyDay) {
-  int size = -1;
-  ASSERT_FALSE(SbDrmGetMetrics(kSbDrmSystemInvalid, &size));
-
-  for (auto key_system : kKeySystems) {
-    SbDrmSystem drm_system = CreateDummyDrmSystem(key_system);
-    if (!SbDrmSystemIsValid(drm_system)) {
-      continue;
-    }
-    EXPECT_EQ(SbDrmGetMetrics(drm_system, nullptr), nullptr);
-    SbDrmDestroySystem(drm_system);
-  }
-}
-
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/starboard/nplb/drm_session_test.cc b/starboard/nplb/drm_session_test.cc
index 0e911a3..9069367 100644
--- a/starboard/nplb/drm_session_test.cc
+++ b/starboard/nplb/drm_session_test.cc
@@ -166,7 +166,9 @@
 }
 
 void SbDrmSessionTest::TearDown() {
-  SbDrmDestroySystem(drm_system_);
+  if (SbDrmSystemIsValid(drm_system_)) {
+    SbDrmDestroySystem(drm_system_);
+  }
 }
 
 void SbDrmSessionTest::CheckSessionUpdateRequestGeneratedCallback(
diff --git a/starboard/nplb/media_can_play_mime_and_key_system_test.cc b/starboard/nplb/media_can_play_mime_and_key_system_test.cc
index 7cb583e..e3746e5 100644
--- a/starboard/nplb/media_can_play_mime_and_key_system_test.cc
+++ b/starboard/nplb/media_can_play_mime_and_key_system_test.cc
@@ -757,10 +757,10 @@
 //       boost the queries of repeated mime and key system. Note that if there's
 //       any capability change, the platform need to explicitly clear the
 //       caches, otherwise they may return outdated results.
-TEST(SbMediaCanPlayMimeAndKeySystem, ValidatePerformance) {
+TEST(SbMediaCanPlayMimeAndKeySystem, FLAKY_ValidatePerformance) {
   auto test_sequential_function_calls =
       [](const SbMediaCanPlayMimeAndKeySystemParam* mime_params,
-         int num_function_calls, SbTimeMonotonic max_time_delta,
+         int num_function_calls, SbTimeMonotonic max_time_delta_per_call,
          const char* query_type) {
         const SbTimeMonotonic time_start = SbTimeGetMonotonicNow();
         for (int i = 0; i < num_function_calls; ++i) {
@@ -777,33 +777,32 @@
                      << "us total across " << num_function_calls << " calls.";
         SB_LOG(INFO) << "  Measured duration " << time_per_call
                      << "us average per call.";
-        EXPECT_LE(time_delta, max_time_delta);
+        EXPECT_LE(time_delta, max_time_delta_per_call * num_function_calls);
       };
 
   // Warmup the cache.
-  test_sequential_function_calls(
-      kWarmupQueryParams, SB_ARRAY_SIZE_INT(kWarmupQueryParams),
-      5 * kSbTimeMillisecond /* 9 calls */, "Warmup queries");
+  test_sequential_function_calls(kWarmupQueryParams,
+                                 SB_ARRAY_SIZE_INT(kWarmupQueryParams),
+                                 100 * kSbTimeMillisecond, "Warmup queries");
+
   // First round of the queries.
   test_sequential_function_calls(
-      kSdrQueryParams, SB_ARRAY_SIZE_INT(kSdrQueryParams),
-      10 * kSbTimeMillisecond /* 38 calls */, "SDR queries");
+      kSdrQueryParams, SB_ARRAY_SIZE_INT(kSdrQueryParams), 500, "SDR queries");
   test_sequential_function_calls(
-      kHdrQueryParams, SB_ARRAY_SIZE_INT(kHdrQueryParams),
-      15 * kSbTimeMillisecond /* 82 calls */, "HDR queries");
+      kHdrQueryParams, SB_ARRAY_SIZE_INT(kHdrQueryParams), 500, "HDR queries");
   test_sequential_function_calls(
-      kDrmQueryParams, SB_ARRAY_SIZE_INT(kDrmQueryParams),
-      10 * kSbTimeMillisecond /* 81 calls */, "DRM queries");
+      kDrmQueryParams, SB_ARRAY_SIZE_INT(kDrmQueryParams), 500, "DRM queries");
+
   // Second round of the queries.
-  test_sequential_function_calls(
-      kSdrQueryParams, SB_ARRAY_SIZE_INT(kSdrQueryParams),
-      5 * kSbTimeMillisecond /* 38 calls */, "Cached SDR queries");
-  test_sequential_function_calls(
-      kHdrQueryParams, SB_ARRAY_SIZE_INT(kHdrQueryParams),
-      5 * kSbTimeMillisecond /* 82 calls */, "Cached HDR queries");
-  test_sequential_function_calls(
-      kDrmQueryParams, SB_ARRAY_SIZE_INT(kDrmQueryParams),
-      5 * kSbTimeMillisecond /* 81 calls */, "Cached DRM queries");
+  test_sequential_function_calls(kSdrQueryParams,
+                                 SB_ARRAY_SIZE_INT(kSdrQueryParams), 100,
+                                 "Cached SDR queries");
+  test_sequential_function_calls(kHdrQueryParams,
+                                 SB_ARRAY_SIZE_INT(kHdrQueryParams), 100,
+                                 "Cached HDR queries");
+  test_sequential_function_calls(kDrmQueryParams,
+                                 SB_ARRAY_SIZE_INT(kDrmQueryParams), 100,
+                                 "Cached DRM queries");
 }
 
 }  // namespace
diff --git a/starboard/nplb/memory_reallocate_test.cc b/starboard/nplb/memory_reallocate_test.cc
index 1eac476..e293af5 100644
--- a/starboard/nplb/memory_reallocate_test.cc
+++ b/starboard/nplb/memory_reallocate_test.cc
@@ -107,7 +107,9 @@
   SbMemoryDeallocate(memory);
 }
 
-TEST(SbMemoryReallocateTest, ReallocatestoZero) {
+// Tests unspecified behavior, currently not stable.
+// Should be deleted or fixed.
+TEST(SbMemoryReallocateTest, DISABLED_ReallocatestoZero) {
   void* memory = SbMemoryAllocate(kSize);
   ASSERT_NE(static_cast<void*>(NULL), memory);
   memory = SbMemoryReallocate(memory, 0);
diff --git a/starboard/nplb/mutex_acquire_test.cc b/starboard/nplb/mutex_acquire_test.cc
index 81ad198..f8d78a4 100644
--- a/starboard/nplb/mutex_acquire_test.cc
+++ b/starboard/nplb/mutex_acquire_test.cc
@@ -91,6 +91,15 @@
   EXPECT_TRUE(SbMutexDestroy(&mutex));
 }
 
+TEST(SbMutexAcquireTest, RainyDayAcquireNull) {
+  SbMutexResult result = SbMutexAcquire(NULL);
+  EXPECT_EQ(kSbMutexDestroyed, result);
+}
+
+TEST(SbMutexAcquireTest, RainyDayReleaseNull) {
+  EXPECT_FALSE(SbMutexRelease(NULL));
+}
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/starboard/nplb/mutex_acquire_try_test.cc b/starboard/nplb/mutex_acquire_try_test.cc
index 4c4b471..7d78855 100644
--- a/starboard/nplb/mutex_acquire_try_test.cc
+++ b/starboard/nplb/mutex_acquire_try_test.cc
@@ -74,6 +74,11 @@
   EXPECT_TRUE(SbMutexDestroy(&mutex));
 }
 
+TEST(SbMutexAcquireTest, RainyDayAcquireTryNull) {
+  SbMutexResult result = SbMutexAcquireTry(NULL);
+  EXPECT_EQ(kSbMutexDestroyed, result);
+}
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/starboard/nplb/nplb_evergreen_compat_tests/BUILD.gn b/starboard/nplb/nplb_evergreen_compat_tests/BUILD.gn
index f22104c..397738a 100644
--- a/starboard/nplb/nplb_evergreen_compat_tests/BUILD.gn
+++ b/starboard/nplb/nplb_evergreen_compat_tests/BUILD.gn
@@ -21,17 +21,11 @@
     "crashpad_config_test.cc",
     "executable_memory_test.cc",
     "fonts_test.cc",
+    "max_file_name_test.cc",
     "sabi_test.cc",
+    "storage_test.cc",
   ]
 
-  if (!sb_evergreen_compatible_enable_lite) {
-    sources += [
-      "icu_test.cc",
-      "max_file_name_test.cc",
-      "storage_test.cc",
-    ]
-  }
-
   public_deps = [
     "//starboard",
     "//testing/gmock",
diff --git a/starboard/nplb/nplb_evergreen_compat_tests/icu_test.cc b/starboard/nplb/nplb_evergreen_compat_tests/icu_test.cc
deleted file mode 100644
index 53a99f6..0000000
--- a/starboard/nplb/nplb_evergreen_compat_tests/icu_test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Cobalt Authors. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <string>
-#include <vector>
-
-#include "starboard/common/log.h"
-#include "starboard/configuration.h"
-#include "starboard/file.h"
-#include "starboard/nplb/nplb_evergreen_compat_tests/checks.h"
-#include "starboard/system.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if SB_IS(EVERGREEN_COMPATIBLE)
-
-namespace starboard {
-namespace nplb {
-namespace nplb_evergreen_compat_tests {
-
-namespace {
-
-const char kDirName[] = "icu";
-
-TEST(IcuTest, VerifyIcuDirectory) {
-  std::vector<char> storage_dir(kSbFileMaxPath);
-  ASSERT_TRUE(SbSystemGetPath(kSbSystemPathStorageDirectory, storage_dir.data(),
-                              kSbFileMaxPath));
-
-  std::string icu_path = storage_dir.data();
-  icu_path += kSbFileSepString;
-  icu_path += kDirName;
-  ASSERT_TRUE(SbFileExists(icu_path.c_str()));
-  SbFileInfo info;
-  ASSERT_TRUE(SbFileGetPathInfo(icu_path.c_str(), &info));
-  ASSERT_TRUE(info.is_directory);
-}
-
-}  // namespace
-}  // namespace nplb_evergreen_compat_tests
-}  // namespace nplb
-}  // namespace starboard
-
-#endif  // SB_IS(EVERGREEN_COMPATIBLE)
diff --git a/starboard/nplb/player_create_test.cc b/starboard/nplb/player_create_test.cc
index 061a323..48c3aa7 100644
--- a/starboard/nplb/player_create_test.cc
+++ b/starboard/nplb/player_create_test.cc
@@ -30,7 +30,7 @@
 using ::testing::Values;
 
 class SbPlayerTest : public ::testing::TestWithParam<SbPlayerOutputMode> {
- public:
+ protected:
   SbPlayerTest() : output_mode_(GetParam()) {}
 
   void GetCurrentFrameIfSupported(SbPlayer player) {
@@ -48,7 +48,6 @@
 #endif  // SB_HAS(GLES2)
   }
 
- protected:
   FakeGraphicsContextProvider fake_graphics_context_provider_;
 
   SbPlayerOutputMode output_mode_;
diff --git a/starboard/nplb/player_write_sample_test.cc b/starboard/nplb/player_write_sample_test.cc
index 65b3b19..c5b015e 100644
--- a/starboard/nplb/player_write_sample_test.cc
+++ b/starboard/nplb/player_write_sample_test.cc
@@ -43,13 +43,12 @@
 
 class SbPlayerWriteSampleTest
     : public ::testing::TestWithParam<SbPlayerTestConfig> {
- public:
+ protected:
   SbPlayerWriteSampleTest();
 
   void SetUp() override;
   void TearDown() override;
 
- protected:
   struct CallbackEvent {
     CallbackEvent() {}
 
diff --git a/starboard/nplb/socket_accept_test.cc b/starboard/nplb/socket_accept_test.cc
index 35195bf..be933db 100644
--- a/starboard/nplb/socket_accept_test.cc
+++ b/starboard/nplb/socket_accept_test.cc
@@ -72,6 +72,10 @@
   EXPECT_TRUE(SbSocketDestroy(server_socket));
 }
 
+TEST_P(SbSocketAcceptTest, RainyDayInvalidSocket) {
+  EXPECT_EQ(kSbSocketInvalid, SbSocketAccept(kSbSocketInvalid));
+}
+
 #if SB_HAS(IPV6)
 INSTANTIATE_TEST_CASE_P(SbSocketAddressTypes,
                         SbSocketAcceptTest,
diff --git a/starboard/nplb/socket_set_options_test.cc b/starboard/nplb/socket_set_options_test.cc
index 60e0c17..b871de6 100644
--- a/starboard/nplb/socket_set_options_test.cc
+++ b/starboard/nplb/socket_set_options_test.cc
@@ -54,6 +54,16 @@
   EXPECT_TRUE(SbSocketDestroy(socket));
 }
 
+TEST_P(SbSocketSetOptionsTest, RainyDayInvalidSocket) {
+  EXPECT_FALSE(SbSocketSetReuseAddress(kSbSocketInvalid, true));
+  EXPECT_FALSE(SbSocketSetReceiveBufferSize(kSbSocketInvalid, 16 * 1024));
+  EXPECT_FALSE(SbSocketSetSendBufferSize(kSbSocketInvalid, 16 * 1024));
+  EXPECT_FALSE(
+      SbSocketSetTcpKeepAlive(kSbSocketInvalid, true, 30 * kSbTimeSecond));
+  EXPECT_FALSE(SbSocketSetTcpNoDelay(kSbSocketInvalid, true));
+  EXPECT_FALSE(SbSocketSetTcpWindowScaling(kSbSocketInvalid, true));
+}
+
 // TODO: Come up with some way to test the effects of these options.
 
 #if SB_HAS(IPV6)
diff --git a/starboard/player.h b/starboard/player.h
index cde4c7a..d38fc09 100644
--- a/starboard/player.h
+++ b/starboard/player.h
@@ -413,7 +413,7 @@
 // Note that it is not the responsibility of this function to verify whether the
 // video described by |creation_param| can be played on the platform, and the
 // implementation should try its best effort to return a valid output mode.
-// |creation_param| will never be NULL.
+// |creation_param| must not be NULL.
 SB_EXPORT SbPlayerOutputMode
 SbPlayerGetPreferredOutputMode(const SbPlayerCreationParam* creation_param);
 
@@ -425,7 +425,7 @@
 //  * No more other callbacks should be issued after this function returns.
 //  * It is not allowed to pass |player| into any other |SbPlayer| function
 //    once SbPlayerDestroy has been called on that player.
-// |player|: The player to be destroyed.
+// |player|: The player to be destroyed. Must not be |kSbPlayerInvalid|.
 SB_EXPORT void SbPlayerDestroy(SbPlayer player);
 
 // SbPlayerSeek2 is like the deprecated SbPlayerSeek, but accepts SbTime
@@ -448,6 +448,8 @@
 //   that was specified when the player was created (SbPlayerCreate).
 //
 // |player|: The SbPlayer in which the seek operation is being performed.
+//   Must not be |kSbPlayerInvalid|.
+
 // |seek_to_timestamp|: The frame at which playback should begin.
 // |ticket|: A user-supplied unique ID that is be passed to all subsequent
 //   |SbPlayerDecoderStatusFunc| calls. (That is the |decoder_status_func|
@@ -472,7 +474,9 @@
 //
 // SbPlayerWriteSample2 allows writing of multiple samples in one call.
 //
-// |player|: The player to which the sample is written.
+// |player|: The player to which the sample is written. Must not be
+//   |kSbPlayerInvalid|.
+
 // |sample_type|: The type of sample being written. See the |SbMediaType|
 //   enum in media.h.
 // |sample_infos|: A pointer to an array of SbPlayerSampleInfo with
@@ -526,7 +530,7 @@
 // frame, implementors should take care to avoid related performance concerns
 // with such frequent calls.
 //
-// |player|: The player that is being resized.
+// |player|: The player that is being resized. Must not be |kSbPlayerInvalid|.
 // |z_index|: The z-index of the player.  When the bounds of multiple players
 //            are overlapped, the one with larger z-index will be rendered on
 //            top of the ones with smaller z-index.
@@ -551,11 +555,14 @@
 // to a rate that is close to |playback_rate| which the implementation supports.
 // It returns false when the playback rate is unchanged, this can happen when
 // |playback_rate| is negative or if it is too high to support.
+//
+// |player| must not be |kSbPlayerInvalid|.
 SB_EXPORT bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate);
 
 // Sets the player's volume.
 //
-// |player|: The player in which the volume is being adjusted.
+// |player|: The player in which the volume is being adjusted. Must not be
+//   |kSbPlayerInvalid|.
 // |volume|: The new player volume. The value must be between |0.0| and |1.0|,
 //   inclusive. A value of |0.0| means that the audio should be muted, and a
 //   value of |1.0| means that it should be played at full volume.
@@ -568,7 +575,8 @@
 // |out_player_info|. This function may be called very frequently and is
 // expected to be inexpensive.
 //
-// |player|: The player about which information is being retrieved.
+// |player|: The player about which information is being retrieved. Must not be
+//   |kSbPlayerInvalid|.
 // |out_player_info|: The information retrieved for the player.
 SB_EXPORT void SbPlayerGetInfo2(SbPlayer player,
                                 SbPlayerInfo2* out_player_info2);
@@ -580,6 +588,8 @@
 // be used to eventually render the frame.  If this function is called with a
 // |player| object that was created with an output mode other than
 // kSbPlayerOutputModeDecodeToTexture, kSbDecodeTargetInvalid is returned.
+//
+// |player| must not be |kSbPlayerInvalid|.
 SB_EXPORT SbDecodeTarget SbPlayerGetCurrentFrame(SbPlayer player);
 
 #ifdef __cplusplus
diff --git a/starboard/raspi/shared/BUILD.gn b/starboard/raspi/shared/BUILD.gn
index a5653f3..c8d51f6 100644
--- a/starboard/raspi/shared/BUILD.gn
+++ b/starboard/raspi/shared/BUILD.gn
@@ -399,7 +399,7 @@
     "//starboard/shared/starboard/player/filter:filter_based_player_sources",
   ]
 
-  if (sb_is_evergreen_compatible && !sb_evergreen_compatible_enable_lite) {
+  if (sb_is_evergreen_compatible) {
     public_deps += [ "//starboard/loader_app:pending_restart" ]
   }
 
diff --git a/starboard/raspi/shared/launcher.py b/starboard/raspi/shared/launcher.py
index 3f6a2ba..ba6605b 100644
--- a/starboard/raspi/shared/launcher.py
+++ b/starboard/raspi/shared/launcher.py
@@ -112,14 +112,11 @@
     # TODO(b/218889313): This should reference the bin/ subdir when that's
     # used.
     test_dir = os.path.join(self.out_directory, 'install', self.target_name)
-    # TODO(b/216356058): Delete this conditional that's just for GYP.
-    if not os.path.isdir(test_dir):
-      test_dir = os.path.join(self.out_directory, 'deploy', self.target_name)
     test_file = self.target_name
 
     test_path = os.path.join(test_dir, test_file)
     if not os.path.isfile(test_path):
-      raise ValueError('TargetPath ({}) must be a file.'.format(test_path))
+      raise ValueError(f'TargetPath ({test_path}) must be a file.')
 
     raspi_user_hostname = Launcher._RASPI_USERNAME + '@' + self.device_id
 
@@ -131,7 +128,7 @@
     # rsync command setup
     options = '-avzLhc'
     source = test_dir + '/'
-    destination = '{}:~/{}/'.format(raspi_user_hostname, raspi_test_dir)
+    destination = f'{raspi_user_hostname}:~/{raspi_test_dir}/'
     self.rsync_command = 'rsync ' + options + ' ' + source + ' ' + destination
 
     # ssh command setup
@@ -145,19 +142,18 @@
     escaped_flags = re.subn(meta_re, r'\\\1', flags)[0]
 
     # test output tags
-    self.test_complete_tag = 'TEST-{time}'.format(time=time.time())
+    self.test_complete_tag = f'TEST-{time.time()}'
     self.test_success_tag = 'succeeded'
     self.test_failure_tag = 'failed'
 
     # test command setup
     test_base_command = raspi_test_path + ' ' + escaped_flags
-    test_success_output = ' && echo {} {}'.format(self.test_complete_tag,
-                                                  self.test_success_tag)
-    test_failure_output = ' || echo {} {}'.format(self.test_complete_tag,
-                                                  self.test_failure_tag)
-    self.test_command = '{} {} {}'.format(test_base_command,
-                                          test_success_output,
-                                          test_failure_output)
+    test_success_output = (f' && echo {self.test_complete_tag}'
+                           f'{self.test_success_tag}')
+    test_failure_output = (f' || echo {self.test_complete_tag}'
+                           f'{self.test_failure_tag}')
+    self.test_command = (f'{test_base_command} {test_success_output}'
+                         f'{test_failure_output}')
 
   def _PexpectSpawnAndConnect(self, command):
     """Spawns a process with pexpect and connect to the raspi.
@@ -238,8 +234,7 @@
           raise
 
   def _Sleep(self, val):
-    self._PexpectSendLine('sleep {};echo {}'.format(val,
-                                                    Launcher._SSH_SLEEP_SIGNAL))
+    self._PexpectSendLine(f'sleep {val};echo {Launcher._SSH_SLEEP_SIGNAL}')
     self.pexpect_process.expect([Launcher._SSH_SLEEP_SIGNAL])
 
   def _CleanupPexpectProcess(self):
@@ -334,7 +329,7 @@
       # Execute debugging commands on the first run
       first_run_commands = []
       if self.test_result_xml_path:
-        first_run_commands.append('touch {}'.format(self.test_result_xml_path))
+        first_run_commands.append(f'touch {self.test_result_xml_path}')
       first_run_commands.extend(['free -mh', 'ps -ux', 'df -h'])
       if FirstRun():
         for cmd in first_run_commands:
diff --git a/starboard/raspi/shared/test_filters.py b/starboard/raspi/shared/test_filters.py
index da172ec..9e8e146 100644
--- a/starboard/raspi/shared/test_filters.py
+++ b/starboard/raspi/shared/test_filters.py
@@ -15,6 +15,7 @@
 
 from starboard.tools.testing import test_filter
 
+# pylint: disable=line-too-long
 _FILTERED_TESTS = {
     'nplb': [
         'SbAudioSinkTest.*',
@@ -35,8 +36,8 @@
         # The implementations for the raspberry pi (0 and 2) are incomplete
         # and not meant to be a reference implementation. As such we will
         # not repair these failing tests for now.
-        'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/0',
-        'VideoDecoderTests/VideoDecoderTest.MultipleResets/0',
+        'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/beneath_the_canopy_137_avc_dmp_Punchout',
+        'VideoDecoderTests/VideoDecoderTest.MultipleResets/beneath_the_canopy_137_avc_dmp_Punchout',
         # Filter failed tests.
         'PlayerComponentsTests/PlayerComponentsTest.*',
     ],
diff --git a/starboard/shared/opus/opus_audio_decoder.cc b/starboard/shared/opus/opus_audio_decoder.cc
index 4d6867f..d420766 100644
--- a/starboard/shared/opus/opus_audio_decoder.cc
+++ b/starboard/shared/opus/opus_audio_decoder.cc
@@ -14,6 +14,8 @@
 
 #include "starboard/shared/opus/opus_audio_decoder.h"
 
+#include <algorithm>
+
 #include "starboard/common/log.h"
 #include "starboard/common/string.h"
 #include "starboard/memory.h"
@@ -91,19 +93,51 @@
                               const ConsumedCB& consumed_cb) {
   SB_DCHECK(BelongsToCurrentThread());
   SB_DCHECK(!input_buffers.empty());
+  SB_DCHECK(pending_audio_buffers_.empty());
   SB_DCHECK(output_cb_);
 
   if (stream_ended_) {
     SB_LOG(ERROR) << "Decode() is called after WriteEndOfStream() is called.";
     return;
   }
+  if (input_buffers.size() > kMinimumBuffersToDecode) {
+    std::copy(std::begin(input_buffers), std::end(input_buffers),
+              std::back_inserter(pending_audio_buffers_));
+    consumed_cb_ = consumed_cb;
+    DecodePendingBuffers();
+  } else {
+    for (const auto& input_buffer : input_buffers) {
+      if (!DecodeInternal(input_buffer)) {
+        return;
+      }
+    }
+    Schedule(consumed_cb);
+  }
+}
 
-  for (const auto& input_buffer : input_buffers) {
-    if (!DecodeInternal(input_buffer)) {
+void OpusAudioDecoder::DecodePendingBuffers() {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(!pending_audio_buffers_.empty());
+  SB_DCHECK(consumed_cb_);
+
+  for (int i = 0; i < kMinimumBuffersToDecode; ++i) {
+    if (!DecodeInternal(pending_audio_buffers_.front())) {
+      return;
+    }
+    pending_audio_buffers_.pop_front();
+    if (pending_audio_buffers_.empty()) {
+      Schedule(consumed_cb_);
+      consumed_cb_ = nullptr;
+      if (stream_ended_) {
+        Schedule(std::bind(&OpusAudioDecoder::WriteEndOfStream, this));
+        stream_ended_ = false;
+      }
       return;
     }
   }
-  Schedule(consumed_cb);
+
+  SB_DCHECK(!pending_audio_buffers_.empty());
+  Schedule(std::bind(&OpusAudioDecoder::DecodePendingBuffers, this));
 }
 
 bool OpusAudioDecoder::DecodeInternal(
@@ -111,7 +145,7 @@
   SB_DCHECK(BelongsToCurrentThread());
   SB_DCHECK(input_buffer);
   SB_DCHECK(output_cb_);
-  SB_DCHECK(!stream_ended_);
+  SB_DCHECK(!stream_ended_ || !pending_audio_buffers_.empty());
 
   scoped_refptr<DecodedAudio> decoded_audio = new DecodedAudio(
       audio_sample_info_.number_of_channels, GetSampleType(),
@@ -171,6 +205,10 @@
   // Opus has no dependent frames so we needn't flush the decoder.  Set the
   // flag to ensure that Decode() is not called when the stream is ended.
   stream_ended_ = true;
+  if (!pending_audio_buffers_.empty()) {
+    return;
+  }
+
   // Put EOS into the queue.
   decoded_audios_.push(new DecodedAudio);
 
@@ -199,6 +237,8 @@
   while (!decoded_audios_.empty()) {
     decoded_audios_.pop();
   }
+  pending_audio_buffers_.clear();
+  consumed_cb_ = nullptr;
 
   CancelPendingJobs();
 }
diff --git a/starboard/shared/opus/opus_audio_decoder.h b/starboard/shared/opus/opus_audio_decoder.h
index 09687f3..95e3407 100644
--- a/starboard/shared/opus/opus_audio_decoder.h
+++ b/starboard/shared/opus/opus_audio_decoder.h
@@ -15,6 +15,7 @@
 #ifndef STARBOARD_SHARED_OPUS_OPUS_AUDIO_DECODER_H_
 #define STARBOARD_SHARED_OPUS_OPUS_AUDIO_DECODER_H_
 
+#include <deque>
 #include <queue>
 #include <vector>
 
@@ -51,6 +52,9 @@
   void Reset() override;
 
  private:
+  static constexpr int kMinimumBuffersToDecode = 2;
+
+  void DecodePendingBuffers();
   bool DecodeInternal(const scoped_refptr<InputBuffer>& input_buffer);
   static const int kMaxOpusFramesPerAU = 9600;
 
@@ -64,6 +68,9 @@
   std::queue<scoped_refptr<DecodedAudio> > decoded_audios_;
   AudioSampleInfo audio_sample_info_;
   int frames_per_au_ = kMaxOpusFramesPerAU;
+
+  std::deque<scoped_refptr<InputBuffer>> pending_audio_buffers_;
+  ConsumedCB consumed_cb_;
 };
 
 }  // namespace opus
diff --git a/starboard/shared/speechd/speech_synthesis_speak.cc b/starboard/shared/speechd/speech_synthesis_speak.cc
index 2ea21f3..f574f16 100644
--- a/starboard/shared/speechd/speech_synthesis_speak.cc
+++ b/starboard/shared/speechd/speech_synthesis_speak.cc
@@ -19,6 +19,9 @@
 using starboard::shared::speechd::SpeechDispatcher;
 
 void SbSpeechSynthesisSpeak(const char* text) {
+  if (!text) {
+    return;
+  }
   SpeechDispatcher* speech_dispatcher = SpeechDispatcher::Get();
   if (speech_dispatcher) {
     speech_dispatcher->Speak(text);
diff --git a/starboard/shared/starboard/application.cc b/starboard/shared/starboard/application.cc
index e5f670e..5599196 100644
--- a/starboard/shared/starboard/application.cc
+++ b/starboard/shared/starboard/application.cc
@@ -274,10 +274,10 @@
   // Ensure the event is deleted unless it is released.
   scoped_ptr<Event> scoped_event(event);
 
-// Ensure that we go through the the appropriate lifecycle events based on
-// the current state. If intermediate events need to be processed, use
-// HandleEventAndUpdateState() rather than Inject() for the intermediate events
-// because there may already be other lifecycle events in the queue.
+  // Ensure that we go through the the appropriate lifecycle events based on
+  // the current state. If intermediate events need to be processed, use
+  // HandleEventAndUpdateState() rather than Inject() for the intermediate
+  // events because there may already be other lifecycle events in the queue.
 
 #if SB_API_VERSION >= 13
   SbTimeMonotonic timestamp = scoped_event->event->timestamp;
@@ -650,7 +650,7 @@
 
 #if SB_API_VERSION >= 13
   return new Event(type, timestamp, start_data, &DeleteStartData);
-#else  // SB_API_VERSION >= 13
+#else   // SB_API_VERSION >= 13
   return new Event(type, start_data, &DeleteStartData);
 #endif  // SB_API_VERSION >= 13
 }
diff --git a/starboard/shared/starboard/media/media_tests.gni b/starboard/shared/starboard/media/media_tests.gni
index 38c8042..a720a48 100644
--- a/starboard/shared/starboard/media/media_tests.gni
+++ b/starboard/shared/starboard/media/media_tests.gni
@@ -15,6 +15,7 @@
 media_tests_sources = [
   "//starboard/shared/starboard/media/avc_util_test.cc",
   "//starboard/shared/starboard/media/codec_util_test.cc",
+  "//starboard/shared/starboard/media/media_util_test.cc",
   "//starboard/shared/starboard/media/mime_type_test.cc",
   "//starboard/shared/starboard/media/video_capabilities_test.cc",
   "//starboard/shared/starboard/media/vp9_util_test.cc",
diff --git a/starboard/shared/starboard/media/media_util.cc b/starboard/shared/starboard/media/media_util.cc
index 58bb7bf..8ee17fc 100644
--- a/starboard/shared/starboard/media/media_util.cc
+++ b/starboard/shared/starboard/media/media_util.cc
@@ -67,7 +67,7 @@
 }
 
 VideoSampleInfo::VideoSampleInfo() {
-  memset(this, 0, sizeof(SbMediaAudioSampleInfo));
+  memset(this, 0, sizeof(SbMediaVideoSampleInfo));
   codec = kSbMediaVideoCodecNone;
 }
 
diff --git a/starboard/shared/starboard/media/media_util_test.cc b/starboard/shared/starboard/media/media_util_test.cc
new file mode 100644
index 0000000..5c048fd
--- /dev/null
+++ b/starboard/shared/starboard/media/media_util_test.cc
@@ -0,0 +1,40 @@
+// Copyright 2023 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "starboard/shared/starboard/media/media_util.h"
+
+#include "starboard/media.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+namespace media {
+namespace {
+
+TEST(VideoSampleInfoTest, DefaultCtor) {
+  VideoSampleInfo video_sample_info;
+  EXPECT_EQ(video_sample_info.codec, kSbMediaVideoCodecNone);
+  // No other members should be accessed if `codec` is `kSbMediaVideoCodecNone`,
+  // however we still want to make sure that the pointer members are set to
+  // nullptr.
+  EXPECT_EQ(video_sample_info.mime, nullptr);
+  EXPECT_EQ(video_sample_info.max_video_capabilities, nullptr);
+}
+
+}  // namespace
+}  // namespace media
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
diff --git a/starboard/shared/starboard/memory.cc b/starboard/shared/starboard/memory.cc
index 8be6cc9..919e828 100644
--- a/starboard/shared/starboard/memory.cc
+++ b/starboard/shared/starboard/memory.cc
@@ -54,12 +54,14 @@
   // These are straight forward error messages. We use the build settings to
   // predict whether the MemoryReporter is likely to fail.
   if (!StarboardAllowsMemoryTracking()) {
-    SbLogRaw("\nMemory Reporting is disabled because this build does "
-             "not support it. Try a QA, devel or debug build.\n");
+    SbLogRaw(
+        "\nMemory Reporting is disabled because this build does "
+        "not support it. Try a QA, devel or debug build.\n");
     return false;
   } else if (LeakTraceEnabled()) {
-    SbLogRaw("\nMemory Reporting might be disabled because leak trace "
-             "(from address sanitizer?) is active.\n");
+    SbLogRaw(
+        "\nMemory Reporting might be disabled because leak trace "
+        "(from address sanitizer?) is active.\n");
     return false;
   }
   return true;
@@ -83,6 +85,11 @@
 }
 
 void* SbMemoryReallocate(void* memory, size_t size) {
+#if !defined(COBALT_BUILD_TYPE_GOLD)
+  SB_CHECK((size != 0) || (memory == nullptr))
+      << "Calling SbMemoryReallocate with a non-null pointer and size 0 is not "
+         "guaranteed to release the memory, and therefore may leak memory.";
+#endif
   SbReportDeallocation(memory);
   void* new_memory = SbMemoryReallocateImpl(memory, size);
   SbReportAllocation(new_memory, size);
@@ -136,10 +143,7 @@
   if (SB_LIKELY(!s_memory_reporter)) {
     return;
   }
-  s_memory_reporter->on_mapmem_cb(
-      s_memory_reporter->context,
-      memory,
-      size);
+  s_memory_reporter->on_mapmem_cb(s_memory_reporter->context, memory, size);
 #endif  // STARBOARD_ALLOWS_MEMORY_TRACKING
 }
 
@@ -150,10 +154,7 @@
   if (SB_LIKELY(!s_memory_reporter)) {
     return;
   }
-  s_memory_reporter->on_unmapmem_cb(
-      s_memory_reporter->context,
-      memory,
-      size);
+  s_memory_reporter->on_unmapmem_cb(s_memory_reporter->context, memory, size);
 #endif  // STARBOARD_ALLOWS_MEMORY_TRACKING
 }
 
@@ -166,10 +167,7 @@
   if (SB_LIKELY(!s_memory_reporter)) {
     return;
   }
-  s_memory_reporter->on_alloc_cb(
-      s_memory_reporter->context,
-      memory,
-      size);
+  s_memory_reporter->on_alloc_cb(s_memory_reporter->context, memory, size);
 #endif  // STARBOARD_ALLOWS_MEMORY_TRACKING
 }
 
@@ -180,9 +178,7 @@
   if (SB_LIKELY(!s_memory_reporter)) {
     return;
   }
-  s_memory_reporter->on_dealloc_cb(
-      s_memory_reporter->context,
-      memory);
+  s_memory_reporter->on_dealloc_cb(s_memory_reporter->context, memory);
 #endif  // STARBOARD_ALLOWS_MEMORY_TRACKING
 }
 
diff --git a/starboard/shared/starboard/player/BUILD.gn b/starboard/shared/starboard/player/BUILD.gn
index 997a39a..a862317 100644
--- a/starboard/shared/starboard/player/BUILD.gn
+++ b/starboard/shared/starboard/player/BUILD.gn
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import("//starboard/shared/starboard/player/testdata/sha_files.gni")
+import("//starboard/shared/starboard/player/testdata/sha1_files.gni")
 
 static_library("video_dmp") {
   check_includes = false
@@ -35,11 +35,11 @@
   script = "//tools/download_from_gcs.py"
 
   sha_sources = []
-  foreach(sha_file, sha1_files) {
+  foreach(sha1_file, sha1_files) {
     sha_sources += [ string_join("/",
                                  [
                                    "testdata",
-                                   sha_file,
+                                   sha1_file,
                                  ]) ]
   }
 
diff --git a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index 9dc1e6a..551a0ad 100644
--- a/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -12,12 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <algorithm>
 #include <cmath>
 #include <deque>
 #include <functional>
 #include <memory>
 #include <numeric>
 #include <queue>
+#include <string>
 
 #include "starboard/common/mutex.h"
 #include "starboard/common/scoped_ptr.h"
@@ -42,11 +44,11 @@
 namespace testing {
 namespace {
 
+using std::string;
+using std::vector;
 using ::testing::Bool;
 using ::testing::Combine;
 using ::testing::ValuesIn;
-using std::vector;
-using std::string;
 using video_dmp::VideoDmpReader;
 
 const SbTimeMonotonic kWaitForNextEventTimeOut = 5 * kSbTimeSecond;
@@ -289,6 +291,28 @@
   bool can_accept_more_input_ = true;
 };
 
+std::string GetAdaptiveAudioDecoderTestConfigName(
+    ::testing::TestParamInfo<std::tuple<vector<const char*>, bool>> info) {
+  std::vector<const char*> filenames(std::get<0>(info.param));
+  bool using_stub_decoder = std::get<1>(info.param);
+  std::string config_name;
+
+  for (auto name : filenames) {
+    config_name += std::string(name) + "__to__";
+  }
+  if (!config_name.empty()) {
+    // Remove trailing "__to__".
+    config_name.erase(config_name.end() - 6, config_name.end());
+
+    std::replace(config_name.begin(), config_name.end(), '.', '_');
+    if (using_stub_decoder) {
+      config_name += "__stub";
+    }
+  }
+
+  return config_name;
+}
+
 TEST_P(AdaptiveAudioDecoderTest, SingleInput) {
   SbTime playing_duration = 0;
   // Skip buffer 0, as the difference between first and second opus buffer
@@ -387,13 +411,14 @@
                            test_params.back().rend());
 
   SB_LOG_IF(INFO, test_params.empty())
-      << "Test params for AdaptiveAudioDecodeTests is empty.";
+      << "Test params for AdaptiveAudioDecoderTests is empty.";
   return test_params;
 }
 
 INSTANTIATE_TEST_CASE_P(AdaptiveAudioDecoderTests,
                         AdaptiveAudioDecoderTest,
-                        Combine(ValuesIn(GetSupportedTests()), Bool()));
+                        Combine(ValuesIn(GetSupportedTests()), Bool()),
+                        GetAdaptiveAudioDecoderTestConfigName);
 
 }  // namespace
 }  // namespace testing
diff --git a/starboard/shared/starboard/player/filter/testing/audio_channel_layout_mixer_test.cc b/starboard/shared/starboard/player/filter/testing/audio_channel_layout_mixer_test.cc
index 4dad168..56a8985 100644
--- a/starboard/shared/starboard/player/filter/testing/audio_channel_layout_mixer_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/audio_channel_layout_mixer_test.cc
@@ -12,14 +12,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "starboard/shared/starboard/player/filter/audio_channel_layout_mixer.h"
+
 #include <cmath>
 #include <functional>
 #include <numeric>
+#include <string>
 
 #include "starboard/common/ref_counted.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/shared/starboard/player/decoded_audio_internal.h"
-#include "starboard/shared/starboard/player/filter/audio_channel_layout_mixer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace starboard {
@@ -158,6 +160,22 @@
   SbMediaAudioFrameStorageType storage_type_;
 };
 
+std::string GetAudioChannelLayoutMixerTestConfigName(
+    ::testing::TestParamInfo<std::tuple<SbMediaAudioSampleType,
+                                        SbMediaAudioFrameStorageType>> info) {
+  SbMediaAudioSampleType sample_type = std::get<0>(info.param);
+  SbMediaAudioFrameStorageType frame_storage_type = std::get<1>(info.param);
+
+  return FormatString(
+      "%s_%s",
+      sample_type == kSbMediaAudioSampleTypeInt16Deprecated
+          ? "SampleTypeInt16"
+          : "SampleTypeFloat32",
+      frame_storage_type == kSbMediaAudioFrameStorageTypeInterleaved
+          ? "StorageTypeInterleaved"
+          : "StorageTypePlanar");
+}
+
 TEST_P(AudioChannelLayoutMixerTest, MixToMono) {
   scoped_ptr<AudioChannelLayoutMixer> mixer =
       AudioChannelLayoutMixer::Create(sample_type_, storage_type_, 1);
@@ -332,7 +350,8 @@
                         Combine(Values(kSbMediaAudioSampleTypeInt16Deprecated,
                                        kSbMediaAudioSampleTypeFloat32),
                                 Values(kSbMediaAudioFrameStorageTypeInterleaved,
-                                       kSbMediaAudioFrameStorageTypePlanar)));
+                                       kSbMediaAudioFrameStorageTypePlanar)),
+                        GetAudioChannelLayoutMixerTestConfigName);
 
 }  // namespace
 }  // namespace testing
diff --git a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index f778eba..2904b6a 100644
--- a/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -14,9 +14,11 @@
 
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
 
+#include <algorithm>
 #include <deque>
 #include <functional>
 #include <map>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -53,7 +55,7 @@
 const SbTimeMonotonic kWaitForNextEventTimeOut = 5 * kSbTimeSecond;
 
 class AudioDecoderTest
-    : public ::testing::TestWithParam<std::tuple<const char*, bool> > {
+    : public ::testing::TestWithParam<std::tuple<const char*, bool>> {
  public:
   AudioDecoderTest()
       : test_filename_(std::get<0>(GetParam())),
@@ -379,6 +381,16 @@
   bool first_output_received_ = false;
 };
 
+std::string GetAudioDecoderTestConfigName(
+    ::testing::TestParamInfo<std::tuple<const char*, bool>> info) {
+  std::string filename(std::get<0>(info.param));
+  bool using_stub_decoder = std::get<1>(info.param);
+
+  std::replace(filename.begin(), filename.end(), '.', '_');
+
+  return filename + (using_stub_decoder ? "__stub" : "");
+}
+
 TEST_P(AudioDecoderTest, MultiDecoders) {
   const int kDecodersToCreate = 100;
   const int kMinimumNumberOfExtraDecodersRequired = 3;
@@ -638,7 +650,8 @@
     Combine(ValuesIn(GetSupportedAudioTestFiles(kIncludeHeaac,
                                                 6,
                                                 "audiopassthrough=false")),
-            Bool()));
+            Bool()),
+    GetAudioDecoderTestConfigName);
 
 }  // namespace
 }  // namespace testing
diff --git a/starboard/shared/starboard/player/filter/testing/player_components_test.cc b/starboard/shared/starboard/player/filter/testing/player_components_test.cc
index 13e4858..b7287bb 100644
--- a/starboard/shared/starboard/player/filter/testing/player_components_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/player_components_test.cc
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "starboard/common/scoped_ptr.h"
+#include "starboard/common/string.h"
 #include "starboard/media.h"
 #include "starboard/player.h"
 #include "starboard/shared/starboard/player/filter/testing/test_util.h"
@@ -37,11 +38,11 @@
 namespace {
 
 using ::starboard::testing::FakeGraphicsContextProvider;
-using std::placeholders::_1;
-using std::placeholders::_2;
 using std::string;
 using std::unique_ptr;
 using std::vector;
+using std::placeholders::_1;
+using std::placeholders::_2;
 using ::testing::ValuesIn;
 using video_dmp::VideoDmpReader;
 
@@ -489,6 +490,22 @@
   bool video_ended_ = false;
 };
 
+std::string GetPlayerComponentsTestConfigName(
+    ::testing::TestParamInfo<PlayerComponentsTestParam> info) {
+  std::string audio_filename(std::get<0>(info.param));
+  std::string video_filename(std::get<1>(info.param));
+  SbPlayerOutputMode output_mode = std::get<2>(info.param);
+
+  std::string config_name(FormatString(
+      "%s_%s_%s", audio_filename.empty() ? "null" : audio_filename.c_str(),
+      video_filename.empty() ? "null" : video_filename.c_str(),
+      output_mode == kSbPlayerOutputModeDecodeToTexture ? "DecodeToTexture"
+                                                        : "Punchout"));
+
+  std::replace(config_name.begin(), config_name.end(), '.', '_');
+  return config_name;
+}
+
 TEST_P(PlayerComponentsTest, Preroll) {
   Seek(0);
   ASSERT_NO_FATAL_FAILURE(WriteDataUntilPrerolled());
@@ -727,7 +744,8 @@
 
 INSTANTIATE_TEST_CASE_P(PlayerComponentsTests,
                         PlayerComponentsTest,
-                        ValuesIn(GetSupportedCreationParameters()));
+                        ValuesIn(GetSupportedCreationParameters()),
+                        GetPlayerComponentsTestConfigName);
 }  // namespace
 }  // namespace testing
 }  // namespace filter
diff --git a/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc b/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
index 03f0c08..8d38b52 100644
--- a/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
+++ b/starboard/shared/starboard/player/filter/testing/video_decoder_test.cc
@@ -76,6 +76,23 @@
   VideoDecoderTestFixture fixture_;
 };
 
+std::string GetVideoDecoderTestConfigName(
+    ::testing::TestParamInfo<std::tuple<VideoTestParam, bool>> info) {
+  const char* filename = std::get<0>(std::get<0>(info.param));
+  SbPlayerOutputMode output_mode = std::get<1>(std::get<0>(info.param));
+  bool using_stub_decoder = std::get<1>(info.param);
+
+  std::string config_name(FormatString(
+      "%s_%s%s", filename,
+      output_mode == kSbPlayerOutputModeDecodeToTexture ? "DecodeToTexture"
+                                                        : "Punchout",
+      using_stub_decoder ? "__stub" : ""));
+
+  std::replace(config_name.begin(), config_name.end(), '.', '_');
+
+  return config_name;
+}
+
 TEST_P(VideoDecoderTest, PrerollFrameCount) {
   EXPECT_GT(fixture_.video_decoder()->GetPrerollFrameCount(), 0);
 }
@@ -484,7 +501,8 @@
 
 INSTANTIATE_TEST_CASE_P(VideoDecoderTests,
                         VideoDecoderTest,
-                        Combine(ValuesIn(GetSupportedVideoTests()), Bool()));
+                        Combine(ValuesIn(GetSupportedVideoTests()), Bool()),
+                        GetVideoDecoderTestConfigName);
 
 }  // namespace
 }  // namespace testing
diff --git a/starboard/shared/starboard/player/player_internal.h b/starboard/shared/starboard/player/player_internal.h
index a6ffecf..825433f 100644
--- a/starboard/shared/starboard/player/player_internal.h
+++ b/starboard/shared/starboard/player/player_internal.h
@@ -41,6 +41,8 @@
       void* context,
       starboard::scoped_ptr<PlayerWorker::Handler> player_worker_handler);
 
+  static int number_of_players() { return number_of_players_; }
+
   void Seek(SbTime seek_to_time, int ticket);
   void WriteSamples(const SbPlayerSampleInfo* sample_infos,
                     int number_of_sample_infos);
diff --git a/starboard/shared/starboard/player/testdata/sha_files.gni b/starboard/shared/starboard/player/testdata/sha1_files.gni
similarity index 100%
rename from starboard/shared/starboard/player/testdata/sha_files.gni
rename to starboard/shared/starboard/player/testdata/sha1_files.gni
diff --git a/starboard/shared/win32/dx_context_video_decoder.cc b/starboard/shared/win32/dx_context_video_decoder.cc
index 9f935c8..1ca7403 100644
--- a/starboard/shared/win32/dx_context_video_decoder.cc
+++ b/starboard/shared/win32/dx_context_video_decoder.cc
@@ -47,23 +47,21 @@
 
   intptr_t device;
   query_device(reinterpret_cast<EGLDeviceEXT>(egl_device),
-      EGL_D3D11_DEVICE_ANGLE, &device);
+               EGL_D3D11_DEVICE_ANGLE, &device);
 
-  ID3D11Device* output_dx_device = reinterpret_cast<ID3D11Device*>(device);
-  IMFDXGIDeviceManager* dxgi_device_mgr = nullptr;
+  Microsoft::WRL::ComPtr<ID3D11Device> output_dx_device =
+      reinterpret_cast<ID3D11Device*>(device);
+  Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> dxgi_device_mgr;
 
   UINT token = 0;
   result = MFCreateDXGIDeviceManager(&token, &dxgi_device_mgr);
   SB_DCHECK(result == S_OK);
   SB_DCHECK(dxgi_device_mgr);
 
-  result = dxgi_device_mgr->ResetDevice(output_dx_device, token);
+  result = dxgi_device_mgr->ResetDevice(output_dx_device.Get(), token);
   SB_DCHECK(SUCCEEDED(result));
 
-  HardwareDecoderContext output = {
-    output_dx_device,
-    dxgi_device_mgr
-  };
+  HardwareDecoderContext output = {output_dx_device, dxgi_device_mgr};
   return output;
 }
 
diff --git a/starboard/shared/win32/mutex_acquire.cc b/starboard/shared/win32/mutex_acquire.cc
index b67d6d6..4e4238f 100644
--- a/starboard/shared/win32/mutex_acquire.cc
+++ b/starboard/shared/win32/mutex_acquire.cc
@@ -19,6 +19,9 @@
 #include "starboard/shared/win32/types_internal.h"
 
 SbMutexResult SbMutexAcquire(SbMutex* mutex) {
+  if (!mutex) {
+    return kSbMutexDestroyed;
+  }
   AcquireSRWLockExclusive(SB_WIN32_INTERNAL_MUTEX(mutex));
   return kSbMutexAcquired;
 }
diff --git a/starboard/shared/win32/mutex_acquire_try.cc b/starboard/shared/win32/mutex_acquire_try.cc
index dda6942..391b6cf 100644
--- a/starboard/shared/win32/mutex_acquire_try.cc
+++ b/starboard/shared/win32/mutex_acquire_try.cc
@@ -19,6 +19,9 @@
 #include "starboard/shared/win32/types_internal.h"
 
 SbMutexResult SbMutexAcquireTry(SbMutex* mutex) {
+  if (!mutex) {
+    return kSbMutexDestroyed;
+  }
   bool result = TryAcquireSRWLockExclusive(SB_WIN32_INTERNAL_MUTEX(mutex));
   return result ? kSbMutexAcquired : kSbMutexBusy;
 }
diff --git a/starboard/shared/win32/mutex_release.cc b/starboard/shared/win32/mutex_release.cc
index 34d35e3..72fbe31 100644
--- a/starboard/shared/win32/mutex_release.cc
+++ b/starboard/shared/win32/mutex_release.cc
@@ -19,6 +19,9 @@
 #include "starboard/shared/win32/types_internal.h"
 
 bool SbMutexRelease(SbMutex* mutex) {
+  if (!mutex) {
+    return false;
+  }
   ReleaseSRWLockExclusive(SB_WIN32_INTERNAL_MUTEX(mutex));
   return true;
 }
diff --git a/starboard/socket.h b/starboard/socket.h
index 0398e75..adcd32b 100644
--- a/starboard/socket.h
+++ b/starboard/socket.h
@@ -283,7 +283,7 @@
 // persistently, so the address is unnecessary, but allowed.
 //
 // |socket|: The SbSocket from which data is read.
-// |out_data|: The data read from the socket.
+// |out_data|: The data read from the socket. Must not be NULL.
 // |data_size|: The number of bytes to read.
 // |out_source|: The source address of the packet.
 SB_EXPORT int SbSocketReceiveFrom(SbSocket socket,
@@ -304,7 +304,7 @@
 // spin).
 //
 // |socket|: The SbSocket to use to write data.
-// |data|: The data read from the socket.
+// |data|: The data written to the socket. Must not be NULL.
 // |data_size|: The number of bytes of |data| to write.
 // |destination|: The location to which data is written. This value must be
 //   |NULL| for TCP connections, which can only have a single endpoint.
diff --git a/starboard/system.h b/starboard/system.h
index 233cb4d..371a15a 100644
--- a/starboard/system.h
+++ b/starboard/system.h
@@ -620,7 +620,8 @@
 SB_EXPORT bool SbSystemSupportsResume();
 
 // Returns pointer to a constant global struct implementing the extension named
-// |name|, if it is implemented. Otherwise return NULL.
+// |name|, if it is implemented. Otherwise return NULL. The |name| string must
+// not be NULL.
 //
 // Extensions are used to implement behavior which is specific to the
 // combination of application & platform. An extension relies on a header file
@@ -641,7 +642,8 @@
 SB_EXPORT const void* SbSystemGetExtension(const char* name);
 
 // Computes a HMAC-SHA256 digest of |message| into |digest| using the
-// application's certification secret.
+// application's certification secret. The |message| and the |digest|
+// pointers must not be NULL.
 //
 // The output will be written into |digest|.  |digest_size_in_bytes| must be 32
 // (or greater), since 32-bytes will be written into it.
diff --git a/starboard/tools/testing/test_runner.py b/starboard/tools/testing/test_runner.py
index 312d634..729dbe0 100755
--- a/starboard/tools/testing/test_runner.py
+++ b/starboard/tools/testing/test_runner.py
@@ -677,7 +677,7 @@
       test_status = "SUCCEEDED"
 
       all_flaky_tests_succeeded = initial_flaky_failed_count == len(
-          flaky_passed_tests)
+          flaky_passed_tests) and initial_flaky_failed_count != 0
 
       # Always mark as FAILED if we have a non-zero return code, or failing
       # test.
diff --git a/starboard/ui_navigation.h b/starboard/ui_navigation.h
index 01754a9..4f8e55f 100644
--- a/starboard/ui_navigation.h
+++ b/starboard/ui_navigation.h
@@ -94,10 +94,14 @@
 // @verbatim
 //   | a b tx |
 //   | c d ty | @endverbatim
-typedef struct SbUiNavMatrix2x3 { float m[6]; } SbUiNavMatrix2x3;
+typedef struct SbUiNavMatrix2x3 {
+  float m[6];
+} SbUiNavMatrix2x3;
 
 // This represents a 4x4 transform matrix in row-major order.
-typedef struct SbUiNavMatrix4 { float m[16]; } SbUiNavMatrix4;
+typedef struct SbUiNavMatrix4 {
+  float m[16];
+} SbUiNavMatrix4;
 
 // This structure specifies all the callbacks which the platform UI engine
 // should invoke for various interaction events on navigation items. These
@@ -309,6 +313,7 @@
 // Retrieve the platform's UI navigation implementation. If the platform does
 // not provide one, then return false without modifying |out_interface|.
 // Otherwise, initialize all members of |out_interface| and return true.
+// The |out_interface| pointer must not be NULL.
 SB_EXPORT bool SbUiNavGetInterface(SbUiNavInterface* out_interface);
 
 #ifdef __cplusplus
diff --git a/starboard/win/win32/cobalt/configuration.py b/starboard/win/win32/cobalt/configuration.py
index e342987..0a5eaa6 100644
--- a/starboard/win/win32/cobalt/configuration.py
+++ b/starboard/win/win32/cobalt/configuration.py
@@ -24,14 +24,13 @@
     return False
 
   def GetTestFilters(self):
-    filters = super(CobaltWinWin32Configuration, self).GetTestFilters()
+    filters = super().GetTestFilters()
     for target, tests in self.__FILTERED_TESTS.items():
       filters.extend(test_filter.TestFilter(target, test) for test in tests)
     return filters
 
   def GetWebPlatformTestFilters(self):
-    filters = super(CobaltWinWin32Configuration,
-                    self).GetWebPlatformTestFilters()
+    filters = super().GetWebPlatformTestFilters()
     filters += [
         '*WebPlatformTest.Run*',
     ]
@@ -52,4 +51,8 @@
            'RasterizerSubmitCalledAtExpectedFrequencyAfterSinglePipelineSubmit'
            ),
       ],
+      'net_unittests': [
+          # Flaky test to be re-enabled after b/271006511 is fixed.
+          'CookieMonsterTest.PredicateSeesAllCookies',
+      ],
   }
diff --git a/starboard/win/win32/test_filters.py b/starboard/win/win32/test_filters.py
index 59732f3..a14fd92 100644
--- a/starboard/win/win32/test_filters.py
+++ b/starboard/win/win32/test_filters.py
@@ -29,48 +29,24 @@
         # performs an optimization that defeats the SB_C_NOINLINE 'noinline'
         # attribute.
         'SbSystemGetStackTest.SunnyDayStackDirection',
+
+        # Failures tracked by b/256160416.
+        'SbSystemGetPathTest.ReturnsRequiredPaths',
+        'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.SeekAndDestroy/audio__null__video_beneath_the_canopy_137_avc_dmp_output_DecodeToTexture',
+        'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.NoInput/audio__null__video_beneath_the_canopy_137_avc_dmp_output_DecodeToTexture',
+        'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.WriteSingleBatch/audio__null__video_beneath_the_canopy_137_avc_dmp_output_DecodeToTexture',
+        'SbPlayerWriteSampleTests/SbPlayerWriteSampleTest.WriteMultipleBatches/audio__null__video_beneath_the_canopy_137_avc_dmp_output_DecodeToTexture',
+        'SbSocketAddressTypes/SbSocketBindTest.RainyDayBadInterface/type_ipv6_filter_ipv6',
+        'SbSocketAddressTypes/SbSocketGetInterfaceAddressTest.SunnyDayDestination/type_ipv6',
+        'SbSocketAddressTypes/SbSocketGetInterfaceAddressTest.SunnyDaySourceForDestination/type_ipv6',
+        'SbSocketAddressTypes/SbSocketGetInterfaceAddressTest.SunnyDaySourceNotLoopback/type_ipv6',
+        'SbSocketAddressTypes/SbSocketResolveTest.SunnyDayFiltered/filter_ipv6_type_ipv6',
     ],
     'player_filter_tests': [
         # These tests fail on our VMs for win-win32 builds due to missing
         # or non functioning system video decoders.
-        'VideoDecoderTests/VideoDecoderTest.DecodeFullGOP/0',
-        'VideoDecoderTests/VideoDecoderTest.DecodeFullGOP/2',
-        'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/0',
-        'VideoDecoderTests/VideoDecoderTest.EndOfStreamWithoutAnyInput/2',
-        'VideoDecoderTests/VideoDecoderTest.GetCurrentDecodeTargetBeforeWriteInputBuffer/0',
-        'VideoDecoderTests/VideoDecoderTest.GetCurrentDecodeTargetBeforeWriteInputBuffer/2',
-        'VideoDecoderTests/VideoDecoderTest.HoldFramesUntilFull/0',
-        'VideoDecoderTests/VideoDecoderTest.HoldFramesUntilFull/2',
-        'VideoDecoderTests/VideoDecoderTest.MaxNumberOfCachedFrames/0',
-        'VideoDecoderTests/VideoDecoderTest.MaxNumberOfCachedFrames/2',
-        'VideoDecoderTests/VideoDecoderTest.MultipleInputs/0',
-        'VideoDecoderTests/VideoDecoderTest.MultipleInputs/2',
-        'VideoDecoderTests/VideoDecoderTest.MultipleInvalidInput/0',
-        'VideoDecoderTests/VideoDecoderTest.MultipleInvalidInput/2',
-        'VideoDecoderTests/VideoDecoderTest.MultipleResets/0',
-        'VideoDecoderTests/VideoDecoderTest.MultipleResets/2',
-        'VideoDecoderTests/VideoDecoderTest.MultipleValidInputsAfterInvalidKeyFrame/0',
-        'VideoDecoderTests/VideoDecoderTest.MultipleValidInputsAfterInvalidKeyFrame/2',
-        'VideoDecoderTests/VideoDecoderTest.OutputModeSupported/0',
-        'VideoDecoderTests/VideoDecoderTest.OutputModeSupported/2',
-        'VideoDecoderTests/VideoDecoderTest.Preroll/0',
-        'VideoDecoderTests/VideoDecoderTest.Preroll/2',
-        'VideoDecoderTests/VideoDecoderTest.PrerollFrameCount/0',
-        'VideoDecoderTests/VideoDecoderTest.PrerollFrameCount/2',
-        'VideoDecoderTests/VideoDecoderTest.PrerollTimeout/0',
-        'VideoDecoderTests/VideoDecoderTest.PrerollTimeout/2',
-        'VideoDecoderTests/VideoDecoderTest.ResetAfterInput/0',
-        'VideoDecoderTests/VideoDecoderTest.ResetAfterInput/2',
-        'VideoDecoderTests/VideoDecoderTest.ResetBeforeInput/0',
-        'VideoDecoderTests/VideoDecoderTest.ResetBeforeInput/2',
-        'VideoDecoderTests/VideoDecoderTest.SingleInput/0',
-        'VideoDecoderTests/VideoDecoderTest.SingleInput/2',
-        'VideoDecoderTests/VideoDecoderTest.SingleInvalidKeyFrame/0',
-        'VideoDecoderTests/VideoDecoderTest.SingleInvalidKeyFrame/2',
-        'VideoDecoderTests/VideoDecoderTest.ThreeMoreDecoders/0',
-        'VideoDecoderTests/VideoDecoderTest.ThreeMoreDecoders/1',
-        'VideoDecoderTests/VideoDecoderTest.ThreeMoreDecoders/2',
-        'VideoDecoderTests/VideoDecoderTest.ThreeMoreDecoders/3',
+        'VideoDecoderTests/VideoDecoderTest.*/beneath_the_canopy_137_avc_dmp_DecodeToTexture*',
+        'VideoDecoderTests/VideoDecoderTest.*/black_test_avc_1080p_30to60_fps_dmp_DecodeToTexture*',
 
         # PlayerComponentsTests fail on our VMs. Preroll callback is always not called in
         # 5 seconds, which causes timeout error.
diff --git a/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp b/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp
index 246754a..e8ef008 100644
--- a/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp
+++ b/third_party/angle/src/compiler/translator/TranslatorGLSL.cpp
@@ -318,6 +318,7 @@
         // on drivers that don't have the extension at all as it would break WebGL 1 for
         // some users.
         sink << "#extension GL_ARB_gpu_shader5 : enable\n";
+        sink << "#extension GL_EXT_gpu_shader5 : enable\n";
     }
 
     TExtensionGLSL extensionGLSL(getOutputType());
diff --git a/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp b/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp
index 75270b6..f3c47dd 100644
--- a/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/third_party/angle/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -78,6 +78,15 @@
     "share_context to eglCreateContext. Results are undefined.",
 };
 #endif  // defined(ANGLE_PLATFORM_ANDROID)
+
+const char *kIgnoredWarnings[] = {
+    // We always request GL_ARB_gpu_shader5 and GL_EXT_gpu_shader5 when compiling shaders but some
+    // drivers warn when it is not present. This ends up spamming the console on every shader
+    // compile.
+    "extension `GL_ARB_gpu_shader5' unsupported in",
+    "extension `GL_EXT_gpu_shader5' unsupported in",
+};
+
 }  // namespace
 
 static void INTERNAL_GL_APIENTRY LogGLDebugMessage(GLenum source,
@@ -192,6 +201,14 @@
         // Don't print performance warnings. They tend to be very spammy in the dEQP test suite and
         // there is very little we can do about them.
 
+        for (const char *&warn : kIgnoredWarnings)
+        {
+            if (strstr(message, warn) != nullptr)
+            {
+                return;
+            }
+        }
+
         // TODO(ynovikov): filter into WARN and INFO if INFO is ever implemented
         WARN() << std::endl
                << "\tSource: " << sourceText << std::endl
diff --git a/third_party/crashpad/wrapper/proto/crashpad_annotations.proto b/third_party/crashpad/wrapper/proto/crashpad_annotations.proto
index 8eb6205..f8b9879 100644
--- a/third_party/crashpad/wrapper/proto/crashpad_annotations.proto
+++ b/third_party/crashpad/wrapper/proto/crashpad_annotations.proto
@@ -19,7 +19,7 @@
 package crashpad.wrapper;
 
 // Annotations that can be shared between Cobalt and Crashpad handler processes.
-// Next id: 5
+// Next id: 6
 message CrashpadAnnotations {
   // The product name.
   string prod = 1;
@@ -30,6 +30,9 @@
   // The User-Agent string that identifies brand, model, etc.
   string user_agent_string = 3;
 
+  // The device series identifier that is used for device authentication.
+  string cert_scope = 5;
+
   // Annotations with keys that are unknown at compile time.
   map<string, string> runtime_annotations = 4;
 }
diff --git a/third_party/crashpad/wrapper/wrapper.cc b/third_party/crashpad/wrapper/wrapper.cc
index 700f9b7..619a17d 100644
--- a/third_party/crashpad/wrapper/wrapper.cc
+++ b/third_party/crashpad/wrapper/wrapper.cc
@@ -36,6 +36,7 @@
 const char kCrashpadVersionKey[]  = "ver";
 const char kCrashpadProductKey[]  = "prod";
 const char kCrashpadUserAgentStringKey[]  = "user_agent_string";
+const char kCrashpadCertScopeKey[] = "cert_scope";
 
 namespace {
 // TODO: Get evergreen information from installation.
@@ -164,6 +165,13 @@
     platform_info.insert({"model", value.data()});
   }
 
+  result = SbSystemGetProperty(kSbSystemPropertyCertificationScope,
+                               value.data(),
+                               kSystemPropertyMaxLength);
+  if (result) {
+    platform_info.insert({kCrashpadCertScopeKey, value.data()});
+  }
+
   return platform_info;
 }
 
@@ -183,7 +191,9 @@
   const base::FilePath default_metrics_dir;
   const std::string product_name = GetProductName();
   std::map<std::string, std::string> default_annotations = {
-      {"ver", kCrashpadVersion}, {"prod", product_name}};
+      {kCrashpadVersionKey, kCrashpadVersion},
+      {kCrashpadProductKey, product_name}
+  };
   const std::vector<std::string> default_arguments = {};
 
   const std::map<std::string, std::string> platform_info = GetPlatformInfo();
diff --git a/third_party/crashpad/wrapper/wrapper.h b/third_party/crashpad/wrapper/wrapper.h
index be60fec..9ac586e 100644
--- a/third_party/crashpad/wrapper/wrapper.h
+++ b/third_party/crashpad/wrapper/wrapper.h
@@ -24,12 +24,15 @@
 // The key name used in Crashpad for the version annotation.
 extern const char kCrashpadVersionKey[];
 
-// The key name used in Crashpad for the version annotation.
+// The key name used in Crashpad for the product annotation.
 extern const char kCrashpadProductKey[];
 
 // The key name used in Crashpad for the user_agent_string annotation.
 extern const char kCrashpadUserAgentStringKey[];
 
+// The key name used in Crashpad for the cert_scope annotation.
+extern const char kCrashpadCertScopeKey[];
+
 void InstallCrashpadHandler(bool start_at_crash);
 
 bool AddEvergreenInfoToCrashpad(EvergreenInfo evergreen_info);
diff --git a/third_party/crashpad/wrapper/wrapper_stub.cc b/third_party/crashpad/wrapper/wrapper_stub.cc
index f96dd94..e6fa75f 100644
--- a/third_party/crashpad/wrapper/wrapper_stub.cc
+++ b/third_party/crashpad/wrapper/wrapper_stub.cc
@@ -21,6 +21,7 @@
 const char kCrashpadVersionKey[]  = "";
 const char kCrashpadProductKey[]  = "";
 const char kCrashpadUserAgentStringKey[]  = "";
+const char kCrashpadCertScopeKey[] = "";
 
 void InstallCrashpadHandler(bool start_at_crash) {}
 
diff --git a/third_party/skia/include/private/SkTDArray.h b/third_party/skia/include/private/SkTDArray.h
index 59c180b..c6a0797 100644
--- a/third_party/skia/include/private/SkTDArray.h
+++ b/third_party/skia/include/private/SkTDArray.h
@@ -320,7 +320,12 @@
 
     void shrinkToFit() {
         fReserve = fCount;
-        fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
+        if (fReserve) {
+            fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
+        } else {
+            sk_free(fArray);
+            fArray = nullptr;
+        }
     }
 
 private:
diff --git a/third_party/web_platform_tests/fetch/api/request/request-error.html b/third_party/web_platform_tests/fetch/api/request/request-error.html
index d4d8b01..07ac86e 100644
--- a/third_party/web_platform_tests/fetch/api/request/request-error.html
+++ b/third_party/web_platform_tests/fetch/api/request/request-error.html
@@ -26,10 +26,12 @@
           "Expect TypeError exception");
       },"Input URL has credentials");
 
-      test(function() {
-        assert_throws(new TypeError() , function() { new Request("", {"mode" : "navigate"}); },
-          "Expect TypeError exception");
-      },"RequestInit's mode is navigate");
+      // Since request is polyfilled, it needs to be possible to create a Request with the mode
+      // 'navigate'.
+      // test(function() {
+      //   assert_throws(new TypeError() , function() { new Request("", {"mode" : "navigate"}); },
+      //     "Expect TypeError exception");
+      // },"RequestInit's mode is navigate");
 
       // Referrer is not supported due to privacy concerns.
       /*
diff --git a/third_party/web_platform_tests/fetch/api/request/request-init-001.sub.html b/third_party/web_platform_tests/fetch/api/request/request-init-001.sub.html
index 4b2cfad..53a14bd 100644
--- a/third_party/web_platform_tests/fetch/api/request/request-init-001.sub.html
+++ b/third_party/web_platform_tests/fetch/api/request/request-init-001.sub.html
@@ -49,8 +49,11 @@
                                                   "strict-origin-when-cross-origin"
                                                   ]
       };
-      var modes = {"givenValues" : ["same-origin", "no-cors", "cors"],
-                   "expectedValues" : ["same-origin", "no-cors", "cors"]
+      // Allow 'navigate' to be passed in as a valid mode to requestInit. This is
+      // necessary since Request is a polyfill and there is no other way to set
+      // mode to 'navigate'.
+      var modes = {"givenValues" : ["same-origin", "no-cors", "cors", "navigate"],
+                   "expectedValues" : ["same-origin", "no-cors", "cors", "navigate"]
       };
       var credentials = {"givenValues" : ["omit", "same-origin", "include"],
                           "expectedValues" : ["omit", "same-origin", "include"]
diff --git a/third_party/web_platform_tests/resources/testharness.js b/third_party/web_platform_tests/resources/testharness.js
index fe2eea3..49f49fc 100644
--- a/third_party/web_platform_tests/resources/testharness.js
+++ b/third_party/web_platform_tests/resources/testharness.js
@@ -551,6 +551,90 @@
     }
 
     /**
+     * Make a copy of a Promise in the current realm.
+     *
+     * @param {Promise} promise the given promise that may be from a different
+     *                          realm
+     * @returns {Promise}
+     *
+     * An arbitrary promise provided by the caller may have originated in
+     * another frame that have since navigated away, rendering the frame's
+     * document inactive. Such a promise cannot be used with `await` or
+     * Promise.resolve(), as microtasks associated with it may be prevented
+     * from being run. See https://github.com/whatwg/html/issues/5319 for a
+     * particular case.
+     *
+     * In functions we define here, there is an expectation from the caller
+     * that the promise is from the current realm, that can always be used with
+     * `await`, etc. We therefore create a new promise in this realm that
+     * inherit the value and status from the given promise.
+     */
+
+    function bring_promise_to_current_realm(promise) {
+        return new Promise(promise.then.bind(promise));
+    }
+
+    function promise_rejects_js(test, constructor, promise, description) {
+        return bring_promise_to_current_realm(promise)
+            .then(test.unreached_func("Should have rejected: " + description))
+            .catch(function(e) {
+                assert_throws_js_impl(constructor, function() { throw e },
+                                          description, "promise_rejects_js");
+            });
+    }
+
+    /**
+     * Assert that a Promise is rejected with the right DOMException.
+     *
+     * @param test the test argument passed to promise_test
+     * @param {number|string} type.  See documentation for assert_throws_dom.
+     *
+     * For the remaining arguments, there are two ways of calling
+     * promise_rejects_dom:
+     *
+     * 1) If the DOMException is expected to come from the current global, the
+     * third argument should be the promise expected to reject, and a fourth,
+     * optional, argument is the assertion description.
+     *
+     * 2) If the DOMException is expected to come from some other global, the
+     * third argument should be the DOMException constructor from that global,
+     * the fourth argument the promise expected to reject, and the fifth,
+     * optional, argument the assertion description.
+     */
+
+    function promise_rejects_dom(test, type, promiseOrConstructor, descriptionOrPromise, maybeDescription) {
+        let constructor, promise, description;
+        if (typeof promiseOrConstructor === "function" &&
+            promiseOrConstructor.name === "DOMException") {
+            constructor = promiseOrConstructor;
+            promise = descriptionOrPromise;
+            description = maybeDescription;
+        } else {
+            constructor = self.DOMException;
+            promise = promiseOrConstructor;
+            description = descriptionOrPromise;
+            assert(maybeDescription === undefined,
+                    "Too many args pased to no-constructor version of promise_rejects_dom");
+        }
+        return bring_promise_to_current_realm(promise)
+            .then(test.unreached_func("Should have rejected: " + description))
+            .catch(function(e) {
+                assert_throws_dom_impl(type, function() { throw e }, description,
+                                        "promise_rejects_dom", constructor);
+            });
+    }
+
+    function promise_rejects_exactly(test, exception, promise, description) {
+        return bring_promise_to_current_realm(promise)
+            .then(test.unreached_func("Should have rejected: " + description))
+            .catch(function(e) {
+                assert_throws_exactly_impl(exception, function() { throw e },
+                                            description, "promise_rejects_exactly");
+            });
+    }
+
+
+    /**
      * This constructor helper allows DOM events to be handled using Promises,
      * which can make it a lot easier to test a very specific series of events,
      * including ensuring that unexpected events are not fired at any point.
@@ -674,6 +758,9 @@
     expose(async_test, 'async_test');
     expose(promise_test, 'promise_test');
     expose(promise_rejects, 'promise_rejects');
+    expose(promise_rejects_js, 'promise_rejects_js');
+    expose(promise_rejects_dom, 'promise_rejects_dom');
+    expose(promise_rejects_exactly, 'promise_rejects_exactly');
     expose(generate_tests, 'generate_tests');
     expose(setup, 'setup');
     expose(done, 'done');
@@ -831,6 +918,41 @@
      * Assertions
      */
 
+    function expose_assert(f, name) {
+        function assert_wrapper(...args) {
+            let status = Test.statuses.TIMEOUT;
+            let stack = null;
+            try {
+                if (settings.debug) {
+                    console.debug("ASSERT", name, tests.current_test && tests.current_test.name, args);
+                }
+                if (tests.output) {
+                    tests.set_assert(name, args);
+                }
+                const rv = f.apply(undefined, args);
+                status = Test.statuses.PASS;
+                return rv;
+            } catch(e) {
+                if (e instanceof AssertionError) {
+                    status = Test.statuses.FAIL;
+                    stack = e.stack;
+                 } else {
+                    status = Test.statuses.ERROR;
+                 }
+                throw e;
+            } finally {
+                if (tests.output && !stack) {
+                    stack = get_stack();
+                }
+                if (tests.output) {
+                    tests.set_assert_status(status, stack);
+                }
+            }
+        }
+        expose(assert_wrapper, name);
+    }
+
+
     function assert_true(actual, description)
     {
         assert(actual === true, "assert_true", description,
@@ -1269,6 +1391,303 @@
     }
     expose(assert_throws, "assert_throws");
 
+    /**
+     * Assert a JS Error with the expected constructor is thrown.
+     *
+     * @param {object} constructor The expected exception constructor.
+     * @param {Function} func Function which should throw.
+     * @param {string} description Error description for the case that the error is not thrown.
+     */
+    function assert_throws_js(constructor, func, description)
+    {
+        assert_throws_js_impl(constructor, func, description,
+                              "assert_throws_js");
+    }
+    expose_assert(assert_throws_js, "assert_throws_js");
+
+    /**
+     * Like assert_throws_js but allows specifying the assertion type
+     * (assert_throws_js or promise_rejects_js, in practice).
+     */
+    function assert_throws_js_impl(constructor, func, description,
+                                   assertion_type)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            // Basic sanity-checks on the thrown exception.
+            assert(typeof e === "object",
+                    assertion_type, description,
+                    "${func} threw ${e} with type ${type}, not an object",
+                    {func:func, e:e, type:typeof e});
+
+            assert(e !== null,
+                    assertion_type, description,
+                    "${func} threw null, not an object",
+                    {func:func});
+
+            // Basic sanity-check on the passed-in constructor
+            assert(typeof constructor == "function",
+                    assertion_type, description,
+                    "${constructor} is not a constructor",
+                    {constructor:constructor});
+            var obj = constructor;
+            while (obj) {
+                if (typeof obj === "function" &&
+                    obj.name === "Error") {
+                    break;
+                }
+                obj = Object.getPrototypeOf(obj);
+            }
+            assert(obj != null,
+                    assertion_type, description,
+                    "${constructor} is not an Error subtype",
+                    {constructor:constructor});
+
+            // And checking that our exception is reasonable
+            assert(e.constructor === constructor &&
+                    e.name === constructor.name,
+                    assertion_type, description,
+                    "${func} threw ${actual} (${actual_name}) expected instance of ${expected} (${expected_name})",
+                    {func:func, actual:e, actual_name:e.name,
+                    expected:constructor,
+                    expected_name:constructor.name});
+        }
+    }
+
+    /**
+     * Assert a DOMException with the expected type is thrown.
+     *
+     * @param {number|string} type The expected exception name or code.  See the
+     *        table of names and codes at
+     *        https://heycam.github.io/webidl/#dfn-error-names-table
+     *        If a number is passed it should be one of the numeric code values
+     *        in that table (e.g. 3, 4, etc).  If a string is passed it can
+     *        either be an exception name (e.g. "HierarchyRequestError",
+     *        "WrongDocumentError") or the name of the corresponding error code
+     *        (e.g. "HIERARCHY_REQUEST_ERR", "WRONG_DOCUMENT_ERR").
+     *
+     * For the remaining arguments, there are two ways of calling
+     * promise_rejects_dom:
+     *
+     * 1) If the DOMException is expected to come from the current global, the
+     * second argument should be the function expected to throw and a third,
+     * optional, argument is the assertion description.
+     *
+     * 2) If the DOMException is expected to come from some other global, the
+     * second argument should be the DOMException constructor from that global,
+     * the third argument the function expected to throw, and the fourth, optional,
+     * argument the assertion description.
+     */
+    function assert_throws_dom(type, funcOrConstructor, descriptionOrFunc, maybeDescription)
+    {
+        let constructor, func, description;
+        if (funcOrConstructor.name === "DOMException") {
+            constructor = funcOrConstructor;
+            func = descriptionOrFunc;
+            description = maybeDescription;
+        } else {
+            constructor = self.DOMException;
+            func = funcOrConstructor;
+            description = descriptionOrFunc;
+            assert(maybeDescription === undefined,
+                    "Too many args pased to no-constructor version of assert_throws_dom");
+        }
+        assert_throws_dom_impl(type, func, description, "assert_throws_dom", constructor)
+    }
+    expose_assert(assert_throws_dom, "assert_throws_dom");
+
+    /**
+     * Similar to assert_throws_dom but allows specifying the assertion type
+     * (assert_throws_dom or promise_rejects_dom, in practice).  The
+     * "constructor" argument must be the DOMException constructor from the
+     * global we expect the exception to come from.
+     */
+    function assert_throws_dom_impl(type, func, description, assertion_type, constructor)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            // Basic sanity-checks on the thrown exception.
+            assert(typeof e === "object",
+                   assertion_type, description,
+                   "${func} threw ${e} with type ${type}, not an object",
+                   {func:func, e:e, type:typeof e});
+
+            assert(e !== null,
+                   assertion_type, description,
+                   "${func} threw null, not an object",
+                   {func:func});
+
+            // Sanity-check our type
+            assert(typeof type == "number" ||
+                   typeof type == "string",
+                   assertion_type, description,
+                   "${type} is not a number or string",
+                   {type:type});
+
+            var codename_name_map = {
+                INDEX_SIZE_ERR: 'IndexSizeError',
+                HIERARCHY_REQUEST_ERR: 'HierarchyRequestError',
+                WRONG_DOCUMENT_ERR: 'WrongDocumentError',
+                INVALID_CHARACTER_ERR: 'InvalidCharacterError',
+                NO_MODIFICATION_ALLOWED_ERR: 'NoModificationAllowedError',
+                NOT_FOUND_ERR: 'NotFoundError',
+                NOT_SUPPORTED_ERR: 'NotSupportedError',
+                INUSE_ATTRIBUTE_ERR: 'InUseAttributeError',
+                INVALID_STATE_ERR: 'InvalidStateError',
+                SYNTAX_ERR: 'SyntaxError',
+                INVALID_MODIFICATION_ERR: 'InvalidModificationError',
+                NAMESPACE_ERR: 'NamespaceError',
+                INVALID_ACCESS_ERR: 'InvalidAccessError',
+                TYPE_MISMATCH_ERR: 'TypeMismatchError',
+                SECURITY_ERR: 'SecurityError',
+                NETWORK_ERR: 'NetworkError',
+                ABORT_ERR: 'AbortError',
+                URL_MISMATCH_ERR: 'URLMismatchError',
+                QUOTA_EXCEEDED_ERR: 'QuotaExceededError',
+                TIMEOUT_ERR: 'TimeoutError',
+                INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError',
+                DATA_CLONE_ERR: 'DataCloneError'
+            };
+
+            var name_code_map = {
+                IndexSizeError: 1,
+                HierarchyRequestError: 3,
+                WrongDocumentError: 4,
+                InvalidCharacterError: 5,
+                NoModificationAllowedError: 7,
+                NotFoundError: 8,
+                NotSupportedError: 9,
+                InUseAttributeError: 10,
+                InvalidStateError: 11,
+                SyntaxError: 12,
+                InvalidModificationError: 13,
+                NamespaceError: 14,
+                InvalidAccessError: 15,
+                TypeMismatchError: 17,
+                SecurityError: 18,
+                NetworkError: 19,
+                AbortError: 20,
+                URLMismatchError: 21,
+                QuotaExceededError: 22,
+                TimeoutError: 23,
+                InvalidNodeTypeError: 24,
+                DataCloneError: 25,
+
+                EncodingError: 0,
+                NotReadableError: 0,
+                UnknownError: 0,
+                ConstraintError: 0,
+                DataError: 0,
+                TransactionInactiveError: 0,
+                ReadOnlyError: 0,
+                VersionError: 0,
+                OperationError: 0,
+                NotAllowedError: 0
+            };
+
+            var code_name_map = {};
+            for (var key in name_code_map) {
+                if (name_code_map[key] > 0) {
+                    code_name_map[name_code_map[key]] = key;
+                }
+            }
+
+            var required_props = {};
+            var name;
+
+            if (typeof type === "number") {
+                if (type === 0) {
+                    throw new AssertionError('Test bug: ambiguous DOMException code 0 passed to assert_throws_dom()');
+                } else if (!(type in code_name_map)) {
+                    throw new AssertionError('Test bug: unrecognized DOMException code "' + type + '" passed to assert_throws_dom()');
+                }
+                name = code_name_map[type];
+                required_props.code = type;
+            } else if (typeof type === "string") {
+                name = type in codename_name_map ? codename_name_map[type] : type;
+                if (!(name in name_code_map)) {
+                    throw new AssertionError('Test bug: unrecognized DOMException code name or name "' + type + '" passed to assert_throws_dom()');
+                }
+
+                required_props.code = name_code_map[name];
+            }
+
+            if (required_props.code === 0 ||
+                ("name" in e &&
+                e.name !== e.name.toUpperCase() &&
+                e.name !== "DOMException")) {
+                // New style exception: also test the name property.
+                required_props.name = name;
+            }
+
+            for (var prop in required_props) {
+                assert(prop in e && e[prop] == required_props[prop],
+                       assertion_type, description,
+                       "${func} threw ${e} that is not a DOMException " + type + ": property ${prop} is equal to ${actual}, expected ${expected}",
+                       {func:func, e:e, prop:prop, actual:e[prop], expected:required_props[prop]});
+            }
+
+            // Check that the exception is from the right global.  This check is last
+            // so more specific, and more informative, checks on the properties can
+            // happen in case a totally incorrect exception is thrown.
+            assert(e.constructor === constructor,
+                   assertion_type, description,
+                   "${func} threw an exception from the wrong global",
+                   {func});
+
+        }
+    }
+
+    /**
+     * Assert the provided value is thrown.
+     *
+     * @param {value} exception The expected exception.
+     * @param {Function} func Function which should throw.
+     * @param {string} description Error description for the case that the error is not thrown.
+     */
+    function assert_throws_exactly(exception, func, description)
+    {
+        assert_throws_exactly_impl(exception, func, description,
+                                   "assert_throws_exactly");
+    }
+    expose_assert(assert_throws_exactly, "assert_throws_exactly");
+
+    /**
+     * Like assert_throws_exactly but allows specifying the assertion type
+     * (assert_throws_exactly or promise_rejects_exactly, in practice).
+     */
+    function assert_throws_exactly_impl(exception, func, description,
+                                        assertion_type)
+    {
+        try {
+            func.call(this);
+            assert(false, assertion_type, description,
+                   "${func} did not throw", {func:func});
+        } catch (e) {
+            if (e instanceof AssertionError) {
+                throw e;
+            }
+
+            assert(same_value(e, exception), assertion_type, description,
+                   "${func} threw ${e} but we expected it to throw ${exception}",
+                   {func:func, e:e, exception:exception});
+        }
+    }
+
     function assert_unreached(description) {
          assert(false, "assert_unreached", description,
                 "Reached unreachable code");
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/echo-cookie-worker.py b/third_party/web_platform_tests/service-workers/service-worker/resources/echo-cookie-worker.py
index 561f64a..73e8caf 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/echo-cookie-worker.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/echo-cookie-worker.py
@@ -1,24 +1,24 @@
 def main(request, response):
-    headers = [(b"Content-Type", b"text/javascript")]
+    headers = [("Content-Type", "text/javascript")]
 
     values = []
     for key in request.cookies:
         for cookie in request.cookies.get_list(key):
-            values.append(b'"%s": "%s"' % (key, cookie.value))
+            values.append('"%s": "%s"' % (key, cookie.value))
 
     # Update the counter to change the script body for every request to trigger
     # update of the service worker.
-    key = request.GET[b'key']
+    key = request.GET['key']
     counter = request.server.stash.take(key)
     if counter is None:
         counter = 0
     counter += 1
     request.server.stash.put(key, counter)
 
-    body = b"""
+    body = """
 // %d
 self.addEventListener('message', e => {
   e.source.postMessage({%s})
-});""" % (counter, b','.join(values))
+});""" % (counter, ','.join(values))
 
     return headers, body
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/fetch-access-control.py b/third_party/web_platform_tests/service-workers/service-worker/resources/fetch-access-control.py
index 446af87..a158cf5 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/fetch-access-control.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/fetch-access-control.py
@@ -1,109 +1,107 @@
+import base64
 import json
 import os
-from base64 import decodebytes
-
-from wptserve.utils import isomorphic_decode, isomorphic_encode
 
 def main(request, response):
     headers = []
-    headers.append((b'X-ServiceWorker-ServerHeader', b'SetInTheServer'))
+    headers.append(('X-ServiceWorker-ServerHeader', 'SetInTheServer'))
 
-    if b"ACAOrigin" in request.GET:
-        for item in request.GET[b"ACAOrigin"].split(b","):
-            headers.append((b"Access-Control-Allow-Origin", item))
+    if "ACAOrigin" in request.GET:
+        for item in request.GET["ACAOrigin"].split(","):
+            headers.append(("Access-Control-Allow-Origin", item))
 
-    for suffix in [b"Headers", b"Methods", b"Credentials"]:
-        query = b"ACA%s" % suffix
-        header = b"Access-Control-Allow-%s" % suffix
+    for suffix in ["Headers", "Methods", "Credentials"]:
+        query = "ACA%s" % suffix
+        header = "Access-Control-Allow-%s" % suffix
         if query in request.GET:
             headers.append((header, request.GET[query]))
 
-    if b"ACEHeaders" in request.GET:
-        headers.append((b"Access-Control-Expose-Headers", request.GET[b"ACEHeaders"]))
+    if "ACEHeaders" in request.GET:
+        headers.append(("Access-Control-Expose-Headers", request.GET["ACEHeaders"]))
 
-    if (b"Auth" in request.GET and not request.auth.username) or b"AuthFail" in request.GET:
+    if ("Auth" in request.GET and not request.auth.username) or "AuthFail" in request.GET:
         status = 401
-        headers.append((b'WWW-Authenticate', b'Basic realm="Restricted"'))
-        body = b'Authentication canceled'
+        headers.append(('WWW-Authenticate', 'Basic realm="Restricted"'))
+        body = 'Authentication canceled'
         return status, headers, body
 
-    if b"PNGIMAGE" in request.GET:
-        headers.append((b"Content-Type", b"image/png"))
-        body = decodebytes(b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1B"
-                           b"AACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMG"
-                           b"jBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=")
+    if "PNGIMAGE" in request.GET:
+        headers.append(("Content-Type", "image/png"))
+        body = base64.decodestring("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1B"
+                                   "AACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAhSURBVDhPY3wro/KfgQLABKXJBqMG"
+                                   "jBoAAqMGDLwBDAwAEsoCTFWunmQAAAAASUVORK5CYII=")
         return headers, body
 
-    if b"VIDEO" in request.GET:
-        headers.append((b"Content-Type", b"video/ogg"))
-        body = open(os.path.join(request.doc_root, u"media", u"movie_5.ogv"), "rb").read()
+    if "VIDEO" in request.GET:
+        headers.append(("Content-Type", "video/webm"))
+        body = open(os.path.join(request.doc_root, "media", "movie_5.ogv"), "rb").read()
         length = len(body)
         # If "PartialContent" is specified, the requestor wants to test range
         # requests. For the initial request, respond with "206 Partial Content"
         # and don't send the entire content. Then expect subsequent requests to
         # have a "Range" header with a byte range. Respond with that range.
-        if b"PartialContent" in request.GET:
+        if "PartialContent" in request.GET:
           if length < 1:
-            return 500, headers, b"file is too small for range requests"
+            return 500, headers, "file is too small for range requests"
           start = 0
           end = length - 1
-          if b"Range" in request.headers:
-            range_header = request.headers[b"Range"]
-            prefix = b"bytes="
-            split_header = range_header[len(prefix):].split(b"-")
+          if "Range" in request.headers:
+            range_header = request.headers["Range"]
+            prefix = "bytes="
+            split_header = range_header[len(prefix):].split("-")
             # The first request might be "bytes=0-". We want to force a range
             # request, so just return the first byte.
-            if split_header[0] == b"0" and split_header[1] == b"":
+            if split_header[0] == "0" and split_header[1] == "":
               end = start
             # Otherwise, it is a range request. Respect the values sent.
-            if split_header[0] != b"":
+            if split_header[0] != "":
               start = int(split_header[0])
-            if split_header[1] != b"":
+            if split_header[1] != "":
               end = int(split_header[1])
           else:
             # The request doesn't have a range. Force a range request by
             # returning the first byte.
             end = start
 
-          headers.append((b"Accept-Ranges", b"bytes"))
-          headers.append((b"Content-Length", isomorphic_encode(str(end -start + 1))))
-          headers.append((b"Content-Range", b"bytes %d-%d/%d" % (start, end, length)))
+          headers.append(("Accept-Ranges", "bytes"))
+          headers.append(("Content-Length", str(end -start + 1)))
+          headers.append(("Content-Range", "bytes %d-%d/%d" % (start, end, length)))
           chunk = body[start:(end + 1)]
           return 206, headers, chunk
         return headers, body
 
-    username = request.auth.username if request.auth.username else b"undefined"
-    password = request.auth.password if request.auth.username else b"undefined"
-    cookie = request.cookies[b'cookie'].value if b'cookie' in request.cookies else b"undefined"
+    username = request.auth.username if request.auth.username else "undefined"
+    password = request.auth.password if request.auth.username else "undefined"
+    cookie = request.cookies['cookie'].value if 'cookie' in request.cookies else "undefined"
 
     files = []
     for key, values in request.POST.items():
         assert len(values) == 1
         value = values[0]
-        if not hasattr(value, u"file"):
+        if not hasattr(value, "file"):
             continue
         data = value.file.read()
-        files.append({u"key": isomorphic_decode(key),
-                      u"name": value.file.name,
-                      u"type": value.type,
-                      u"error": 0, #TODO,
-                      u"size": len(data),
-                      u"content": data})
+        files.append({"key": key,
+                      "name": value.file.name,
+                      "type": value.type,
+                      "error": 0, #TODO,
+                      "size": len(data),
+                      "content": data})
 
-    get_data = {isomorphic_decode(key):isomorphic_decode(request.GET[key]) for key, value in request.GET.items()}
-    post_data = {isomorphic_decode(key):isomorphic_decode(request.POST[key]) for key, value in request.POST.items()
-                 if not hasattr(request.POST[key], u"file")}
-    headers_data = {isomorphic_decode(key):isomorphic_decode(request.headers[key]) for key, value in request.headers.items()}
+    get_data = {key:request.GET[key] for key,value in request.GET.items()}
+    post_data = {key:request.POST[key] for key,value in request.POST.items()
+                 if not hasattr(request.POST[key], "file")}
+    headers_data = {key:request.headers[key] for key,value in request.headers.items()}
 
-    data = {u"jsonpResult": u"success",
-            u"method": request.method,
-            u"headers": headers_data,
-            u"body": isomorphic_decode(request.body),
-            u"files": files,
-            u"GET": get_data,
-            u"POST": post_data,
-            u"username": isomorphic_decode(username),
-            u"password": isomorphic_decode(password),
-            u"cookie": isomorphic_decode(cookie)}
+    data = {"jsonpResult": "success",
+            "method": request.method,
+            "headers": headers_data,
+            "body": request.body,
+            "files": files,
+            "GET": get_data,
+            "POST": post_data,
+            "username": username,
+            "password": password,
+            "cookie": cookie}
 
-    return headers, u"report( %s )" % json.dumps(data)
+    return headers, "report( %s )" % json.dumps(data)
\ No newline at end of file
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/redirect.py b/third_party/web_platform_tests/service-workers/service-worker/resources/redirect.py
index bd559d5..20521b0 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/redirect.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/redirect.py
@@ -1,27 +1,25 @@
-from wptserve.utils import isomorphic_decode
-
 def main(request, response):
-    if b'Status' in request.GET:
-        status = int(request.GET[b"Status"])
+    if 'Status' in request.GET:
+        status = int(request.GET["Status"])
     else:
         status = 302
 
     headers = []
 
-    url = isomorphic_decode(request.GET[b'Redirect'])
-    headers.append((b"Location", url))
+    url = request.GET['Redirect']
+    headers.append(("Location", url))
 
-    if b"ACAOrigin" in request.GET:
-        for item in request.GET[b"ACAOrigin"].split(b","):
-            headers.append((b"Access-Control-Allow-Origin", item))
+    if "ACAOrigin" in request.GET:
+        for item in request.GET["ACAOrigin"].split(","):
+            headers.append(("Access-Control-Allow-Origin", item))
 
-    for suffix in [b"Headers", b"Methods", b"Credentials"]:
-        query = b"ACA%s" % suffix
-        header = b"Access-Control-Allow-%s" % suffix
+    for suffix in ["Headers", "Methods", "Credentials"]:
+        query = "ACA%s" % suffix
+        header = "Access-Control-Allow-%s" % suffix
         if query in request.GET:
             headers.append((header, request.GET[query]))
 
-    if b"ACEHeaders" in request.GET:
-        headers.append((b"Access-Control-Expose-Headers", request.GET[b"ACEHeaders"]))
+    if "ACEHeaders" in request.GET:
+        headers.append(("Access-Control-Expose-Headers", request.GET["ACEHeaders"]))
 
-    return status, headers, b""
+    return status, headers, ""
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/service-worker-csp-worker.py b/third_party/web_platform_tests/service-workers/service-worker/resources/service-worker-csp-worker.py
index 35a4696..20bc85a 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/service-worker-csp-worker.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/service-worker-csp-worker.py
@@ -1,4 +1,4 @@
-bodyDefault = b'''
+bodyDefault = '''
 importScripts('worker-testharness.js');
 importScripts('test-helpers.sub.js');
 importScripts('/common/get-host-info.sub.js');
@@ -17,6 +17,7 @@
                 'Importing the other origins script should fail.');
   }, 'importScripts test for default-src');
 
+/* b/114053979 Cobalt eval() allowed when missing csp
 test(function() {
     assert_throws_js(EvalError,
                      function() { eval('1 + 1'); },
@@ -24,7 +25,7 @@
     assert_throws_js(EvalError,
                      function() { new Function('1 + 1'); },
                      'new Function() should throw EvalError.')
-  }, 'eval test for default-src');
+  }, 'eval test for default-src');*/
 
 async_test(function(t) {
     fetch(host_info.HTTPS_REMOTE_ORIGIN +
@@ -43,7 +44,8 @@
       base_path() + 'redirect.py?Redirect=';
     var OTHER_BASE_URL = host_info.HTTPS_REMOTE_ORIGIN +
       base_path() + 'fetch-access-control.py?'
-    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*'),
+    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*') +
+          '&ACAOrigin=*',
           {mode: 'cors'})
       .then(function(response){
           assert_unreached('Redirected fetch should fail.');
@@ -53,7 +55,7 @@
       .catch(unreached_rejection(t));
   }, 'Redirected fetch test for default-src');'''
 
-bodyScript = b'''
+bodyScript = '''
 importScripts('worker-testharness.js');
 importScripts('test-helpers.sub.js');
 importScripts('/common/get-host-info.sub.js');
@@ -72,6 +74,7 @@
                 'Importing the other origins script should fail.');
   }, 'importScripts test for script-src');
 
+/* b/114053979 Cobalt eval() allowed when missing csp
 test(function() {
     assert_throws_js(EvalError,
                      function() { eval('1 + 1'); },
@@ -79,7 +82,7 @@
     assert_throws_js(EvalError,
                      function() { new Function('1 + 1'); },
                      'new Function() should throw EvalError.')
-  }, 'eval test for script-src');
+  }, 'eval test for script-src');*/
 
 async_test(function(t) {
     fetch(host_info.HTTPS_REMOTE_ORIGIN +
@@ -98,7 +101,8 @@
       base_path() + 'redirect.py?Redirect=';
     var OTHER_BASE_URL = host_info.HTTPS_REMOTE_ORIGIN +
       base_path() + 'fetch-access-control.py?'
-    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*'),
+    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*') +
+          '&ACAOrigin=*',
           {mode: 'cors'})
       .then(function(response){
           t.done();
@@ -108,7 +112,7 @@
       .catch(unreached_rejection(t));
   }, 'Redirected fetch test for script-src');'''
 
-bodyConnect = b'''
+bodyConnect = '''
 importScripts('worker-testharness.js');
 importScripts('test-helpers.sub.js');
 importScripts('/common/get-host-info.sub.js');
@@ -127,6 +131,7 @@
                  'Importing the other origins script should not fail.');
   }, 'importScripts test for connect-src');
 
+/* b/114053979 Cobalt eval() allowed when missing csp
 test(function() {
     var eval_failed = false;
     try {
@@ -137,7 +142,7 @@
     }
     assert_false(eval_failed,
                  'connect-src without unsafe-eval should not block eval().');
-  }, 'eval test for connect-src');
+  }, 'eval test for connect-src');*/
 
 async_test(function(t) {
     fetch(host_info.HTTPS_REMOTE_ORIGIN +
@@ -156,7 +161,8 @@
       base_path() + 'redirect.py?Redirect=';
     var OTHER_BASE_URL = host_info.HTTPS_REMOTE_ORIGIN +
       base_path() + 'fetch-access-control.py?'
-    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*'),
+    fetch(REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*') +
+          '&ACAOrigin=*',
           {mode: 'cors'})
       .then(function(response){
           assert_unreached('Redirected fetch should fail.');
@@ -168,16 +174,16 @@
 
 def main(request, response):
     headers = []
-    headers.append((b'Content-Type', b'application/javascript'))
-    directive = request.GET[b'directive']
-    body = b'ERROR: Unknown directive'
-    if directive == b'default':
-        headers.append((b'Content-Security-Policy', b"default-src 'self'"))
+    headers.append(('Content-Type', 'application/javascript'))
+    directive = request.GET['directive']
+    body = 'ERROR: Unknown directive'
+    if directive == 'default':
+        headers.append(('Content-Security-Policy', "default-src 'self'"))
         body = bodyDefault
-    elif directive == b'script':
-        headers.append((b'Content-Security-Policy', b"script-src 'self'"))
+    elif directive == 'script':
+        headers.append(('Content-Security-Policy', "script-src 'self'"))
         body = bodyScript
-    elif directive == b'connect':
-        headers.append((b'Content-Security-Policy', b"connect-src 'self'"))
+    elif directive == 'connect':
+        headers.append(('Content-Security-Policy', "connect-src 'self'"))
         body = bodyConnect
     return headers, body
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/test-helpers.sub.js b/third_party/web_platform_tests/service-workers/service-worker/resources/test-helpers.sub.js
index 7430152..28b657a 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/test-helpers.sub.js
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/test-helpers.sub.js
@@ -86,7 +86,15 @@
   return new Promise(test.step_func(function(resolve) {
       var handler = test.step_func(function() {
         registration.removeEventListener('updatefound', handler);
-        resolve(registration.installing);
+        // b/234788479 Implement waiting for update worker state tasks in
+        // Install algorithm, otherwise the worker is activated too early
+        if (registration.installing) {
+          resolve(registration.installing);
+        } else if (registration.waiting) {
+          resolve(registration.waiting);
+        } else {
+          resolve(registration.active);
+        }
       });
       registration.addEventListener('updatefound', handler);
     }));
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/test-request-headers-worker.py b/third_party/web_platform_tests/service-workers/service-worker/resources/test-request-headers-worker.py
index 78a9335..8188bab 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/test-request-headers-worker.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/test-request-headers-worker.py
@@ -3,14 +3,12 @@
 import uuid
 import sys
 
-from wptserve.utils import isomorphic_decode
-
 def main(request, response):
-  path = os.path.join(os.path.dirname(isomorphic_decode(__file__)),
+  path = os.path.join(os.path.dirname(__file__),
                       u"test-request-headers-worker.js")
   body = open(path, u"rb").read()
 
-  data = {isomorphic_decode(key):isomorphic_decode(request.headers[key]) for key, value in request.headers.items()}
+  data = {key:request.headers[key] for key,value in request.headers.items()}
   body = body.replace(b"%HEADERS%", json.dumps(data).encode("utf-8"))
   body = body.replace(b"%UUID%", str(uuid.uuid4()).encode("utf-8"))
 
@@ -18,4 +16,4 @@
   headers.append((b"ETag", b"etag"))
   headers.append((b"Content-Type", b'text/javascript'))
 
-  return headers, body
+  return headers, body
\ No newline at end of file
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py b/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py
index 1547cb5..2d95387 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py
@@ -1,9 +1,9 @@
 def main(request, response):
-    key = request.GET[b'key']
+    key = request.GET['key']
     already_requested = request.server.stash.take(key)
 
     if already_requested is None:
         request.server.stash.put(key, True)
-        return [(b'Content-Type', b'application/javascript')], b'// initial script'
+        return [('Content-Type', 'application/javascript')], '// initial script'
 
-    response.status = (404, b'Not found: should not have been able to import this script twice!')
+    response.status = (404, 'Not found: should not have been able to import this script twice!')
diff --git a/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py b/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py
index 1c447e1..8be62ec 100644
--- a/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py
+++ b/third_party/web_platform_tests/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py
@@ -1,15 +1,13 @@
-from wptserve.utils import isomorphic_decode
-
 def main(request, response):
-    key = request.GET[b'key']
+    key = request.GET['key']
     already_requested = request.server.stash.take(key)
 
-    header = [(b'Content-Type', b'application/javascript')]
-    initial_script = u'importScripts("./update-missing-import-scripts-imported-worker.py?key={0}")'.format(isomorphic_decode(key))
-    updated_script = u'// removed importScripts()'
+    header = [('Content-Type', 'application/javascript')]
+    initial_script = 'importScripts("./update-missing-import-scripts-imported-worker.py?key={0}")'.format(key)
+    updated_script = '// removed importScripts()'
 
     if already_requested is None:
         request.server.stash.put(key, True)
         return header, initial_script
 
-    return header, updated_script
+    return header, updated_script
\ No newline at end of file
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index f3e9d0f..c013b2a 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -50,6 +50,10 @@
 
   void SetTimeModified(const base::Time& time) override;
 
+#if defined(STARBOARD)
+  bool Flush() override;
+#endif
+
  private:
   size_t max_read_bytes_;
   std::string* output_;
@@ -77,6 +81,13 @@
   return true;
 }
 
+#if defined(STARBOARD)
+bool StringWriterDelegate::Flush() {
+  // Do nothing.
+  return true;
+}
+#endif
+
 void StringWriterDelegate::SetTimeModified(const base::Time& time) {
   // Do nothing.
 }
@@ -289,6 +300,12 @@
     delegate->SetTimeModified(current_entry_info()->last_modified());
   }
 
+#if defined(STARBOARD)
+  if (!delegate->Flush()) {
+    return false;
+  }
+#endif
+
   return entire_file_extracted;
 }
 
@@ -478,14 +495,17 @@
   file_->SetTimes(base::Time::Now(), time);
 }
 
+#if defined(STARBOARD)
+bool FileWriterDelegate::Flush() {
+  return file_->Flush();
+}
+#endif
 // FilePathWriterDelegate ------------------------------------------------------
 
 FilePathWriterDelegate::FilePathWriterDelegate(
     const base::FilePath& output_file_path)
     : output_file_path_(output_file_path) {}
-
 FilePathWriterDelegate::~FilePathWriterDelegate() {}
-
 bool FilePathWriterDelegate::PrepareOutput() {
   // We can't rely on parent directory entries being specified in the
   // zip, so we make sure they are created.
@@ -500,12 +520,19 @@
 bool FilePathWriterDelegate::WriteBytes(const char* data, int num_bytes) {
   return num_bytes == file_.WriteAtCurrentPos(data, num_bytes);
 }
+#if defined(STARBOARD)
+bool FilePathWriterDelegate::Flush() {
+  return file_.Flush();
+}
+#endif
 
 void FilePathWriterDelegate::SetTimeModified(const base::Time& time) {
-  file_.Close();
-  // TODO: use a workaround for base::TouchFile, because Starboard has not
-  // enabled the functions to update file modified/access time.
-  // base::TouchFile(output_file_path_, base::Time::Now(), time);
+#if defined(STARBOARD)
+  // Starboard doesn't support setting file access or modification times.
+#else
+  base::TouchFile(output_file_path_, base::Time::Now(), time);
+#endif
+
 }
 
 }  // namespace zip
diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h
index d442d42..c4bcc1c 100644
--- a/third_party/zlib/google/zip_reader.h
+++ b/third_party/zlib/google/zip_reader.h
@@ -42,6 +42,12 @@
 
   // Sets the last-modified time of the data.
   virtual void SetTimeModified(const base::Time& time) = 0;
+
+#if defined(STARBOARD)
+  // Invoked at the end of the entry extraction to flush to persistent storage.
+  // Returns failure on failure to flush.
+  virtual bool Flush() = 0;
+#endif
 };
 
 // This class is used for reading zip files. A typical use case of this
@@ -255,6 +261,10 @@
   // Sets the last-modified time of the data.
   void SetTimeModified(const base::Time& time) override;
 
+#if defined(STARBOARD)
+  bool Flush() override;
+#endif
+
   // Return the actual size of the file.
   int64_t file_length() { return file_length_; }
 
@@ -289,6 +299,10 @@
   // Sets the last-modified time of the data.
   void SetTimeModified(const base::Time& time) override;
 
+#if defined(STARBOARD)
+  bool Flush() override;
+#endif
+
  private:
   base::FilePath output_file_path_;
   base::File file_;
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
index a595102..b6ab67e 100644
--- a/third_party/zlib/google/zip_reader_unittest.cc
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -117,6 +117,7 @@
   MOCK_METHOD0(PrepareOutput, bool());
   MOCK_METHOD2(WriteBytes, bool(const char*, int));
   MOCK_METHOD1(SetTimeModified, void(const base::Time&));
+  MOCK_METHOD0(Flush, bool());
 };
 
 bool ExtractCurrentEntryToFilePath(zip::ZipReader* reader,
@@ -623,6 +624,8 @@
 
   EXPECT_CALL(mock_writer, PrepareOutput())
       .WillOnce(Return(true));
+  EXPECT_CALL(mock_writer, Flush())
+      .WillOnce(Return(true));
   EXPECT_CALL(mock_writer, WriteBytes(_, _))
       .WillOnce(Return(false));
 
@@ -635,6 +638,29 @@
       &mock_writer, std::numeric_limits<uint64_t>::max()));
 }
 
+#if defined(STARBOARD)
+// Test that when WriterDelegate::Flush returns false the extraction fails.
+TEST_F(ZipReaderTest, ExtractCurrentEntryFlushFailure) {
+  testing::StrictMock<MockWriterDelegate> mock_writer;
+
+  EXPECT_CALL(mock_writer, PrepareOutput())
+      .WillOnce(Return(true));
+  EXPECT_CALL(mock_writer, WriteBytes(_, _))
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(mock_writer, SetTimeModified(_));
+  EXPECT_CALL(mock_writer, Flush())
+      .WillOnce(Return(false));
+
+  base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+  ZipReader reader;
+
+  ASSERT_TRUE(reader.Open(test_zip_file_));
+  ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
+  ASSERT_FALSE(reader.ExtractCurrentEntry(
+      &mock_writer, std::numeric_limits<uint64_t>::max()));
+}
+#endif
+
 // Test that extraction succeeds when the writer delegate reports all is well.
 TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
   testing::StrictMock<MockWriterDelegate> mock_writer;
@@ -645,6 +671,8 @@
       .WillRepeatedly(Return(true));
   EXPECT_CALL(mock_writer, SetTimeModified(_));
 
+  EXPECT_CALL(mock_writer, Flush()).WillOnce(Return(true));
+
   base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
   ZipReader reader;
 
diff --git a/tools/create_archive.py b/tools/create_archive.py
index d1e5c9a..16ccb74 100755
--- a/tools/create_archive.py
+++ b/tools/create_archive.py
@@ -44,7 +44,6 @@
 # Use strict include filter to pass artifacts to Mobile Harness
 TEST_PATTERNS = [
     'content/*',
-    'deploy/*',
     'install/*',
     # TODO: All of those should be built under deploy/
     '*.apk',
@@ -70,15 +69,17 @@
   return sys.platform in ['win32']
 
 
+class InvalidArchiveExtensionException(RuntimeError):
+  pass
+
+
 def _CheckArchiveExtension(archive_path, is_parallel):
   if is_parallel and (_LINUX_PARALLEL_ZIP_EXTENSION not in archive_path):
-    raise RuntimeError(
-        'Invalid archive extension. Parallelized zip requested, but path is %s'
-        % archive_path)
+    raise InvalidArchiveExtensionException(
+        f'Parallelized zip requested, but path is {archive_path}')
   if not is_parallel and (_LINUX_PARALLEL_ZIP_EXTENSION in archive_path):
-    raise RuntimeError(
-        'Invalid archive extension. Serialized zip requested, but path is: %s' %
-        archive_path)
+    raise InvalidArchiveExtensionException(
+        f'Serialized zip requested, but path is: {archive_path}')
 
 
 def _CreateCompressedArchive(source_paths,
@@ -138,12 +139,11 @@
       logging.info('included subpaths: %s', included_paths)
 
       if not os.path.exists(source_path):
-        raise ValueError('Failed to find source path "{}".'.format(source_path))
+        raise ValueError(f'Failed to find source path "{source_path}".')
 
       for target_path in included_paths:
         if not os.path.exists(os.path.join(source_path, target_path)):
-          raise ValueError(
-              'Failed to find target path "{}".'.format(target_path))
+          raise ValueError(f'Failed to find target path "{target_path}".')
 
       source_parent_dir, source_dir_name = os.path.split(
           os.path.abspath(source_path))
@@ -253,7 +253,7 @@
   if intermediate:
     exclude_patterns = worker_tools.BUILDBOT_INTERMEDIATE_FILE_NAMES_WILDCARDS
   excludes = ' '.join([
-      '-xr!{}'.format(x.replace(worker_tools.SOURCE_DIR, source_path))
+      f'-xr!{x.replace(worker_tools.SOURCE_DIR, source_path)}'
       for x in exclude_patterns
   ])
   contents = [
@@ -261,9 +261,9 @@
       for pattern in patterns
       if glob.glob(os.path.join(source_path, pattern))
   ]
-  return '"{}" a {} -bsp1 -snl -ttar {} {}'.format(_7Z_PATH, excludes,
-                                                   intermediate_tar_path,
-                                                   ' '.join(contents))
+  files_to_tar = ' '.join(contents)
+  return (f'"{_7Z_PATH}" a {excludes} -bsp1 -snl -ttar '
+          f'{intermediate_tar_path} {files_to_tar}')
 
 
 def _CreateLinuxTarCmd(source_path, intermediate_tar_path, patterns,
@@ -272,7 +272,7 @@
   if intermediate:
     exclude_patterns = worker_tools.BUILDBOT_INTERMEDIATE_FILE_NAMES_WILDCARDS
   excludes = ' '.join([
-      '--exclude="{}"'.format(x.replace(worker_tools.SOURCE_DIR, source_path))
+      f'--exclude="{x.replace(worker_tools.SOURCE_DIR, source_path)}"'
       for x in exclude_patterns
   ])
   mode = 'r' if os.path.exists(intermediate_tar_path) else 'c'
@@ -281,42 +281,38 @@
       for pattern in patterns
       if glob.glob(os.path.join(source_path, pattern))
   ]
-  return 'tar -{}vf {} --format=posix {} {}'.format(mode, intermediate_tar_path,
-                                                    excludes,
-                                                    ' '.join(contents))
+  files_to_tar = ' '.join(contents)
+  return (f'tar -{mode}vf {intermediate_tar_path} --format=posix '
+          f'{excludes} {files_to_tar}')
 
 
 def _CreateUntarCommand(intermediate_tar_path):
   if _IsWindows():
-    return '"{}" x -bsp1 {}'.format(_7Z_PATH, intermediate_tar_path)
+    return f'"{_7Z_PATH}" x -bsp1 {intermediate_tar_path}'
   else:
-    return 'tar -xvf {}'.format(intermediate_tar_path)
+    return f'tar -xvf {intermediate_tar_path}'
 
 
 def _CreateZipCommand(intermediate_tar_path, dest_path, is_parallel=False):
   if _IsWindows():
-    return '"{}" a -bsp1 -mx={} -mmt=on {} {}'.format(_7Z_PATH,
-                                                      _COMPRESSION_LEVEL,
-                                                      dest_path,
-                                                      intermediate_tar_path)
+    return (f'"{_7Z_PATH}" a -bsp1 -mx={_COMPRESSION_LEVEL} '
+            f'-mmt=on {dest_path} {intermediate_tar_path}')
   else:
     zip_program = (
         _LINUX_PARALLEL_ZIP_PROGRAM
         if is_parallel else _LINUX_SERIAL_ZIP_PROGRAM)
-    return '{} -vc -1 {} > {}'.format(zip_program, intermediate_tar_path,
-                                   dest_path)
+    return f'{zip_program} -vc -1 {intermediate_tar_path} > {dest_path}'
 
 
 def _CreateUnzipCommand(source_path, intermediate_tar_path, is_parallel=False):
   if _IsWindows():
     tar_parent = os.path.dirname(intermediate_tar_path)
-    return '"{}" x -bsp1 {} -o{}'.format(_7Z_PATH, source_path, tar_parent)
+    return f'"{_7Z_PATH}" x -bsp1 {source_path} -o{tar_parent}'
   else:
     zip_program = (
         _LINUX_PARALLEL_ZIP_PROGRAM
         if is_parallel else _LINUX_SERIAL_ZIP_PROGRAM)
-    return '{} -dvc {} > {}'.format(zip_program, source_path,
-                                    intermediate_tar_path)
+    return f'{zip_program} -dvc {source_path} > {intermediate_tar_path}'
 
 
 def _CleanUp(intermediate_tar_path):
@@ -382,8 +378,8 @@
   else:
     _CreateCompressedArchive(
         args.source_paths, args.dest_path,
-        TEST_PATTERNS if args.test_infra else args.patterns,
-        args.intermediate, args.parallel)
+        TEST_PATTERNS if args.test_infra else args.patterns, args.intermediate,
+        args.parallel)
 
 
 if __name__ == '__main__':