Import Cobalt 21.master.0.292047

Includes the following patches:
  https://cobalt-review.googlesource.com/c/cobalt/+/5670
    by xingyz@amazon.com
  https://cobalt-review.googlesource.com/c/cobalt/+/5770
    by marccote@lab126.com
diff --git a/src/.pylintrc b/src/.pylintrc
index 77b0063..e167680 100644
--- a/src/.pylintrc
+++ b/src/.pylintrc
@@ -1,111 +1,175 @@
+# This Pylint rcfile contains a best-effort configuration to uphold the
+# best-practices and style described in the Google Python style guide:
+#   https://google.github.io/styleguide/pyguide.html
+#
+# Its canonical open-source location is:
+#   https://google.github.io/styleguide/pylintrc
+#
+# Last updated for Cobalt (YYYY-MM-DD): 2020-11-04
+
 [MASTER]
 
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
 # Add files or directories to the blacklist. They should be base names, not
 # paths.
-ignore=CVS
+ignore=third_party
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
 
 # Pickle collected data for later comparisons.
-persistent=yes
+persistent=no
 
 # List of plugins (as comma separated values of python modules names) to load,
 # usually to register additional checkers.
 load-plugins=
 
+# Use multiple processes to speed up Pylint.
+jobs=4
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code
+extension-pkg-whitelist=
+
 
 [MESSAGES CONTROL]
 
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
+confidence=
+
 # Enable the message, report, category or checker with the given id(s). You can
 # either give multiple identifier separated by comma (,) or put this option
-# multiple time.
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
 #enable=
 
 # Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifier separated by comma (,) or put this option
-# multiple time (only on the command line, not in the configuration file where
-# it should appear only once).
-# CHANGED:
-# C0103: Invalid name ""
-# C0111: Missing docstring
-# C0302: Too many lines in module (N)
-# I0010: Unable to consider inline option ''
-# I0011: Locally disabling WNNNN
-#
-# R0801: Similar lines in N files
-# R0901: Too many ancestors (8/7)
-# R0902: Too many instance attributes (N/7)
-# R0903: Too few public methods (N/2)
-# R0904: Too many public methods (N/20)
-# R0911: Too many return statements (N/6)
-# R0912: Too many branches (N/12)
-# R0913: Too many arguments (N/5)
-# R0914: Too many local variables (N/15)
-# R0915: Too many statements (N/50)
-# R0921: Abstract class not referenced
-# R0922: Abstract class is only referenced 1 times
-# W0122: Use of the exec statement
-# W0141: Used builtin function ''
-# W0142: Used * or ** magic
-# W0402: Uses of a deprecated module 'string'
-# W0404: 41: Reimport 'XX' (imported line NN)
-# W0511: TODO
-# W0603: Using the global statement
-# W0703: Catch "Exception"
-# W1201: Specify string format arguments as logging function parameters
-#
-# These should get enabled, but the codebase has too many violations currently.
-# bad-continuation
-# anomalous-backslash-in-string
-# bad-context-manager
-# bad-indentation
-# bad-str-strip-call
-# bad-whitespace
-# cell-var-from-loop
-# deprecated-lambda
-# eval-used
-# function-redefined
-# import-error
-# locally-enabled
-# missing-final-newline
-# no-init
-# no-name-in-module
-# no-self-use
-# not-callable
-# old-style-class
-# protected-access
-# superfluous-parens
-# super-on-old-class
-# too-many-function-args
-# trailing-whitespace
-# unnecessary-semicolon
-# unpacking-non-sequence
-# unused-import
-# useless-else-on-loop
-disable=C0103,C0111,C0302,I0010,I0011,R0801,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0921,R0922,W0122,W0141,W0142,W0402,W0404,W0511,W0603,W0703,W1201,bad-continuation,anomalous-backslash-in-string,bad-context-manager,bad-indentation,bad-str-strip-call,bad-whitespace,cell-var-from-loop,deprecated-lambda,eval-used,function-redefined,import-error,locally-enabled,missing-final-newline,no-init,no-name-in-module,no-self-use,not-callable,old-style-class,protected-access,superfluous-parens,super-on-old-class,too-many-function-args,trailing-whitespace,unnecessary-semicolon,unpacking-non-sequence,unused-import,useless-else-on-loop
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once).You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use"--disable=all --enable=classes
+# --disable=W"
+disable=abstract-method,
+        apply-builtin,
+        arguments-differ,
+        attribute-defined-outside-init,
+        backtick,
+        bad-option-value,
+        basestring-builtin,
+        buffer-builtin,
+        c-extension-no-member,
+        consider-using-enumerate,
+        cmp-builtin,
+        cmp-method,
+        coerce-builtin,
+        coerce-method,
+        delslice-method,
+        div-method,
+        duplicate-code,
+        eq-without-hash,
+        execfile-builtin,
+        file-builtin,
+        filter-builtin-not-iterating,
+        fixme,
+        getslice-method,
+        global-statement,
+        hex-method,
+        idiv-method,
+        implicit-str-concat-in-sequence,
+        import-error,
+        import-self,
+        import-star-module-level,
+        inconsistent-return-statements,
+        input-builtin,
+        intern-builtin,
+        invalid-str-codec,
+        locally-disabled,
+        long-builtin,
+        long-suffix,
+        map-builtin-not-iterating,
+        misplaced-comparison-constant,
+        missing-function-docstring,
+        metaclass-assignment,
+        next-method-called,
+        next-method-defined,
+        no-absolute-import,
+        no-else-break,
+        no-else-continue,
+        no-else-raise,
+        no-else-return,
+        no-init,  # added
+        no-member,
+        no-name-in-module,
+        no-self-use,
+        nonzero-method,
+        oct-method,
+        old-division,
+        old-ne-operator,
+        old-octal-literal,
+        old-raise-syntax,
+        parameter-unpacking,
+        print-statement,
+        raising-string,
+        range-builtin-not-iterating,
+        raw_input-builtin,
+        rdiv-method,
+        reduce-builtin,
+        relative-import,
+        reload-builtin,
+        round-builtin,
+        setslice-method,
+        signature-differs,
+        standarderror-builtin,
+        suppressed-message,
+        sys-max-int,
+        too-few-public-methods,
+        too-many-ancestors,
+        too-many-arguments,
+        too-many-boolean-expressions,
+        too-many-branches,
+        too-many-instance-attributes,
+        too-many-locals,
+        too-many-nested-blocks,
+        too-many-public-methods,
+        too-many-return-statements,
+        too-many-statements,
+        trailing-newlines,
+        unichr-builtin,
+        unicode-builtin,
+        unnecessary-pass,
+        unpacking-in-except,
+        useless-else-on-loop,
+        useless-object-inheritance,
+        useless-suppression,
+        using-cmp-argument,
+        wrong-import-order,
+        xrange-builtin,
+        zip-builtin-not-iterating,
 
 
 [REPORTS]
 
 # Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html
+# (visual studio) and html. You can also give a reporter class, eg
+# mypackage.mymodule.MyReporterClass.
 output-format=text
 
 # Put messages in a separate file for each module / package specified on the
 # command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
+# written in a file name "pylint_global.[txt|html]". This option is deprecated
+# and it will be removed in Pylint 2.0.
 files-output=no
 
 # Tells whether to display a full report or only the messages
-# CHANGED:
 reports=no
 
 # Python expression which should return a note less than 10 (10 is the highest
@@ -115,9 +179,147 @@
 # (RP0004).
 evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
 
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details
+#msg-template=
+
+
+[BASIC]
+
+# Good variable names which should always be accepted, separated by a comma
+good-names=main,_
+
+# Bad variable names which should always be refused, separated by a comma
+bad-names=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Include a hint for the correct naming format with invalid-name
+include-naming-hint=no
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
+
+# Regular expression matching correct function names
+function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
+
+# Regular expression matching correct variable names
+variable-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct constant names
+const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+
+# Regular expression matching correct attribute names
+attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
+
+# Regular expression matching correct argument names
+argument-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct class attribute names
+class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
+
+# Regular expression matching correct inline iteration names
+inlinevar-rgx=^[a-z][a-z0-9_]*$
+
+# Regular expression matching correct class names
+class-rgx=^_?[A-Z][a-zA-Z0-9]*$
+
+# Regular expression matching correct module names
+module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
+
+# Regular expression matching correct method names
+method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=10
+
+
+[TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis. It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+
+[FORMAT]
+
+# Maximum number of characters on a single line.
+max-line-length=80
+
+# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
+# lines made too long by directives to pytype.
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=(?x)(
+  ^\s*(\#\ )?<?https?://\S+>?$|
+  ^\s*(from\s+\S+\s+)?import\s+.+$)
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=yes
+
+# List of optional constructs for which whitespace checking is disabled. `dict-
+# separator` is used to allow tabulation in dicts, etc.: {1  : 1,\n222: 2}.
+# `trailing-comma` allows a space between comma and closing bracket: (a, ).
+# `empty-line` allows space-only lines.
+no-space-check=
+
+# Maximum number of lines in a module
+max-module-lines=99999
+
+# String used as indentation unit.  The internal Google style guide mandates 2
+# spaces.  Google's externaly-published style guide says 4, consistent with
+# PEP 8.  Here, we use 2 spaces, for conformity with many open-sourced Google
+# projects (like TensorFlow).
+indent-string='  '
+
+# Number of spaces of indent required inside a hanging  or continued line.
+indent-after-paren=4
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=TODO
+
+
+[STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=yes
 
 
 [VARIABLES]
@@ -125,39 +327,28 @@
 # Tells whether we should check for unused import in __init__ files.
 init-import=no
 
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
-dummy-variables-rgx=_|dummy
+# A regular expression matching the name of dummy variables (i.e. expectedly
+# not used).
+dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
 
 # List of additional names supposed to be defined in builtins. Remember that
 # you should avoid to define new builtins when possible.
 additional-builtins=
 
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,_cb
 
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject,twisted.internet.reactor,hashlib,google.appengine.api.memcache
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent,multiprocessing.managers.SyncManager
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
 
 
-[MISCELLANEOUS]
+[LOGGING]
 
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
+# Logging modules to check that the string format arguments are in logging
+# function parameter format
+logging-modules=logging,absl.logging,tensorflow.io.logging
 
 
 [SIMILARITIES]
@@ -171,119 +362,35 @@
 # Ignore docstrings when computing similarities.
 ignore-docstrings=yes
 
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-# CHANGED:
-indent-string='  '
+# Ignore imports when computing similarities.
+ignore-imports=no
 
 
-[BASIC]
+[SPELLING]
 
-# Required attributes for module, separated by a comma
-required-attributes=
+# Spelling dictionary name. Available dictionaries: none. To make it working
+# install python-enchant package.
+spelling-dict=
 
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
 
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
+# A path to a file that contains private dictionary; one word per line.
+spelling-private-dict-file=
 
-# Regular expression which should only match correct module level names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Regular expression which should only match functions or classes name which do
-# not require a docstring
-no-docstring-rgx=__.*__
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branchs=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
+# Tells whether to store unknown words to indicated private dictionary in
+# --spelling-private-dict-file option instead of raising a message.
+spelling-store-unknown-words=no
 
 
 [IMPORTS]
 
 # Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
+deprecated-modules=regsub,
+                   TERMIOS,
+                   Bastion,
+                   rexec,
+                   sets
 
 # Create a graph of every (i.e. internal and external) dependencies in the
 # given file (report RP0402 must not be disabled)
@@ -297,9 +404,46 @@
 # not be disabled)
 int-import-graph=
 
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant, absl
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+
+[CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+                      __new__,
+                      setUp
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+                  _fields,
+                  _replace,
+                  _source,
+                  _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls,
+                            class_
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=mcs
+
 
 [EXCEPTIONS]
 
 # Exceptions that will emit a warning when being caught. Defaults to
 # "Exception"
-overgeneral-exceptions=Exception
+overgeneral-exceptions=StandardError,
+                       Exception,
+                       BaseException
diff --git a/src/cobalt/black_box_tests/black_box_tests.py b/src/cobalt/black_box_tests/black_box_tests.py
index 271b2cc..43cf1a7 100644
--- a/src/cobalt/black_box_tests/black_box_tests.py
+++ b/src/cobalt/black_box_tests/black_box_tests.py
@@ -34,7 +34,6 @@
 
 _DISABLED_BLACKBOXTEST_CONFIGS = [
     'android-arm/devel',
-    'android-arm64/devel',
     'android-x86/devel',
     'raspi-0/devel',
 ]
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index d709ff7..55e3102 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -1616,6 +1616,38 @@
   return nullptr;
 }
 
+void BrowserModule::InitializeComponents() {
+  TRACE_EVENT0("cobalt::browser", "BrowserModule::InitializeComponents()");
+  InstantiateRendererModule();
+
+  if (media_module_) {
+#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \
+    SB_HAS(CONCEALED_STATE)
+    media_module_->UpdateSystemWindowAndResourceProvider(
+        system_window_.get(), GetResourceProvider());
+#else
+    media_module_->Resume(GetResourceProvider());
+#endif  // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION ||
+        // SB_HAS(CONCEALED_STATE)
+  } else {
+    options_.media_module_options.allow_resume_after_suspend =
+        SbSystemSupportsResume();
+    media_module_.reset(new media::MediaModule(system_window_.get(),
+                                               GetResourceProvider(),
+                                               options_.media_module_options));
+
+    if (web_module_) {
+      web_module_->SetCamera3D(input_device_manager_->camera_3d());
+      web_module_->SetMediaModule(media_module_.get());
+    }
+  }
+
+  if (web_module_) {
+    web_module_->GetUiNavRoot()->SetContainerWindow(
+        system_window_->GetSbWindow());
+  }
+}
+
 void BrowserModule::InitializeSystemWindow() {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::InitializeSystemWindow()");
   DCHECK(!system_window_);
@@ -1646,28 +1678,7 @@
       // SB_HAS(ON_SCREEN_KEYBOARD)
       system_window_.get());
 
-  InstantiateRendererModule();
-
-  if (media_module_) {
-    media_module_->UpdateSystemWindowAndResourceProvider(
-        system_window_.get(), GetResourceProvider());
-  } else {
-    options_.media_module_options.allow_resume_after_suspend =
-        SbSystemSupportsResume();
-    media_module_.reset(new media::MediaModule(system_window_.get(),
-                                               GetResourceProvider(),
-                                               options_.media_module_options));
-
-    if (web_module_) {
-      web_module_->SetCamera3D(input_device_manager_->camera_3d());
-      web_module_->SetWebMediaPlayerFactory(media_module_.get());
-    }
-  }
-
-  if (web_module_) {
-    web_module_->GetUiNavRoot()->SetContainerWindow(
-        system_window_->GetSbWindow());
-  }
+  InitializeComponents();
 }
 
 void BrowserModule::InstantiateRendererModule() {
@@ -1751,8 +1762,8 @@
 
 void BrowserModule::ConcealInternal() {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::ConcealInternal()");
-  FOR_EACH_OBSERVER(
-      LifecycleObserver, lifecycle_observers_, Conceal(GetResourceProvider()));
+  FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
+                    Conceal(GetResourceProvider()));
 
   ResetResources();
 
@@ -1765,10 +1776,14 @@
   if (media_module_) {
     DCHECK(system_window_);
     window_size_ = system_window_->GetWindowSize();
+#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \
+    SB_HAS(CONCEALED_STATE)
     input_device_manager_.reset();
     system_window_.reset();
     media_module_->UpdateSystemWindowAndResourceProvider(
         NULL, GetResourceProvider());
+#endif  // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION ||
+        // SB_HAS(CONCEALED_STATE)
   }
 }
 
@@ -1783,15 +1798,18 @@
 void BrowserModule::RevealInternal() {
   TRACE_EVENT0("cobalt::browser", "BrowserModule::RevealInternal()");
   DCHECK(!renderer_module_);
-  DCHECK(!system_window_);
-  InitializeSystemWindow();
-
-  // Propagate the current screen size.
-  UpdateScreenSize();
+  if (!system_window_) {
+    InitializeSystemWindow();
+  } else {
+    InitializeComponents();
+  }
 
   DCHECK(system_window_);
   window_size_ = system_window_->GetWindowSize();
 
+  // Propagate the current screen size.
+  UpdateScreenSize();
+
   // Set resource provider right after render module initialized.
   FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
                     Reveal(GetResourceProvider()));
@@ -1805,7 +1823,12 @@
   TRACE_EVENT0("cobalt::browser", "BrowserModule::UnfreezeInternal()");
   // Set the Stub resource provider to media module and to web module
   // at Concealed state.
+#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \
+    SB_HAS(CONCEALED_STATE)
   media_module_->Resume(GetResourceProvider());
+#endif  // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION ||
+        // SB_HAS(CONCEALED_STATE)
+
   FOR_EACH_OBSERVER(LifecycleObserver, lifecycle_observers_,
                     Unfreeze(GetResourceProvider()));
 }
@@ -1819,11 +1842,11 @@
     return;
   }
 
-  bool splash_screen_ready_to_freeze = splash_screen_ ?
-      splash_screen_->IsReadyToFreeze() : true;
+  bool splash_screen_ready_to_freeze =
+      splash_screen_ ? splash_screen_->IsReadyToFreeze() : true;
 #if defined(ENABLE_DEBUGGER)
-  bool debug_console_ready_to_freeze = debug_console_ ?
-      debug_console_->IsReadyToFreeze() : true;
+  bool debug_console_ready_to_freeze =
+      debug_console_ ? debug_console_->IsReadyToFreeze() : true;
 #endif  // defined(ENABLE_DEBUGGER)
   bool web_module_ready_to_freeze = web_module_->IsReadyToFreeze();
   if (splash_screen_ready_to_freeze &&
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index 0f6648a..d49f817 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -391,6 +391,9 @@
   // Gets the current resource provider.
   render_tree::ResourceProvider* GetResourceProvider();
 
+  // Initialize all components without initializing system window.
+  void InitializeComponents();
+
   // Initializes the system window, and all components that require it.
   void InitializeSystemWindow();
 
diff --git a/src/cobalt/browser/debug_console.cc b/src/cobalt/browser/debug_console.cc
index 5716112..74264c7 100644
--- a/src/cobalt/browser/debug_console.cc
+++ b/src/cobalt/browser/debug_console.cc
@@ -145,7 +145,7 @@
       base::Bind(&DebugConsole::OnError, base::Unretained(this)),
       WebModule::CloseCallback(), /* window_close_callback */
       base::Closure(),            /* window_minimize_callback */
-      NULL /* can_play_type_handler */, NULL /* web_media_player_factory */,
+      NULL /* can_play_type_handler */, NULL /* media_module */,
       network_module, window_dimensions, resource_provider, layout_refresh_rate,
       web_module_options));
 }
diff --git a/src/cobalt/browser/splash_screen.cc b/src/cobalt/browser/splash_screen.cc
index 7d18340..751001c 100644
--- a/src/cobalt/browser/splash_screen.cc
+++ b/src/cobalt/browser/splash_screen.cc
@@ -102,7 +102,7 @@
       *url_to_pass, initial_application_state, render_tree_produced_callback_,
       base::Bind(&OnError), on_window_close,
       base::Closure(),  // window_minimize_callback
-      NULL /* can_play_type_handler */, NULL /* web_media_player_factory */,
+      NULL /* can_play_type_handler */, NULL /* media_module */,
       network_module, window_dimensions, resource_provider, layout_refresh_rate,
       web_module_options));
 }
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index 10124f4..e948d99 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -64,6 +64,8 @@
 #include "cobalt/layout/topmost_event_target.h"
 #include "cobalt/loader/image/animated_image_tracker.h"
 #include "cobalt/loader/switches.h"
+#include "cobalt/media/decoder_buffer_allocator.h"
+#include "cobalt/media/media_module.h"
 #include "cobalt/media_session/media_session_client.h"
 #include "cobalt/script/error_report.h"
 #include "cobalt/script/javascript_engine.h"
@@ -213,8 +215,7 @@
 
   void SetSize(cssom::ViewportSize viewport_size);
   void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
-  void SetWebMediaPlayerFactory(
-      media::WebMediaPlayerFactory* web_media_player_factory);
+  void SetMediaModule(media::MediaModule* media_module);
   void SetImageCacheCapacity(int64_t bytes);
   void SetRemoteTypefaceCacheCapacity(int64_t bytes);
 
@@ -403,6 +404,10 @@
   // See the documentation in base/memory/weak_ptr.h for details.
   base::WeakPtr<dom::Window> window_weak_;
 
+  // Used only when MediaModule is null
+  std::unique_ptr<media::DecoderBufferMemoryInfo>
+      stub_decoder_buffer_memory_info_;
+
   // Environment Settings object
   std::unique_ptr<dom::DOMSettings> environment_settings_;
 
@@ -589,10 +594,20 @@
 
   media_source_registry_.reset(new dom::MediaSource::Registry);
 
+  const media::DecoderBufferMemoryInfo* memory_info = nullptr;
+
+  if (data.media_module) {
+    memory_info = data.media_module->GetDecoderBufferAllocator();
+  } else {
+    stub_decoder_buffer_memory_info_.reset(
+        new media::StubDecoderBufferMemoryInfo);
+    memory_info = stub_decoder_buffer_memory_info_.get();
+  }
+
   environment_settings_.reset(new dom::DOMSettings(
       kDOMMaxElementDepth, fetcher_factory_.get(), data.network_module,
       media_source_registry_.get(), blob_registry_.get(),
-      data.can_play_type_handler, javascript_engine_.get(),
+      data.can_play_type_handler, memory_info, javascript_engine_.get(),
       global_environment_.get(), debugger_hooks_,
       &mutation_observer_task_manager_, data.options.dom_settings_options));
   DCHECK(environment_settings_);
@@ -635,9 +650,9 @@
       animated_image_tracker_.get(), image_cache_.get(),
       reduced_image_cache_capacity_manager_.get(), remote_typeface_cache_.get(),
       mesh_cache_.get(), local_storage_database_.get(),
-      data.can_play_type_handler, data.web_media_player_factory,
-      execution_state_.get(), script_runner_.get(),
-      global_environment_->script_value_factory(), media_source_registry_.get(),
+      data.can_play_type_handler, data.media_module, execution_state_.get(),
+      script_runner_.get(), global_environment_->script_value_factory(),
+      media_source_registry_.get(),
       web_module_stat_tracker_->dom_stat_tracker(), data.initial_url,
       data.network_module->GetUserAgent(),
       data.network_module->preferred_language(),
@@ -687,8 +702,7 @@
 
   window_->navigator()->set_maybefreeze_callback(
       data.options.maybe_freeze_callback);
-  window_->navigator()->set_media_player_factory(
-      data.web_media_player_factory);
+  window_->navigator()->set_media_player_factory(data.media_module);
 
   bool is_concealed =
       (data.initial_application_state == base::kApplicationStateConcealed);
@@ -768,6 +782,7 @@
   topmost_event_target_.reset();
   layout_manager_.reset();
   environment_settings_.reset();
+  stub_decoder_buffer_memory_info_.reset();
   window_weak_.reset();
   window_->ClearPointerStateForShutdown();
   window_ = NULL;
@@ -1069,9 +1084,11 @@
   window_->SetCamera3D(camera_3d);
 }
 
-void WebModule::Impl::SetWebMediaPlayerFactory(
-    media::WebMediaPlayerFactory* web_media_player_factory) {
-  window_->set_web_media_player_factory(web_media_player_factory);
+void WebModule::Impl::SetMediaModule(media::MediaModule* media_module) {
+  SB_DCHECK(media_module);
+  environment_settings_->set_decoder_buffer_memory_info(
+      media_module->GetDecoderBufferAllocator());
+  window_->set_web_media_player_factory(media_module);
 }
 
 void WebModule::Impl::SetApplicationState(base::ApplicationState state) {
@@ -1301,8 +1318,7 @@
     const CloseCallback& window_close_callback,
     const base::Closure& window_minimize_callback,
     media::CanPlayTypeHandler* can_play_type_handler,
-    media::WebMediaPlayerFactory* web_media_player_factory,
-    network::NetworkModule* network_module,
+    media::MediaModule* media_module, network::NetworkModule* network_module,
     const ViewportSize& window_dimensions,
     render_tree::ResourceProvider* resource_provider, float layout_refresh_rate,
     const Options& options)
@@ -1314,9 +1330,9 @@
   ConstructionData construction_data(
       initial_url, initial_application_state, render_tree_produced_callback,
       error_callback, window_close_callback, window_minimize_callback,
-      can_play_type_handler, web_media_player_factory, network_module,
-      window_dimensions, resource_provider, kDOMMaxElementDepth,
-      layout_refresh_rate, ui_nav_root_, options);
+      can_play_type_handler, media_module, network_module, window_dimensions,
+      resource_provider, kDOMMaxElementDepth, layout_refresh_rate, ui_nav_root_,
+      options);
 
   // Start the dedicated thread and create the internal implementation
   // object on that thread.
@@ -1576,12 +1592,10 @@
                             base::Unretained(impl_.get()), camera_3d));
 }
 
-void WebModule::SetWebMediaPlayerFactory(
-    media::WebMediaPlayerFactory* web_media_player_factory) {
+void WebModule::SetMediaModule(media::MediaModule* media_module) {
   message_loop()->task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&WebModule::Impl::SetWebMediaPlayerFactory,
-                 base::Unretained(impl_.get()), web_media_player_factory));
+      FROM_HERE, base::Bind(&WebModule::Impl::SetMediaModule,
+                            base::Unretained(impl_.get()), media_module));
 }
 
 void WebModule::SetImageCacheCapacity(int64_t bytes) {
@@ -1670,8 +1684,8 @@
   DCHECK_NE(base::MessageLoop::current(), message_loop());
 
   message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&WebModule::Impl::Focus,
-                            base::Unretained(impl_.get())));
+      FROM_HERE,
+      base::Bind(&WebModule::Impl::Focus, base::Unretained(impl_.get())));
 }
 
 void WebModule::ReduceMemory() {
@@ -1702,9 +1716,9 @@
 
   volatile bool is_ready_to_freeze = false;
   message_loop()->task_runner()->PostBlockingTask(
-      FROM_HERE, base::Bind(&WebModule::Impl::IsReadyToFreeze,
-                            base::Unretained(impl_.get()),
-                            &is_ready_to_freeze));
+      FROM_HERE,
+      base::Bind(&WebModule::Impl::IsReadyToFreeze,
+                 base::Unretained(impl_.get()), &is_ready_to_freeze));
   return is_ready_to_freeze;
 }
 
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index afbb6a7..ca84be8 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -50,7 +50,7 @@
 #include "cobalt/loader/fetcher_factory.h"
 #include "cobalt/math/size.h"
 #include "cobalt/media/can_play_type_handler.h"
-#include "cobalt/media/web_media_player_factory.h"
+#include "cobalt/media/media_module.h"
 #include "cobalt/network/network_module.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/render_tree/resource_provider.h"
@@ -292,7 +292,7 @@
             const CloseCallback& window_close_callback,
             const base::Closure& window_minimize_callback,
             media::CanPlayTypeHandler* can_play_type_handler,
-            media::WebMediaPlayerFactory* web_media_player_factory,
+            media::MediaModule* media_module,
             network::NetworkModule* network_module,
             const cssom::ViewportSize& window_dimensions,
             render_tree::ResourceProvider* resource_provider,
@@ -371,8 +371,7 @@
   void SetSize(const cssom::ViewportSize& viewport_size);
 
   void SetCamera3D(const scoped_refptr<input::Camera3D>& camera_3d);
-  void SetWebMediaPlayerFactory(
-      media::WebMediaPlayerFactory* web_media_player_factory);
+  void SetMediaModule(media::MediaModule* media_module);
   void SetImageCacheCapacity(int64_t bytes);
   void SetRemoteTypefaceCacheCapacity(int64_t bytes);
 
@@ -417,7 +416,7 @@
         const CloseCallback& window_close_callback,
         const base::Closure& window_minimize_callback,
         media::CanPlayTypeHandler* can_play_type_handler,
-        media::WebMediaPlayerFactory* web_media_player_factory,
+        media::MediaModule* media_module,
         network::NetworkModule* network_module,
         const cssom::ViewportSize& window_dimensions,
         render_tree::ResourceProvider* resource_provider,
@@ -431,7 +430,7 @@
           window_close_callback(window_close_callback),
           window_minimize_callback(window_minimize_callback),
           can_play_type_handler(can_play_type_handler),
-          web_media_player_factory(web_media_player_factory),
+          media_module(media_module),
           network_module(network_module),
           window_dimensions(window_dimensions),
           resource_provider(resource_provider),
@@ -447,7 +446,7 @@
     const CloseCallback& window_close_callback;
     const base::Closure& window_minimize_callback;
     media::CanPlayTypeHandler* can_play_type_handler;
-    media::WebMediaPlayerFactory* web_media_player_factory;
+    media::MediaModule* media_module;
     network::NetworkModule* network_module;
     cssom::ViewportSize window_dimensions;
     render_tree::ResourceProvider* resource_provider;
diff --git a/src/cobalt/build/all.gyp b/src/cobalt/build/all.gyp
index c2db0e4..5c2f484 100644
--- a/src/cobalt/build/all.gyp
+++ b/src/cobalt/build/all.gyp
@@ -109,6 +109,7 @@
         }],
         ['sb_evergreen==1', {
           'dependencies': [
+            '<(DEPTH)/components/update_client/update_client.gyp:cobalt_slot_management_test_deploy',
             '<(DEPTH)/third_party/musl/musl.gyp:musl_unittests',
             '<(DEPTH)/starboard/loader_app/installation_manager.gyp:*',
           ],
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 3fcc752..0d364a4 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-289410
\ No newline at end of file
+292047
\ No newline at end of file
diff --git a/src/cobalt/build/cobalt_configuration.gypi b/src/cobalt/build/cobalt_configuration.gypi
index 7880f93..38e7cf2 100644
--- a/src/cobalt/build/cobalt_configuration.gypi
+++ b/src/cobalt/build/cobalt_configuration.gypi
@@ -130,6 +130,8 @@
     # Build version number.
     'cobalt_version%': '<(BUILD_NUMBER)',
 
+    'cobalt_licenses_platform%': 'default',
+
     # Deprecated. Implement the CobaltExtensionConfigurationApi function
     # CobaltRasterizerType instead.
     # Defines what kind of rasterizer will be used.  This can be adjusted to
diff --git a/src/cobalt/content/licenses/platform/android/licenses_cobalt.txt b/src/cobalt/content/licenses/platform/android/licenses_cobalt.txt
new file mode 100644
index 0000000..e431145
--- /dev/null
+++ b/src/cobalt/content/licenses/platform/android/licenses_cobalt.txt
@@ -0,0 +1,4063 @@
+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)
+
+
+  /* ***** 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 ***** */
+
+
+  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.
+
+
+  xdg_mime
+
+
+  Licensed under the Academic Free License version 2.0 (below)
+  Or under the following terms:
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+
+
+  --------------------------------------------------------------------------------
+  Academic Free License v. 2.0
+  --------------------------------------------------------------------------------
+
+  This Academic Free License (the "License") applies to any original work of
+  authorship (the "Original Work") whose owner (the "Licensor") has placed the
+  following notice immediately following the copyright notice for the Original
+  Work:
+
+  Licensed under the Academic Free License version 2.0
+  1) Grant of Copyright License. Licensor hereby grants You a world-wide,
+  royalty-free, non-exclusive, perpetual, sublicenseable license to do the
+  following:
+
+  a) to reproduce the Original Work in copies;
+  b) to prepare derivative works ("Derivative Works") based upon the Original
+     Work;
+  c) to distribute copies of the Original Work and Derivative Works to the
+     public;
+  d) to perform the Original Work publicly; and
+  e) to display the Original Work publicly.
+
+  2) Grant of Patent License. Licensor hereby grants You a world-wide,
+  royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
+  claims owned or controlled by the Licensor that are embodied in the Original
+  Work as furnished by the Licensor, to make, use, sell and offer for sale the
+  Original Work and Derivative Works.
+
+  3) Grant of Source Code License. The term "Source Code" means the preferred
+  form of the Original Work for making modifications to it and all available
+  documentation describing how to modify the Original Work. Licensor hereby
+  agrees to provide a machine-readable copy of the Source Code of the Original
+  Work along with each copy of the Original Work that Licensor distributes.
+  Licensor reserves the right to satisfy this obligation by placing a
+  machine-readable copy of the Source Code in an information repository
+  reasonably calculated to permit inexpensive and convenient access by You for as
+  long as Licensor continues to distribute the Original Work, and by publishing
+  the address of that information repository in a notice immediately following
+  the copyright notice that applies to the Original Work.
+
+  4) Exclusions From License Grant. Neither the names of Licensor, nor the names
+  of any contributors to the Original Work, nor any of their trademarks or
+  service marks, may be used to endorse or promote products derived from this
+  Original Work without express prior written permission of the Licensor. Nothing
+  in this License shall be deemed to grant any rights to trademarks, copyrights,
+  patents, trade secrets or any other intellectual property of Licensor except as
+  expressly stated herein. No patent license is granted to make, use, sell or
+  offer to sell embodiments of any patent claims other than the licensed claims
+  defined in Section 2. No right is granted to the trademarks of Licensor even if
+  such marks are included in the Original Work. Nothing in this License shall be
+  interpreted to prohibit Licensor from licensing under different terms from this
+  License any Original Work that Licensor otherwise would have a right to
+  license.
+
+  5) This section intentionally omitted.
+
+  6) Attribution Rights. You must retain, in the Source Code of any Derivative
+  Works that You create, all copyright, patent or trademark notices from the
+  Source Code of the Original Work, as well as any notices of licensing and any
+  descriptive text identified therein as an "Attribution Notice." You must cause
+  the Source Code for any Derivative Works that You create to carry a prominent
+  Attribution Notice reasonably calculated to inform recipients that You have
+  modified the Original Work.
+
+  7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
+  the copyright in and to the Original Work and the patent rights granted herein
+  by Licensor are owned by the Licensor or are sublicensed to You under the terms
+  of this License with the permission of the contributor(s) of those copyrights
+  and patent rights. Except as expressly stated in the immediately proceeding
+  sentence, the Original Work is provided under this License on an "AS IS" BASIS
+  and WITHOUT WARRANTY, either express or implied, including, without limitation,
+  the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+  PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
+  This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
+  license to Original Work is granted hereunder except under this disclaimer.
+
+  8) Limitation of Liability. Under no circumstances and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise, shall the
+  Licensor be liable to any person for any direct, indirect, special, incidental,
+  or consequential damages of any character arising as a result of this License
+  or the use of the Original Work including, without limitation, damages for loss
+  of goodwill, work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses. This limitation of liability shall not
+  apply to liability for death or personal injury resulting from Licensor'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.
+
+  9) Acceptance and Termination. If You distribute copies of the Original Work or
+  a Derivative Work, You must make a reasonable effort under the circumstances to
+  obtain the express assent of recipients to the terms of this License. Nothing
+  else but this License (or another written agreement between Licensor and You)
+  grants You permission to create Derivative Works based upon the Original Work
+  or to exercise any of the rights granted in Section 1 herein, and any attempt
+  to do so except under the terms of this License (or another written agreement
+  between Licensor and You) is expressly prohibited by U.S. copyright law, the
+  equivalent laws of other countries, and by international treaty. Therefore, by
+  exercising any of the rights granted to You in Section 1 herein, You indicate
+  Your acceptance of this License and all of its terms and conditions.
+
+  10) Termination for Patent Action. This License shall terminate automatically
+  and You may no longer exercise any of the rights granted to You by this License
+  as of the date You commence an action, including a cross-claim or counterclaim,
+  for patent infringement (i) against Licensor with respect to a patent
+  applicable to software or (ii) against any entity with respect to a patent
+  applicable to the Original Work (but excluding combinations of the Original
+  Work with other software or hardware).
+
+  11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
+  License may be brought only in the courts of a jurisdiction wherein the
+  Licensor resides or in which Licensor conducts its primary business, and under
+  the laws of that jurisdiction excluding its conflict-of-law provisions. The
+  application of the United Nations Convention on Contracts for the International
+  Sale of Goods is expressly excluded. Any use of the Original Work outside the
+  scope of this License or after its termination shall be subject to the
+  requirements and penalties of the U.S. Copyright Act, 17 U.S.C. 101 et seq.,
+  the equivalent laws of other countries, and international treaty. This section
+  shall survive the termination of this License.
+
+  12) Attorneys Fees. In any action to enforce the terms of this License or
+  seeking damages relating thereto, the prevailing party shall be entitled to
+  recover its costs and expenses, including, without limitation, reasonable
+  attorneys' fees and costs incurred in connection with such action, including
+  any appeal of such action. This section shall survive the termination of this
+  License.
+
+  13) 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.
+
+  14) Definition of "You" in This License. "You" throughout this License, whether
+  in upper or lower case, means an individual or a legal entity exercising rights
+  under, and complying with all of the terms of, 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
+  (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.
+
+  15) Right to Use. You may use the Original Work in all ways not otherwise
+  restricted or conditioned by this License or by law, and Licensor promises not
+  to interfere with or be responsible for such uses by You.
+
+  This license is Copyright (C) 2003 Lawrence E. Rosen. All rights reserved.
+  Permission is hereby granted to copy and distribute this license without
+  modification. This license may not be modified without the express written
+  permission of its copyright owner.
+
+
+  xdg_user_dirs
+
+
+  Copyright (c) 2007 Red Hat, inc
+
+  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.
+
+
+  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.
+
+
+
+  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)
+
+
+  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:
+
+  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.
+
+
+
+  dlmalloc
+
+  This is a version (aka dlmalloc) of malloc/free/realloc written by
+  Doug Lea and released to the public domain, as explained at
+  http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
+  comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+
+
+  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
+
+
+  (Copied from the README.)
+
+  --------------------------------------------------------------------------------
+
+  The authors make NO WARRANTY or representation, either express or implied,
+  with respect to this software, its quality, accuracy, merchantability, or
+  fitness for a particular purpose.  This software is provided "AS IS", and you,
+  its user, assume the entire risk as to its quality and accuracy.
+
+  This software is copyright (C) 1991-1998, Thomas G. Lane.
+  All Rights Reserved except as specified below.
+
+  Permission is hereby granted to use, copy, modify, and distribute this
+  software (or portions thereof) for any purpose, without fee, subject to these
+  conditions:
+  (1) If any part of the source code for this software is distributed, then this
+  README file must be included, with this copyright and no-warranty notice
+  unaltered; and any additions, deletions, or changes to the original files
+  must be clearly indicated in accompanying documentation.
+  (2) If only executable code is distributed, then the accompanying
+  documentation must state that "this software is based in part on the work of
+  the Independent JPEG Group".
+  (3) Permission for use of this software is granted only if the user accepts
+  full responsibility for any undesirable consequences; the authors accept
+  NO LIABILITY for damages of any kind.
+
+  These conditions apply to any software derived from or based on the IJG code,
+  not just to the unmodified library.  If you use our work, you ought to
+  acknowledge us.
+
+  Permission is NOT granted for the use of any IJG author's name or company name
+  in advertising or publicity relating to this software or products derived from
+  it.  This software may be referred to only as "the Independent JPEG Group's
+  software".
+
+  We specifically permit and encourage the use of this software as the basis of
+  commercial products, provided that all warranty or liability claims are
+  assumed by the product vendor.
+
+
+  ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+  sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+  ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+  by the usual distribution terms of the Free Software Foundation; principally,
+  that you must include source code if you redistribute it.  (See the file
+  ansi2knr.c for full details.)  However, since ansi2knr.c is not needed as part
+  of any program generated from the IJG code, this does not limit you more than
+  the foregoing paragraphs do.
+
+  The Unix configuration script "configure" was produced with GNU Autoconf.
+  It is copyright by the Free Software Foundation but is freely distributable.
+  The same holds for its supporting scripts (config.guess, config.sub,
+  ltconfig, ltmain.sh).  Another support script, install-sh, is copyright
+  by M.I.T. but is also freely distributable.
+
+  It appears that the arithmetic coding option of the JPEG spec is covered by
+  patents owned by IBM, AT&T, and Mitsubishi.  Hence arithmetic coding cannot
+  legally be used without obtaining one or more licenses.  For this reason,
+  support for arithmetic coding has been removed from the free JPEG software.
+  (Since arithmetic coding provides only a marginal gain over the unpatented
+  Huffman mode, it is unlikely that very many implementations will support it.)
+  So far as we are aware, there are no patent restrictions on the remaining
+  code.
+
+  The IJG distribution formerly included code to read and write GIF files.
+  To avoid entanglement with the Unisys LZW patent, GIF reading support has
+  been removed altogether, and the GIF writer has been simplified to produce
+  "uncompressed GIFs".  This technique does not use the LZW algorithm; the
+  resulting GIF files are larger than usual, but are readable by all standard
+  GIF decoders.
+
+  We are required to state that
+      "The Graphics Interchange Format(c) is the Copyright property of
+      CompuServe Incorporated.  GIF(sm) is a Service Mark property of
+      CompuServe Incorporated."
+
+
+
+  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.
+
+
+  sqlite
+
+
+  The author disclaims copyright to this source code.  In place of
+  a legal notice, here is a blessing:
+
+     May you do good and not evil.
+     May you find forgiveness for yourself and forgive others.
+     May you share freely, never taking more than you give.
+
+
+
+  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.
+
+
+
+  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
+
+  */
+
+
+
+  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.
+
+
+  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.
+
+
+
+  promise-polyfill
+
+
+  Copyright (c) 2014 Taylor Hakes
+  Copyright (c) 2014 Forbes Lindesay
+
+  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.
+
+
+
+  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.
diff --git a/src/cobalt/content/licenses/licenses_cobalt.txt b/src/cobalt/content/licenses/platform/default/licenses_cobalt.txt
similarity index 100%
rename from src/cobalt/content/licenses/licenses_cobalt.txt
rename to src/cobalt/content/licenses/platform/default/licenses_cobalt.txt
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 3810d3d..cce2d9a 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -15,6 +15,7 @@
 #include "cobalt/dom/document.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -528,6 +529,11 @@
 void Document::SetActiveElement(Element* active_element) {
   if (active_element) {
     active_element_ = base::AsWeakPtr(active_element);
+    if (active_element != ui_nav_focus_element_) {
+      // Call UpdateUiNavigationFocus() after UI navigation items have been
+      // updated. This happens during render tree generation from layout.
+      ui_nav_focus_needs_update_ = true;
+    }
   } else {
     active_element_.reset();
   }
@@ -863,6 +869,15 @@
   return true;
 }
 
+void Document::UpdateUiNavigation() {
+  HTMLElement* active_html_element =
+      active_element() ? active_element()->AsHTMLElement() : nullptr;
+  if (active_html_element && ui_nav_focus_needs_update_) {
+    ui_nav_focus_needs_update_ = false;
+    active_html_element->UpdateUiNavigationFocus(/* force_update */ false);
+  }
+}
+
 void Document::SampleTimelineTime() { default_timeline_->Sample(); }
 
 #if defined(ENABLE_PARTIAL_LAYOUT_CONTROL)
@@ -1000,10 +1015,11 @@
 
   // Refocus the previously-focused UI navigation item (if any).
   if (visibility_state == kVisibilityStateVisible) {
-    HTMLElement* active_html_element = active_element() ?
-        active_element()->AsHTMLElement() : nullptr;
+    HTMLElement* active_html_element =
+        active_element() ? active_element()->AsHTMLElement() : nullptr;
     if (active_html_element) {
-      active_html_element->RefocusUiNavItem();
+      ui_nav_focus_needs_update_ = false;
+      active_html_element->UpdateUiNavigationFocus(/* force_update */ true);
     }
   }
 }
@@ -1024,10 +1040,10 @@
 void Document::CollectHTMLMediaElements(
     std::vector<HTMLMediaElement*>* html_media_elements) {
   scoped_refptr<HTMLElement> root = html();
-    if (root) {
-      DCHECK_EQ(this, root->parent_node());
-      root->CollectHTMLMediaElementsRecursively(html_media_elements, 0);
-    }
+  if (root) {
+    DCHECK_EQ(this, root->parent_node());
+    root->CollectHTMLMediaElementsRecursively(html_media_elements, 0);
+  }
 }
 
 // Algorithm for 'freeze steps'
@@ -1047,8 +1063,8 @@
   // 3. Let elements be all media elements that are shadow-including
   //    documents of doc, in shadow-including tree order.
   //    Note: Cobalt currently only supports one document.
-  std::unique_ptr<std::vector<HTMLMediaElement*>>
-      html_media_elements(new std::vector<HTMLMediaElement*>());
+  std::unique_ptr<std::vector<HTMLMediaElement*>> html_media_elements(
+      new std::vector<HTMLMediaElement*>());
   CollectHTMLMediaElements(html_media_elements.get());
 
   // 4. For each element in elements:
@@ -1074,8 +1090,8 @@
   // 1. Let elements be all media elements that are shadow-including
   //    documents of doc, in shadow-including tree order.
   //    Note: Cobalt currently only supports one document.
-  std::unique_ptr<std::vector<HTMLMediaElement*>>
-      html_media_elements(new std::vector<HTMLMediaElement*>());
+  std::unique_ptr<std::vector<HTMLMediaElement*>> html_media_elements(
+      new std::vector<HTMLMediaElement*>());
   CollectHTMLMediaElements(html_media_elements.get());
 
   // 2. For each element in elements:
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index 18bcaaa..627cfae 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <queue>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
 #include "base/callback.h"
@@ -343,6 +344,31 @@
   // Returns whether the computed style is valid after the call.
   bool UpdateComputedStyleOnElementAndAncestor(HTMLElement* element);
 
+  // Called periodically to update the UI navigation system.
+  void UpdateUiNavigation();
+
+  // Track UI navigation system's focus element.
+  const void* ui_nav_focus_element() const { return ui_nav_focus_element_; }
+  void set_ui_nav_focus_element(const void* focus_element) {
+    ui_nav_focus_element_ = focus_element;
+  }
+
+  // Track HTML elements that are UI navigtion items. This facilitates updating
+  // their layout information as needed.
+  void AddUiNavigationElement(HTMLElement* element) {
+    ui_nav_elements_.insert(element);
+  }
+  void RemoveUiNavigationElement(HTMLElement* element) {
+    ui_nav_elements_.erase(element);
+  }
+  const std::unordered_set<HTMLElement*>& ui_navigation_elements() const {
+    return ui_nav_elements_;
+  }
+  void set_ui_nav_needs_layout(bool needs_layout) {
+    ui_nav_needs_layout_ = needs_layout;
+  }
+  bool ui_nav_needs_layout() const { return ui_nav_needs_layout_; }
+
   // Manages the clock used by Web Animations.
   //     https://www.w3.org/TR/web-animations
   // This clock is also used for requestAnimationFrame() callbacks, according
@@ -591,6 +617,22 @@
   //   https://wicg.github.io/page-lifecycle/#page-lifecycle
   bool frozenness_;
 
+  // Indicates whether UI navigation focus needs to be updated.
+  bool ui_nav_focus_needs_update_ = false;
+
+  // Track the current focus of UI navigation. This is only an identifier and
+  // not meant to be dereferenced.
+  const void* ui_nav_focus_element_ = nullptr;
+
+  // Track all HTMLElements in this document which are UI navigation items.
+  // These should be raw pointers to avoid affecting the elements' ref counts.
+  // The elements will explicitly add and remove themselves from this set.
+  std::unordered_set<HTMLElement*> ui_nav_elements_;
+
+  // This specifies whether the UI navigation HTML elements need updating during
+  // layout.
+  bool ui_nav_needs_layout_ = false;
+
   scoped_refptr<IntersectionObserverTaskManager>
       intersection_observer_task_manager_;
 };
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index c01b17a..366eaab 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -364,8 +364,8 @@
       ],
       'copies': [
         {
-          'destination': '<(sb_static_contents_output_data_dir)',
-          'files': ['<(static_contents_source_dir)/licenses/'],
+          'destination': '<(sb_static_contents_output_data_dir)/licenses',
+          'files': ['<(static_contents_source_dir)/licenses/platform/<(cobalt_licenses_platform)/licenses_cobalt.txt'],
         },
       ],
       'all_dependent_settings': {
diff --git a/src/cobalt/dom/dom_settings.cc b/src/cobalt/dom/dom_settings.cc
index d525a3b..49b2d71 100644
--- a/src/cobalt/dom/dom_settings.cc
+++ b/src/cobalt/dom/dom_settings.cc
@@ -26,6 +26,7 @@
     network::NetworkModule* network_module,
     MediaSourceRegistry* media_source_registry, Blob::Registry* blob_registry,
     media::CanPlayTypeHandler* can_play_type_handler,
+    const media::DecoderBufferMemoryInfo* decoder_buffer_memory_info,
     script::JavaScriptEngine* engine,
     script::GlobalEnvironment* global_environment,
     const base::DebuggerHooks& debugger_hooks,
@@ -38,6 +39,7 @@
       media_source_registry_(media_source_registry),
       blob_registry_(blob_registry),
       can_play_type_handler_(can_play_type_handler),
+      decoder_buffer_memory_info_(decoder_buffer_memory_info),
       javascript_engine_(engine),
       global_environment_(global_environment),
       debugger_hooks_(debugger_hooks),
diff --git a/src/cobalt/dom/dom_settings.h b/src/cobalt/dom/dom_settings.h
index ca8d674..e5d8b78 100644
--- a/src/cobalt/dom/dom_settings.h
+++ b/src/cobalt/dom/dom_settings.h
@@ -22,6 +22,7 @@
 #include "cobalt/dom/url_registry.h"
 #include "cobalt/dom/url_utils.h"
 #include "cobalt/media/can_play_type_handler.h"
+#include "cobalt/media/decoder_buffer_memory_info.h"
 #include "cobalt/script/environment_settings.h"
 #include "cobalt/speech/microphone.h"
 
@@ -58,6 +59,7 @@
               MediaSourceRegistry* media_source_registry,
               Blob::Registry* blob_registry,
               media::CanPlayTypeHandler* can_play_type_handler,
+              const media::DecoderBufferMemoryInfo* decoder_buffer_memory_info,
               script::JavaScriptEngine* engine,
               script::GlobalEnvironment* global_environment_proxy,
               const base::DebuggerHooks& debugger_hooks,
@@ -90,6 +92,25 @@
   MediaSourceRegistry* media_source_registry() const {
     return media_source_registry_;
   }
+  std::size_t media_source_size_limit() const {
+    return decoder_buffer_memory_info_
+               ? decoder_buffer_memory_info_->GetMaximumMemoryCapacity()
+               : 0;
+  }
+  std::size_t total_media_source_size() const {
+    return decoder_buffer_memory_info_
+               ? decoder_buffer_memory_info_->GetCurrentMemoryCapacity()
+               : 0;
+  }
+  std::size_t used_media_source_memory_size() const {
+    return decoder_buffer_memory_info_
+               ? decoder_buffer_memory_info_->GetAllocatedMemory()
+               : 0;
+  }
+  void set_decoder_buffer_memory_info(
+      const media::DecoderBufferMemoryInfo* decoder_buffer_memory_info) {
+    decoder_buffer_memory_info_ = decoder_buffer_memory_info;
+  }
   media::CanPlayTypeHandler* can_play_type_handler() const {
     return can_play_type_handler_;
   }
@@ -114,6 +135,7 @@
   MediaSourceRegistry* media_source_registry_;
   Blob::Registry* blob_registry_;
   media::CanPlayTypeHandler* can_play_type_handler_;
+  const media::DecoderBufferMemoryInfo* decoder_buffer_memory_info_;
   script::JavaScriptEngine* javascript_engine_;
   script::GlobalEnvironment* global_environment_;
   const base::DebuggerHooks& debugger_hooks_;
diff --git a/src/cobalt/dom/event_target_test.cc b/src/cobalt/dom/event_target_test.cc
index abe5152..94192f3 100644
--- a/src/cobalt/dom/event_target_test.cc
+++ b/src/cobalt/dom/event_target_test.cc
@@ -19,8 +19,8 @@
 #include "cobalt/base/polymorphic_downcast.h"
 #include "cobalt/dom/dom_exception.h"
 #include "cobalt/dom/dom_settings.h"
-#include "cobalt/dom/testing/mock_event_listener.h"
 #include "cobalt/dom/global_stats.h"
+#include "cobalt/dom/testing/mock_event_listener.h"
 #include "cobalt/script/testing/fake_script_value.h"
 #include "cobalt/script/testing/mock_exception_state.h"
 #include "cobalt/test/mock_debugger_hooks.h"
@@ -51,10 +51,10 @@
  protected:
   EventTargetTest()
       : environment_settings_(0, nullptr, nullptr, nullptr, nullptr, nullptr,
-                              nullptr, nullptr, debugger_hooks_, nullptr,
-                              DOMSettings::Options()) {
-        EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
-      }
+                              nullptr, nullptr, nullptr, debugger_hooks_,
+                              nullptr, DOMSettings::Options()) {
+    EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
+  }
   ~EventTargetTest() override {
     EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks());
   }
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index e3f92a6..c02f298 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -80,11 +80,6 @@
 // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
 const int32 kUiNavFocusTabIndexThreshold = -2;
 
-// Track which HTMLElement is currently focused by UI navigation so that
-// redundant blur / focus events are not fired. Do not de-reference this
-// variable -- it is only meant to identify objects.
-const HTMLElement* g_ui_nav_focus_ = nullptr;
-
 struct NonTrivialStaticFields {
   NonTrivialStaticFields() {
     cssom::PropertyKeyVector computed_style_invalidation_properties;
@@ -1026,6 +1021,10 @@
   if (!is_valid) {
     UpdateComputedStyle(parent_computed_style_declaration, root_computed_style,
                         style_change_event_time, kAncestorsAreDisplayed);
+    UpdateUiNavigation();
+    node_document()->set_ui_nav_needs_layout(true);
+  } else if (ui_nav_needs_update_) {
+    UpdateUiNavigation();
   }
 
   // Do not update computed style for descendants of "display: none" elements,
@@ -1171,8 +1170,8 @@
 }
 
 void HTMLElement::OnUiNavBlur() {
-  if (g_ui_nav_focus_ == this) {
-    g_ui_nav_focus_ = nullptr;
+  if (node_document() && node_document()->ui_nav_focus_element() == this) {
+    node_document()->set_ui_nav_focus_element(nullptr);
     Blur();
   }
 }
@@ -1180,8 +1179,8 @@
 void HTMLElement::OnUiNavFocus() {
   // Suppress the focus event if this is already focused -- i.e. the HTMLElement
   // initiated the focus change that resulted in this call to OnUiNavFocus.
-  if (g_ui_nav_focus_ != this) {
-    g_ui_nav_focus_ = this;
+  if (node_document() && node_document()->ui_nav_focus_element() != this) {
+    node_document()->set_ui_nav_focus_element(this);
     Focus();
   }
 }
@@ -1338,45 +1337,6 @@
     old_active_element->AsHTMLElement()->RunUnFocusingSteps();
   }
 
-  // Custom, not in any spec.
-  // Set the focus item for the UI navigation system. Search up the DOM tree to
-  // find the nearest ancestor that is a UI navigation item if needed. Do this
-  // step before dispatching events as the event handlers may make UI navigation
-  // changes.
-  for (Node* node = this; node; node = node->parent_node()) {
-    Element* element = node->AsElement();
-    if (!element) {
-      continue;
-    }
-    HTMLElement* html_element = element->AsHTMLElement();
-    if (!html_element) {
-      continue;
-    }
-    if (!html_element->ui_nav_item_ ||
-        html_element->ui_nav_item_->IsContainer()) {
-      continue;
-    }
-    if (g_ui_nav_focus_ == html_element) {
-      // UI navigation is already focused on the correct element.
-      break;
-    }
-    // Updating the g_ui_nav_focus_ has the additional effect of suppressing
-    // the Blur call for the previously focused HTMLElement and the Focus call
-    // for this HTMLElement as a result of OnUiNavBlur / OnUiNavFocus callbacks
-    // that result from initiating the UI navigation focus change.
-    g_ui_nav_focus_ = html_element;
-    // Only navigation items attached to the root container are interactable.
-    // If the item is not registered with a container, then force a layout to
-    // connect items to their containers and eventually to the root container.
-    scoped_refptr<ui_navigation::NavItem> nav_item = html_element->ui_nav_item_;
-    if (!nav_item->GetContainerItem()) {
-      // UI navigation items are updated as part of generating the render tree.
-      node_document()->DoSynchronousLayoutAndGetRenderTree();
-    }
-    nav_item->Focus();
-    break;
-  }
-
   // focusin: A user agent MUST dispatch this event when an event target is
   // about to receive focus. This event type MUST be dispatched before the
   // element is given focus. The event target MUST be the element which is about
@@ -1442,7 +1402,11 @@
   ClearRuleMatchingState();
 }
 
-void HTMLElement::RefocusUiNavItem() {
+void HTMLElement::UpdateUiNavigationFocus(bool force_focus) {
+  if (!node_document()) {
+    return;
+  }
+
   // Set the focus item for the UI navigation system. Search up the DOM tree to
   // find the nearest ancestor that is a UI navigation item if needed. Do this
   // step before dispatching events as the event handlers may make UI navigation
@@ -1460,11 +1424,16 @@
         html_element->ui_nav_item_->IsContainer()) {
       continue;
     }
-    // Updating the g_ui_nav_focus_ has the additional effect of suppressing
-    // the Blur call for the previously focused HTMLElement and the Focus call
-    // for this HTMLElement as a result of OnUiNavBlur / OnUiNavFocus callbacks
-    // that result from initiating the UI navigation focus change.
-    g_ui_nav_focus_ = html_element;
+    if (node_document()->ui_nav_focus_element() == html_element &&
+        !force_focus) {
+      // UI navigation is already focused on the correct element.
+      break;
+    }
+    // Updating the UI navigation focus element has the additional effect of
+    // suppressing the Blur call for the previously focused HTMLElement and the
+    // Focus call for this HTMLElement as a result of OnUiNavBlur / OnUiNavFocus
+    // callbacks that result from initiating the UI navigation focus change.
+    node_document()->set_ui_nav_focus_element(html_element);
     html_element->ui_nav_item_->Focus();
     break;
   }
@@ -1503,6 +1472,9 @@
   } else {
     tabindex_ = base::nullopt;
   }
+
+  // Changing the tabindex may trigger a UI navigation change.
+  ui_nav_needs_update_ = true;
 }
 
 namespace {
@@ -2063,11 +2035,6 @@
     }
   }
 
-  // Update the UI navigation item and invalidate layout boxes if needed.
-  if (!UpdateUiNavigationAndReturnIfLayoutBoxesAreValid()) {
-    invalidation_flags.invalidate_layout_boxes = true;
-  }
-
   if (invalidation_flags.mark_descendants_as_display_none) {
     MarkNotDisplayedOnDescendants();
   }
@@ -2149,7 +2116,9 @@
          computed_style()->visibility() == cssom::KeywordValue::GetVisible();
 }
 
-bool HTMLElement::UpdateUiNavigationAndReturnIfLayoutBoxesAreValid() {
+void HTMLElement::UpdateUiNavigation() {
+  ui_nav_needs_update_ = false;
+
   base::Optional<ui_navigation::NativeItemType> ui_nav_item_type;
   if (tabindex_ && *tabindex_ <= kUiNavFocusTabIndexThreshold &&
       computed_style()->pointer_events() != cssom::KeywordValue::GetNone()) {
@@ -2159,7 +2128,7 @@
     ui_nav_item_type = ui_navigation::kNativeItemTypeContainer;
   }
 
-  if (ui_nav_item_type && IsDisplayed()) {
+  if (ui_nav_item_type && IsDisplayed() && node_document()) {
     ui_navigation::NativeItemDir ui_nav_item_dir;
     ui_nav_item_dir.is_left_to_right =
         directionality() == kLeftToRightDirectionality;
@@ -2169,7 +2138,7 @@
       if (ui_nav_item_->GetType() == *ui_nav_item_type) {
         // Keep using the existing navigation item.
         ui_nav_item_->SetDir(ui_nav_item_dir);
-        return true;
+        return;
       }
       // The current navigation item isn't of the correct type. Disable it so
       // that callbacks won't be invoked for it. The object will be destroyed
@@ -2195,23 +2164,28 @@
             FROM_HERE,
             base::Bind(&HTMLElement::OnUiNavScroll, base::AsWeakPtr(this))));
     ui_nav_item_->SetDir(ui_nav_item_dir);
-    return false;
+
+    node_document()->AddUiNavigationElement(this);
+    node_document()->set_ui_nav_needs_layout(true);
+    InvalidateLayoutBoxRenderTreeNodes();
   } else if (ui_nav_item_) {
     // This navigation item is no longer relevant.
     ReleaseUiNavigationItem();
-    return false;
+    InvalidateLayoutBoxRenderTreeNodes();
   }
-
-  return true;
 }
 
 void HTMLElement::ReleaseUiNavigationItem() {
   if (ui_nav_item_) {
     // Disable the UI navigation item so it won't receive anymore callbacks
     // while being released.
-    if (g_ui_nav_focus_ == this) {
-      g_ui_nav_focus_ = nullptr;
-      ui_nav_item_->UnfocusAll();
+    if (node_document()) {
+      node_document()->RemoveUiNavigationElement(this);
+      node_document()->set_ui_nav_needs_layout(true);
+      if (node_document()->ui_nav_focus_element() == this) {
+        node_document()->set_ui_nav_focus_element(nullptr);
+        ui_nav_item_->UnfocusAll();
+      }
     }
     ui_nav_item_->SetEnabled(false);
     ui_nav_item_ = nullptr;
diff --git a/src/cobalt/dom/html_element.h b/src/cobalt/dom/html_element.h
index 7bb152c..2eddb38 100644
--- a/src/cobalt/dom/html_element.h
+++ b/src/cobalt/dom/html_element.h
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/compiler_specific.h"
@@ -363,10 +364,9 @@
     return ui_nav_item_;
   }
 
-  // Reset focus on the associated UI navigation item (if any). This is used
-  // when resuming from the conealed state, in case the underlying UI navigation
-  // system was reset during the conceal.
-  void RefocusUiNavItem();
+  // Update the UI navigation system to focus on the relevant navigation item
+  // for this HTML element (if any).
+  void UpdateUiNavigationFocus(bool force_focus);
 
   // Returns true if the element is the root element as defined in
   // https://www.w3.org/TR/html50/semantics.html#the-root-element.
@@ -424,7 +424,7 @@
   void ClearRuleMatchingStateInternal(bool invalidate_descendants);
 
   // Update the UI navigation item type for this element.
-  bool UpdateUiNavigationAndReturnIfLayoutBoxesAreValid();
+  void UpdateUiNavigation();
   void ReleaseUiNavigationItem();
 
   // Clear the list of active background images, and notify the animated image
@@ -521,6 +521,9 @@
   // boxes without requiring a new layout.
   scoped_refptr<ui_navigation::NavItem> ui_nav_item_;
 
+  // Signal whether the UI navigation item may need to be updated.
+  bool ui_nav_needs_update_ = false;
+
   // HTMLElement is a friend of Animatable so that animatable can insert and
   // remove animations into HTMLElement's set of animations.
   friend class DOMAnimatable;
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index beb04c7..13fbcc8 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -17,6 +17,7 @@
 #include <algorithm>
 #include <limits>
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
@@ -154,13 +155,14 @@
       sent_end_event_(false),
       request_mode_(loader::kNoCORSMode) {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::HTMLMediaElement()");
-  MLOG();
+  LOG(INFO) << "Create HTMLMediaElement with volume " << volume_
+            << ", playback rate " << playback_rate_ << ".";
   ON_INSTANCE_CREATED(HTMLMediaElement);
 }
 
 HTMLMediaElement::~HTMLMediaElement() {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::~HTMLMediaElement()");
-  MLOG();
+  LOG(INFO) << "Destroy HTMLMediaElement.";
   ClearMediaSource();
   ON_INSTANCE_RELEASED(HTMLMediaElement);
 }
@@ -177,7 +179,7 @@
 
 void HTMLMediaElement::set_src(const std::string& src) {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::set_src()");
-  MLOG() << src;
+  LOG(INFO) << "Set src to \"" << src << "\".";
   SetAttribute("src", src);
   ClearMediaPlayer();
   ScheduleLoad();
@@ -212,7 +214,7 @@
   scoped_refptr<TimeRanges> buffered = new TimeRanges;
 
   if (!player_) {
-    MLOG() << "(empty)";
+    LOG(INFO) << "(empty)";
     return buffered;
   }
 
@@ -347,9 +349,8 @@
 
 float HTMLMediaElement::current_time(
     script::ExceptionState* exception_state) const {
-
   if (!player_) {
-    MLOG() << 0 << " (because player is NULL)";
+    LOG(INFO) << 0 << " (because player is NULL)";
     return 0;
   }
 
@@ -371,11 +372,10 @@
   // WebMediaPlayer::kReadyStateHaveNothing, then raise an INVALID_STATE_ERR
   // exception.
   if (ready_state_ == WebMediaPlayer::kReadyStateHaveNothing || !player_) {
-    MLOG() << "invalid state error";
+    LOG(ERROR) << "invalid state error";
     DOMException::Raise(DOMException::kInvalidStateErr, exception_state);
     return;
   }
-  MLOG() << "seek to " << time;
   Seek(time);
 }
 
@@ -418,7 +418,8 @@
 }
 
 void HTMLMediaElement::set_playback_rate(float rate) {
-  MLOG() << rate;
+  LOG(INFO) << "Change playback rate from " << playback_rate_ << " to " << rate
+            << ".";
 
   if (playback_rate_ != rate) {
     playback_rate_ = rate;
@@ -472,7 +473,7 @@
 }
 
 void HTMLMediaElement::set_autoplay(bool autoplay) {
-  MLOG() << autoplay;
+  LOG(INFO) << "Set autoplay to " << autoplay << ".";
   // The value of 'autoplay' is true when the 'autoplay' attribute is present.
   // The value of the attribute is irrelevant.
   if (autoplay) {
@@ -488,6 +489,7 @@
 }
 
 void HTMLMediaElement::set_loop(bool loop) {
+  LOG(INFO) << "Set loop to " << loop << ".";
   // The value of 'loop' is true when the 'loop' attribute is present.
   // The value of the attribute is irrelevant.
   if (loop) {
@@ -499,7 +501,7 @@
 
 void HTMLMediaElement::Play() {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::Play()");
-  MLOG();
+  LOG(INFO) << "Play.";
   // 4.8.10.9. Playing the media resource
   if (!player_ || network_state_ == kNetworkEmpty) {
     ScheduleLoad();
@@ -526,7 +528,7 @@
 
 void HTMLMediaElement::Pause() {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::Pause()");
-  MLOG();
+  LOG(INFO) << "Pause.";
   // 4.8.10.9. Playing the media resource
   if (!player_ || network_state_ == kNetworkEmpty) {
     ScheduleLoad();
@@ -565,7 +567,7 @@
 
 void HTMLMediaElement::set_volume(float volume,
                                   script::ExceptionState* exception_state) {
-  MLOG() << volume;
+  LOG(INFO) << "Change volume from " << volume_ << " to " << volume << ".";
   if (volume < 0.0f || volume > 1.0f) {
     DOMException::Raise(DOMException::kIndexSizeErr, exception_state);
     return;
@@ -584,7 +586,7 @@
 }
 
 void HTMLMediaElement::set_muted(bool muted) {
-  MLOG() << muted;
+  LOG(INFO) << "Change muted from " << muted_ << " to " << muted << ".";
   if (muted_ != muted) {
     muted_ = muted;
     // Avoid recursion when the player reports volume changes.
@@ -638,13 +640,13 @@
 
 void HTMLMediaElement::ScheduleEvent(const scoped_refptr<Event>& event) {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::ScheduleEvent()");
-  MLOG() << event->type();
+  LOG(INFO) << "Schedule event " << event->type() << ".";
   event_queue_.Enqueue(event);
 }
 
 void HTMLMediaElement::CreateMediaPlayer() {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::CreateMediaPlayer()");
-  MLOG();
+  LOG(INFO) << "Create media player.";
   if (src().empty()) {
     reduced_image_cache_capacity_request_ = base::nullopt;
   } else if (html_element_context()
@@ -901,7 +903,7 @@
 
 void HTMLMediaElement::ClearMediaPlayer() {
   TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::ClearMediaPlayer()");
-  MLOG();
+  LOG(INFO) << "Clear media player.";
 
   ClearMediaSource();
 
@@ -1082,6 +1084,8 @@
 void HTMLMediaElement::SetReadyState(WebMediaPlayer::ReadyState state) {
   TRACE_EVENT1("cobalt::dom", "HTMLMediaElement::SetReadyState()", "state",
                state);
+  LOG(INFO) << "Set ready state from " << ready_state_ << " to " << state
+            << ".";
   // Set "was_potentially_playing" BEFORE updating ready_state_,
   // PotentiallyPlaying() uses it
   bool was_potentially_playing = PotentiallyPlaying();
@@ -1173,6 +1177,8 @@
 }
 
 void HTMLMediaElement::SetNetworkState(WebMediaPlayer::NetworkState state) {
+  LOG(INFO) << "Set network state from " << network_state_ << " to " << state
+            << ".";
   switch (state) {
     case WebMediaPlayer::kNetworkStateEmpty:
       // Just update the cached state and leave, we can't do anything.
@@ -1208,6 +1214,8 @@
 
 void HTMLMediaElement::SetNetworkError(WebMediaPlayer::NetworkState state,
                                        const std::string& message) {
+  LOG(ERROR) << "Set network error " << state << " with message \"" << message
+             << "\".";
   switch (state) {
     case WebMediaPlayer::kNetworkStateFormatError:
     case WebMediaPlayer::kNetworkStateNetworkError:
@@ -1235,6 +1243,7 @@
 }
 
 void HTMLMediaElement::Seek(float time) {
+  LOG(INFO) << "Seek to " << time << ".";
   // 4.8.9.9 Seeking - continued from set_current_time().
 
   // Check state again as Seek() can be called by HTMLMediaElement internally.
@@ -1318,6 +1327,7 @@
 }
 
 void HTMLMediaElement::FinishSeek() {
+  LOG(INFO) << "Finish seek.";
   // 4.8.10.9 Seeking step 14
   seeking_ = false;
 
@@ -1433,7 +1443,6 @@
       return true;
     }
   }
-
   return false;
 }
 
@@ -1446,7 +1455,6 @@
 }
 
 void HTMLMediaElement::MediaEngineError(scoped_refptr<MediaError> error) {
-  MLOG() << error->code();
   if (error->message().empty()) {
     LOG(WARNING) << "HTMLMediaElement::MediaEngineError " << error->code();
   } else {
@@ -1532,6 +1540,7 @@
   eos_played |=
       !SbDoubleIsNan(dur) && (0.0f != dur) && now >= dur && playback_rate_ > 0;
   if (eos_played) {
+    LOG(INFO) << "End of stream is played.";
     // If the media element has a loop attribute specified and does not have a
     // current media controller,
     if (loop()) {
@@ -1655,9 +1664,14 @@
   }
 
   if (!filter) {
+    LOG(WARNING) << "PreferDecodeToTexture() could not find filter "
+                    "property.";
     return false;
   }
 
+  LOG(INFO) << "PreferDecodeToTexture() get filter property: "
+            << filter->ToString() << ".";
+
   const cssom::MapToMeshFunction* map_to_mesh_filter =
       cssom::MapToMeshFunction::ExtractFromFilterList(filter);
 
diff --git a/src/cobalt/dom/memory_info.cc b/src/cobalt/dom/memory_info.cc
index 06ef819..cc0155f 100644
--- a/src/cobalt/dom/memory_info.cc
+++ b/src/cobalt/dom/memory_info.cc
@@ -45,5 +45,30 @@
           .used_heap_size);
 }
 
+uint32 MemoryInfo::media_source_size_limit(
+    script::EnvironmentSettings* environment_settings) const {
+  DOMSettings* settings =
+      base::polymorphic_downcast<DOMSettings*>(environment_settings);
+  return settings ? static_cast<uint32>(settings->media_source_size_limit())
+                  : 0u;
+}
+
+uint32 MemoryInfo::total_media_source_size(
+    script::EnvironmentSettings* environment_settings) const {
+  DOMSettings* settings =
+      base::polymorphic_downcast<DOMSettings*>(environment_settings);
+  return settings ? static_cast<uint32>(settings->total_media_source_size())
+                  : 0u;
+}
+
+uint32 MemoryInfo::used_media_source_memory_size(
+    script::EnvironmentSettings* environment_settings) const {
+  DOMSettings* settings =
+      base::polymorphic_downcast<DOMSettings*>(environment_settings);
+  return settings
+             ? static_cast<uint32>(settings->used_media_source_memory_size())
+             : 0u;
+}
+
 }  // namespace dom
 }  // namespace cobalt
diff --git a/src/cobalt/dom/memory_info.h b/src/cobalt/dom/memory_info.h
index 13ff2f9..a6e4dcf 100644
--- a/src/cobalt/dom/memory_info.h
+++ b/src/cobalt/dom/memory_info.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_DOM_MEMORY_INFO_H_
 #define COBALT_DOM_MEMORY_INFO_H_
 
+#include "cobalt/media/decoder_buffer_allocator.h"
 #include "cobalt/script/environment_settings.h"
 #include "cobalt/script/wrappable.h"
 
@@ -32,6 +33,12 @@
       script::EnvironmentSettings* environment_settings) const;
   uint32 used_js_heap_size(
       script::EnvironmentSettings* environment_settings) const;
+  uint32 media_source_size_limit(
+      script::EnvironmentSettings* environment_settings) const;
+  uint32 total_media_source_size(
+      script::EnvironmentSettings* environment_settings) const;
+  uint32 used_media_source_memory_size(
+      script::EnvironmentSettings* environment_settings) const;
 
   DEFINE_WRAPPABLE_TYPE(MemoryInfo);
 
diff --git a/src/cobalt/dom/memory_info.idl b/src/cobalt/dom/memory_info.idl
index db9b747..4308390 100644
--- a/src/cobalt/dom/memory_info.idl
+++ b/src/cobalt/dom/memory_info.idl
@@ -20,4 +20,8 @@
 ] interface MemoryInfo {
   [CallWith=EnvironmentSettings] readonly attribute unsigned long totalJSHeapSize;
   [CallWith=EnvironmentSettings] readonly attribute unsigned long usedJSHeapSize;
+
+  [CallWith=EnvironmentSettings] readonly attribute unsigned long mediaSourceSizeLimit;
+  [CallWith=EnvironmentSettings] readonly attribute unsigned long totalMediaSourceSize;
+  [CallWith=EnvironmentSettings] readonly attribute unsigned long usedMediaSourceMemorySize;
 };
diff --git a/src/cobalt/dom/testing/stub_environment_settings.h b/src/cobalt/dom/testing/stub_environment_settings.h
index 03c7266..95ed623 100644
--- a/src/cobalt/dom/testing/stub_environment_settings.h
+++ b/src/cobalt/dom/testing/stub_environment_settings.h
@@ -26,7 +26,7 @@
  public:
   explicit StubEnvironmentSettings(const Options& options = Options())
       : DOMSettings(0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
-                    nullptr, null_debugger_hooks_, nullptr, options) {}
+                    nullptr, nullptr, null_debugger_hooks_, nullptr, options) {}
   ~StubEnvironmentSettings() override {}
 
  private:
diff --git a/src/cobalt/dom/testing/stub_window.h b/src/cobalt/dom/testing/stub_window.h
index 2631d15..3107483 100644
--- a/src/cobalt/dom/testing/stub_window.h
+++ b/src/cobalt/dom/testing/stub_window.h
@@ -64,7 +64,7 @@
         environment_settings.get()
             ? std::move(environment_settings)
             : std::unique_ptr<script::EnvironmentSettings>(new DOMSettings(
-                  0, NULL, NULL, NULL, NULL, NULL, engine_.get(),
+                  0, NULL, NULL, NULL, NULL, NULL, NULL, engine_.get(),
                   global_environment(), null_debugger_hooks_, NULL));
     window_ = new dom::Window(
         environment_settings_.get(), cssom::ViewportSize(1920, 1080),
diff --git a/src/cobalt/extension/media_session.h b/src/cobalt/extension/media_session.h
index eb91f7c..91ab5b2 100644
--- a/src/cobalt/extension/media_session.h
+++ b/src/cobalt/extension/media_session.h
@@ -89,6 +89,7 @@
   CobaltExtensionMediaMetadata* metadata;
   double actual_playback_rate;
   SbTimeMonotonic current_playback_position;
+  bool has_position_state;
 } CobaltExtensionMediaSessionState;
 
 typedef struct CobaltExtensionMediaSessionApi {
@@ -114,7 +115,7 @@
 
   // Destory platform's MediaSessionClient after the Cobalt's
   // MediaSessionClient has been destroyed.
-  void (*DestroyMediaSessionClientCallback) ();
+  void (*DestroyMediaSessionClientCallback)();
 } CobaltExtensionMediaSessionApi;
 
 inline void CobaltExtensionMediaSessionActionDetailsInit(
diff --git a/src/cobalt/h5vcc/h5vcc_updater.cc b/src/cobalt/h5vcc/h5vcc_updater.cc
index bebd3b0..7db80e6 100644
--- a/src/cobalt/h5vcc/h5vcc_updater.cc
+++ b/src/cobalt/h5vcc/h5vcc_updater.cc
@@ -14,6 +14,12 @@
 
 #include "cobalt/h5vcc/h5vcc_updater.h"
 
+namespace {
+
+const uint16 kInvalidInstallationIndex = 1000;
+
+}  // namespace
+
 namespace cobalt {
 namespace h5vcc {
 
@@ -52,5 +58,14 @@
   }
 }
 
+uint16 H5vccUpdater::GetInstallationIndex() const {
+  if (!updater_module_) {
+    return kInvalidInstallationIndex;
+  }
+  int index = updater_module_->GetInstallationIndex();
+
+  return index == -1 ? kInvalidInstallationIndex : static_cast<uint16>(index);
+}
+
 }  // namespace h5vcc
 }  // namespace cobalt
diff --git a/src/cobalt/h5vcc/h5vcc_updater.h b/src/cobalt/h5vcc/h5vcc_updater.h
index 6578e58..841b893 100644
--- a/src/cobalt/h5vcc/h5vcc_updater.h
+++ b/src/cobalt/h5vcc/h5vcc_updater.h
@@ -44,6 +44,8 @@
 
   void ResetInstallations();
 
+  uint16 GetInstallationIndex() const;
+
 #else
   H5vccUpdater() {}
 #endif
diff --git a/src/cobalt/h5vcc/h5vcc_updater.idl b/src/cobalt/h5vcc/h5vcc_updater.idl
index e92910f..4a81664 100644
--- a/src/cobalt/h5vcc/h5vcc_updater.idl
+++ b/src/cobalt/h5vcc/h5vcc_updater.idl
@@ -22,4 +22,6 @@
   DOMString getUpdateStatus();
 
   void resetInstallations();
+
+  unsigned short getInstallationIndex();
 };
diff --git a/src/cobalt/layout/box.cc b/src/cobalt/layout/box.cc
index 2a21d1b..9d68134 100644
--- a/src/cobalt/layout/box.cc
+++ b/src/cobalt/layout/box.cc
@@ -16,7 +16,7 @@
 
 #include <algorithm>
 #include <limits>
-#include <memory>
+#include <utility>
 
 #include "base/logging.h"
 #include "cobalt/base/polymorphic_downcast.h"
@@ -86,8 +86,8 @@
   cssom::TransformPropertyValue* transform_value =
       base::polymorphic_downcast<cssom::TransformPropertyValue*>(
           transform_property_value);
-  math::Matrix3F css_transform_matrix = transform_value->ToMatrix(
-      used_rect.size(), ui_nav_focus);
+  math::Matrix3F css_transform_matrix =
+      transform_value->ToMatrix(used_rect.size(), ui_nav_focus);
 
   // Apply the CSS transformations, taking into account the CSS
   // transform-origin property.
@@ -116,8 +116,8 @@
 #ifdef _DEBUG
   margin_box_offset_from_containing_block_.SetVector(LayoutUnit(),
                                                      LayoutUnit());
-  static_position_offset_from_parent_.SetInsets(
-      LayoutUnit(), LayoutUnit(), LayoutUnit(), LayoutUnit());
+  static_position_offset_from_parent_.SetInsets(LayoutUnit(), LayoutUnit(),
+                                                LayoutUnit(), LayoutUnit());
   static_position_offset_from_containing_block_to_parent_.SetInsets(
       LayoutUnit(), LayoutUnit(), LayoutUnit(), LayoutUnit());
   margin_insets_.SetInsets(LayoutUnit(), LayoutUnit(), LayoutUnit(),
@@ -132,13 +132,9 @@
 
 Box::~Box() { layout_stat_tracker_->OnBoxDestroyed(); }
 
-bool Box::IsPositioned() const {
-  return computed_style()->IsPositioned();
-}
+bool Box::IsPositioned() const { return computed_style()->IsPositioned(); }
 
-bool Box::IsTransformed() const {
-  return computed_style()->IsTransformed();
-}
+bool Box::IsTransformed() const { return computed_style()->IsTransformed(); }
 
 bool Box::IsAbsolutelyPositioned() const {
   return computed_style()->position() == cssom::KeywordValue::GetAbsolute() ||
@@ -402,14 +398,13 @@
           box->margin_box_offset_from_containing_block() +
           box->GetBorderBoxOffsetFromMarginBox();
       transform =
-          GetCSSTransform(
-              box->computed_style()->transform().get(),
-              box->computed_style()->transform_origin().get(),
-              math::RectF(transform_rect_offset.x().toFloat(),
-                          transform_rect_offset.y().toFloat(),
-                          box->GetBorderBoxWidth().toFloat(),
-                          box->GetBorderBoxHeight().toFloat()),
-              box->ComputeUiNavFocusForTransform()) *
+          GetCSSTransform(box->computed_style()->transform().get(),
+                          box->computed_style()->transform_origin().get(),
+                          math::RectF(transform_rect_offset.x().toFloat(),
+                                      transform_rect_offset.y().toFloat(),
+                                      box->GetBorderBoxWidth().toFloat(),
+                                      box->GetBorderBoxHeight().toFloat()),
+                          box->ComputeUiNavFocusForTransform()) *
           transform;
     }
 
@@ -422,9 +417,9 @@
     Vector2dLayoutUnit containing_block_offset =
         box->GetContainingBlockOffsetFromItsContentBox(container) +
         container->GetContentBoxOffsetFromMarginBox();
-    transform = math::TranslateMatrix(
-        containing_block_offset.x().toFloat(),
-        containing_block_offset.y().toFloat()) * transform;
+    transform = math::TranslateMatrix(containing_block_offset.x().toFloat(),
+                                      containing_block_offset.y().toFloat()) *
+                transform;
 
     box = container;
   }
@@ -597,10 +592,8 @@
   LayoutUnit left_inset =
       left() + margin_left() + border_left_width() + padding_left();
   return InsetsLayoutUnit(
-      left_inset,
-      top() + margin_top() + border_top_width() + padding_top(),
-      containing_block->width() - left_inset - width(),
-      LayoutUnit());
+      left_inset, top() + margin_top() + border_top_width() + padding_top(),
+      containing_block->width() - left_inset - width(), LayoutUnit());
 }
 
 LayoutUnit Box::GetContentBoxLeftEdgeOffsetFromContainingBlock() const {
@@ -767,11 +760,6 @@
   const base::Optional<RoundedCorners> padding_rounded_corners =
       ComputePaddingRoundedCorners(rounded_corners);
 
-  // Update the associated UI navigation item with the box's properties.
-  if (ui_nav_item_) {
-    UpdateUiNavigationItem();
-  }
-
   // Update intersection observers for any targets represented by this box.
   if (box_intersection_observer_module_) {
     box_intersection_observer_module_->UpdateIntersectionObservations();
@@ -828,8 +816,7 @@
   // check to see if there is a need to distinguish between content and
   // background.
   if (!overflow_hidden ||
-      (!IsOverflowAnimatedByUiNavigation() &&
-       !outline_is_visible &&
+      (!IsOverflowAnimatedByUiNavigation() && !outline_is_visible &&
        computed_style()->box_shadow() == cssom::KeywordValue::GetNone() &&
        border_insets_.zero())) {
     // If there's no reason to distinguish between content and background,
@@ -1189,7 +1176,8 @@
     return 0;
   } else {
     return base::polymorphic_downcast<cssom::IntegerValue*>(
-               computed_style()->z_index().get())->value();
+               computed_style()->z_index().get())
+        ->value();
   }
 }
 
@@ -1371,9 +1359,9 @@
     const scoped_refptr<ui_navigation::NavItem>& ui_nav_focus,
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
     MatrixTransformNode::Builder* transform_node_builder) {
-  transform_node_builder->transform = GetCSSTransform(
-      style->transform().get(), style->transform_origin().get(),
-      used_rect, ui_nav_focus);
+  transform_node_builder->transform =
+      GetCSSTransform(style->transform().get(), style->transform_origin().get(),
+                      used_rect, ui_nav_focus);
 }
 
 void SetupMatrixTransformNodeFromCSSTransform(
@@ -1399,7 +1387,8 @@
     const scoped_refptr<const cssom::CSSComputedStyleData>& style,
     FilterNode::Builder* filter_node_builder) {
   float opacity = base::polymorphic_downcast<const cssom::NumberValue*>(
-                      style->opacity().get())->value();
+                      style->opacity().get())
+                      ->value();
 
   if (opacity < 1.0f) {
     filter_node_builder->opacity_filter.emplace(std::max(0.0f, opacity));
@@ -1515,7 +1504,7 @@
       base::polymorphic_downcast<cssom::TransformPropertyValue*>(
           computed_style()->transform().get());
   if (!transform_property_value->HasTrait(
-      cssom::TransformFunction::kTraitUsesUiNavFocus)) {
+          cssom::TransformFunction::kTraitUsesUiNavFocus)) {
     return nullptr;
   }
 
@@ -1533,7 +1522,6 @@
     const base::Optional<RoundedCorners>& inner_rounded_corners,
     CompositionNode::Builder* border_node_builder,
     AnimateNode::Builder* animate_node_builder) {
-
   if (computed_style()->box_shadow() != cssom::KeywordValue::GetNone()) {
     const cssom::PropertyListValue* box_shadow_list =
         base::polymorphic_downcast<const cssom::PropertyListValue*>(
@@ -1917,8 +1905,8 @@
     animate_node_builder->Add(
         css_transform_node,
         base::Bind(&ApplyAnimation<MatrixTransformNode>,
-                   base::Bind(&SetupMatrixTransformNodeFromCSSStyle,
-                              used_rect, ui_nav_focus),
+                   base::Bind(&SetupMatrixTransformNodeFromCSSStyle, used_rect,
+                              ui_nav_focus),
                    baked_animation_set, base_style),
         transform_is_dynamic ? base::TimeDelta::Max()
                              : baked_animation_set.end_time());
@@ -1933,18 +1921,16 @@
         new MatrixTransformNode(border_node, math::Matrix3F::Identity());
     animate_node_builder->Add(
         css_transform_node,
-        base::Bind(&SetupMatrixTransformNodeFromCSSTransform,
-                   used_rect, ui_nav_focus,
-                   computed_style()->transform(),
+        base::Bind(&SetupMatrixTransformNodeFromCSSTransform, used_rect,
+                   ui_nav_focus, computed_style()->transform(),
                    computed_style()->transform_origin()));
     return css_transform_node;
   }
 
   if (IsTransformed()) {
-    math::Matrix3F matrix =
-        GetCSSTransform(computed_style()->transform().get(),
-                        computed_style()->transform_origin().get(),
-                        used_rect, ui_nav_focus);
+    math::Matrix3F matrix = GetCSSTransform(
+        computed_style()->transform().get(),
+        computed_style()->transform_origin().get(), used_rect, ui_nav_focus);
     if (matrix.IsIdentity()) {
       return border_node;
     } else {
@@ -1976,9 +1962,11 @@
   scoped_refptr<CompositionNode> composition_node;
   if (node_to_animate->GetTypeId() == base::GetTypeId<CompositionNode>() &&
       base::polymorphic_downcast<CompositionNode*>(node_to_animate.get())
-          ->data().offset().IsZero()) {
-    composition_node = base::polymorphic_downcast<CompositionNode*>(
-        node_to_animate.get());
+          ->data()
+          .offset()
+          .IsZero()) {
+    composition_node =
+        base::polymorphic_downcast<CompositionNode*>(node_to_animate.get());
   } else {
     composition_node = new CompositionNode(node_to_animate, math::Vector2dF());
   }
@@ -1991,6 +1979,10 @@
 }
 
 void Box::UpdateUiNavigationItem() {
+  if (!ui_nav_item_) {
+    return;
+  }
+
   // The scrollable overflow region is the union of the border box of all
   // contained boxes.
   //   https://www.w3.org/TR/css-overflow-3/#scrollable-overflow-region
@@ -2027,9 +2019,9 @@
   math::Matrix3F transform =
       GetMarginBoxTransformFromContainingBlock(containing_block) *
       math::TranslateMatrix(border_box_offset.x().toFloat() +
-                            0.5f * border_box_size.width().toFloat(),
+                                0.5f * border_box_size.width().toFloat(),
                             border_box_offset.y().toFloat() +
-                            0.5f * border_box_size.height().toFloat());
+                                0.5f * border_box_size.height().toFloat());
   ui_navigation::NativeMatrix2x3 ui_nav_matrix;
   ui_nav_matrix.m[0] = transform(0, 0);
   ui_nav_matrix.m[1] = transform(0, 1);
@@ -2044,8 +2036,8 @@
 
 // Based on https://www.w3.org/TR/CSS21/visudet.html#blockwidth.
 void Box::UpdateHorizontalMarginsAssumingBlockLevelInFlowBox(
-    BaseDirection containing_block_direction,
-    LayoutUnit containing_block_width, LayoutUnit border_box_width,
+    BaseDirection containing_block_direction, LayoutUnit containing_block_width,
+    LayoutUnit border_box_width,
     const base::Optional<LayoutUnit>& possibly_overconstrained_margin_left,
     const base::Optional<LayoutUnit>& possibly_overconstrained_margin_right) {
   base::Optional<LayoutUnit> maybe_margin_left =
@@ -2075,8 +2067,8 @@
   // If there is exactly one value specified as "auto", its used value follows
   // from the equality.
   if (maybe_margin_left &&
-        (!maybe_margin_right ||
-         containing_block_direction == kLeftToRightBaseDirection)) {
+      (!maybe_margin_right ||
+       containing_block_direction == kLeftToRightBaseDirection)) {
     set_margin_left(*maybe_margin_left);
     set_margin_right(containing_block_width - *maybe_margin_left -
                      border_box_width);
diff --git a/src/cobalt/layout/box.h b/src/cobalt/layout/box.h
index a7f3506..43768e3 100644
--- a/src/cobalt/layout/box.h
+++ b/src/cobalt/layout/box.h
@@ -16,6 +16,7 @@
 #define COBALT_LAYOUT_BOX_H_
 
 #include <iosfwd>
+#include <memory>
 #include <ostream>
 #include <string>
 #include <vector>
@@ -705,6 +706,9 @@
     blend_background_color_ = value;
   }
 
+  // Configure the box's UI navigation item with the box's position, size, etc.
+  void UpdateUiNavigationItem();
+
   void SetUiNavItem(const scoped_refptr<ui_navigation::NavItem>& item) {
     ui_nav_item_ = item;
   }
@@ -901,9 +905,6 @@
       const scoped_refptr<render_tree::Node>& node_to_animate,
       render_tree::animations::AnimateNode::Builder* animate_node_builder);
 
-  // Configure the box's UI navigation item with the box's position, size, etc.
-  void UpdateUiNavigationItem();
-
   // The css_computed_style_declaration_ member references the
   // cssom::CSSComputedStyleDeclaration object owned by the HTML Element from
   // which this box is derived.
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index 2bc8571..ad09c7d 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -16,6 +16,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/trace_event/trace_event.h"
@@ -133,6 +134,7 @@
            box_iterator != boxes_.end(); ++box_iterator) {
         Box* box = *box_iterator;
         do {
+          box->SetUiNavItem(html_element->GetUiNavItem());
           box->InvalidateParent();
           box = box->GetSplitSibling();
         } while (box != NULL);
@@ -522,9 +524,7 @@
   // boxes in the paragraph.
   // http://unicode.org/reports/tr9/#Terminating_Explicit_Directional_Isolates
   if (has_scoped_directional_isolate_) {
-    (*paragraph_)
-        ->AppendCodePoint(
-            Paragraph::kPopDirectionalIsolateCodePoint);
+    (*paragraph_)->AppendCodePoint(Paragraph::kPopDirectionalIsolateCodePoint);
   }
 
   if (paragraph_scoped_) {
@@ -1106,7 +1106,7 @@
   const web_animations::AnimationSet::InternalSet& animation_set =
       parent_animations->animations();
   const cssom::PropertyKeyVector& properties_set =
-    cssom::GetInheritedAnimatableProperties();
+      cssom::GetInheritedAnimatableProperties();
 
   // Go through all the parent animations and only add those pertaining to
   // inheritable properties.
diff --git a/src/cobalt/layout/layout.cc b/src/cobalt/layout/layout.cc
index 4dcd17d..b635518 100644
--- a/src/cobalt/layout/layout.cc
+++ b/src/cobalt/layout/layout.cc
@@ -14,6 +14,8 @@
 
 #include "cobalt/layout/layout.h"
 
+#include <utility>
+
 #include "base/trace_event/trace_event.h"
 #include "cobalt/base/stop_watch.h"
 #include "cobalt/cssom/computed_style.h"
@@ -25,6 +27,7 @@
 #include "cobalt/layout/benchmark_stat_names.h"
 #include "cobalt/layout/box_generator.h"
 #include "cobalt/layout/initial_containing_block.h"
+#include "cobalt/layout/layout_boxes.h"
 #include "cobalt/layout/used_style.h"
 #include "cobalt/render_tree/animations/animate_node.h"
 
@@ -82,8 +85,8 @@
 
   // Associate the UI navigation root with the initial containing block.
   if (document->window()) {
-    (*initial_containing_block)->SetUiNavItem(
-        document->window()->GetUiNavRoot());
+    (*initial_containing_block)
+        ->SetUiNavItem(document->window()->GetUiNavRoot());
   }
 
   // Generate boxes.
@@ -148,6 +151,25 @@
     (*initial_containing_block)->set_top(LayoutUnit());
     (*initial_containing_block)->UpdateSize(LayoutParams());
   }
+
+  // Update all UI navigation elements with the sizes and positions of their
+  // corresponding layout boxes.
+  if (document->ui_nav_needs_layout()) {
+    TRACE_EVENT0("cobalt::layout", "UpdateUiNavigationItems");
+    document->set_ui_nav_needs_layout(false);
+
+    const auto& ui_nav_elements = document->ui_navigation_elements();
+    (*initial_containing_block)->UpdateUiNavigationItem();
+    for (dom::HTMLElement* html_element : ui_nav_elements) {
+      LayoutBoxes* layout_boxes = base::polymorphic_downcast<LayoutBoxes*>(
+          html_element->layout_boxes());
+      if (layout_boxes) {
+        for (Box* box : layout_boxes->boxes()) {
+          box->UpdateUiNavigationItem();
+        }
+      }
+    }
+  }
 }
 
 scoped_refptr<render_tree::Node> GenerateRenderTreeFromBoxTree(
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index e394f7a..1da3d31 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -434,6 +434,7 @@
   }
 
   on_layout_callback_.Run();
+  document->UpdateUiNavigation();
 }
 
 LayoutManager::LayoutManager(
diff --git a/src/cobalt/layout_tests/testdata/cobalt/onload_event_fired_even_though_link_file_does_not_exist-expected.png b/src/cobalt/layout_tests/testdata/cobalt/onload_event_fired_even_though_link_file_does_not_exist-expected.png
index 2239574..cc63ae6 100644
--- a/src/cobalt/layout_tests/testdata/cobalt/onload_event_fired_even_though_link_file_does_not_exist-expected.png
+++ b/src/cobalt/layout_tests/testdata/cobalt/onload_event_fired_even_though_link_file_does_not_exist-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/cobalt/woff2-decoding-expected.png b/src/cobalt/layout_tests/testdata/cobalt/woff2-decoding-expected.png
index bb5f747..f3c1add 100644
--- a/src/cobalt/layout_tests/testdata/cobalt/woff2-decoding-expected.png
+++ b/src/cobalt/layout_tests/testdata/cobalt/woff2-decoding-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/10-3-9-inline-block-non-replaced-elements-with-auto-width-should-shrink-to-fit-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/10-3-9-inline-block-non-replaced-elements-with-auto-width-should-shrink-to-fit-expected.png
index 5101858..f59eb5f 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/10-3-9-inline-block-non-replaced-elements-with-auto-width-should-shrink-to-fit-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/10-3-9-inline-block-non-replaced-elements-with-auto-width-should-shrink-to-fit-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-limit-box-size-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-limit-box-size-expected.png
index c46d4ab..ac24a76 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-limit-box-size-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-limit-box-size-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-percentage-should-refer-containing-block-width-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-percentage-should-refer-containing-block-width-expected.png
index a51672b..1609158 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-percentage-should-refer-containing-block-width-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/10-4-min-width-and-max-width-percentage-should-refer-containing-block-width-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/10-5-percentage-of-auto-height-should-compute-to-auto-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/10-5-percentage-of-auto-height-should-compute-to-auto-expected.png
index 42daa05..c48c6b0 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/10-5-percentage-of-auto-height-should-compute-to-auto-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/10-5-percentage-of-auto-height-should-compute-to-auto-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/10-8-line-height-should-be-used-for-vertical-align-with-inline-non-replaced-boxes-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/10-8-line-height-should-be-used-for-vertical-align-with-inline-non-replaced-boxes-expected.png
index c902fd5..e2fd9b0 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/10-8-line-height-should-be-used-for-vertical-align-with-inline-non-replaced-boxes-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/10-8-line-height-should-be-used-for-vertical-align-with-inline-non-replaced-boxes-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-in-flow-siblings-separated-by-inline-box-should-not-form-collapsed-margin-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-in-flow-siblings-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
index 312a572..5bf111f 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-in-flow-siblings-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-in-flow-siblings-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-first-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-first-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
index 84a4dd1..0455860 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-first-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-first-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-last-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-last-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
index 38157f0..1790457 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-last-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/8-3-1-parent-and-last-in-flow-child-separated-by-inline-box-should-not-form-collapsed-margin-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-2-1-1-inline-level-boxes-should-be-wrapped-in-anonymous-block-boxes-in-block-formatting-context-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-2-1-1-inline-level-boxes-should-be-wrapped-in-anonymous-block-boxes-in-block-formatting-context-expected.png
index 0341d3c..406498f 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-2-1-1-inline-level-boxes-should-be-wrapped-in-anonymous-block-boxes-in-block-formatting-context-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-2-1-1-inline-level-boxes-should-be-wrapped-in-anonymous-block-boxes-in-block-formatting-context-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-collapsed-elements-should-reduce-available-width-of-line-box-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-collapsed-elements-should-reduce-available-width-of-line-box-expected.png
index 7bd94b0..95ab0af 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-collapsed-elements-should-reduce-available-width-of-line-box-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-collapsed-elements-should-reduce-available-width-of-line-box-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-inline-boxes-should-split-at-br-elements-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-inline-boxes-should-split-at-br-elements-expected.png
index cec0fa0..ccbd726 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-inline-boxes-should-split-at-br-elements-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-inline-boxes-should-split-at-br-elements-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-long-inline-boxes-should-be-split-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-long-inline-boxes-should-be-split-expected.png
index 9f936a3..0c5cc0a 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-long-inline-boxes-should-be-split-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-long-inline-boxes-should-be-split-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-multiple-inline-boxes-exceeding-width-of-line-box-should-be-split-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-multiple-inline-boxes-exceeding-width-of-line-box-should-be-split-expected.png
index 931503f..a892f27 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-multiple-inline-boxes-exceeding-width-of-line-box-should-be-split-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-multiple-inline-boxes-exceeding-width-of-line-box-should-be-split-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-nested-inline-boxes-should-split-at-br-elements-expected.png b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-nested-inline-boxes-should-split-at-br-elements-expected.png
index cec0fa0..ccbd726 100644
--- a/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-nested-inline-boxes-should-split-at-br-elements-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-2-1/9-4-2-nested-inline-boxes-should-split-at-br-elements-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png
index 03e1d7a..b1cf019 100644
--- a/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-text-3/3-bidirectional-content-should-overflow-the-line-with-white-space-nowrap-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/4-1-1-space-preceding-br-element-should-not-be-collapsed-expected.png b/src/cobalt/layout_tests/testdata/css-text-3/4-1-1-space-preceding-br-element-should-not-be-collapsed-expected.png
index 358cba3..37aa685 100644
--- a/src/cobalt/layout_tests/testdata/css-text-3/4-1-1-space-preceding-br-element-should-not-be-collapsed-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-text-3/4-1-1-space-preceding-br-element-should-not-be-collapsed-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css-text-3/4-1-3-spaces-at-beginning-and-end-of-line-should-be-collapsed-expected.png b/src/cobalt/layout_tests/testdata/css-text-3/4-1-3-spaces-at-beginning-and-end-of-line-should-be-collapsed-expected.png
index 172b827..62e745b 100644
--- a/src/cobalt/layout_tests/testdata/css-text-3/4-1-3-spaces-at-beginning-and-end-of-line-should-be-collapsed-expected.png
+++ b/src/cobalt/layout_tests/testdata/css-text-3/4-1-3-spaces-at-beginning-and-end-of-line-should-be-collapsed-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family-expected.png
index ee17764..3458d6d 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-2-font-face-font-family-hides-system-font-family-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-font-postscript-name-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-font-postscript-name-expected.png
index b265af2..e76570a 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-font-postscript-name-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-font-postscript-name-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-full-font-name-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-full-font-name-expected.png
index b265af2..e76570a 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-full-font-name-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-src-local-can-match-full-font-name-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face-expected.png
index 766bcab..c3e9320 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-first-available-local-font-face-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable-expected.png
index 6f94416..0fdd74c 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-3-use-next-font-family-if-font-face-sources-unavailable-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png
index 018a47c..d88ff47 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/4-4-use-correct-style-in-font-face-set-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-specified-font-family-if-available-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-specified-font-family-if-available-expected.png
index e121e4b..4dc97e3 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-specified-font-family-if-available-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-specified-font-family-if-available-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png
index bf339a6..5d53a71 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-system-fallback-if-no-matching-family-is-found-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png
index e509aaa..e5d66c0 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/color-emojis-should-render-properly-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-not-occur-on-bold-font-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-not-occur-on-bold-font-expected.png
index 6887b09..313808b 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-not-occur-on-bold-font-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-not-occur-on-bold-font-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-occur-on-non-bold-font-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-occur-on-non-bold-font-expected.png
index e38f5c6..00d6958 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-occur-on-non-bold-font-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/synthetic-bolding-should-occur-on-non-bold-font-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/text-bounds-should-be-calculated-properly-when-containing-zero-height-font-runs-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/text-bounds-should-be-calculated-properly-when-containing-zero-height-font-runs-expected.png
index 42db3df..078162c 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/text-bounds-should-be-calculated-properly-when-containing-zero-height-font-runs-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/text-bounds-should-be-calculated-properly-when-containing-zero-height-font-runs-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-expected.png b/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-expected.png
index 9317db5..ca4989a 100644
--- a/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-expected.png
+++ b/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-when-set-via-attribute-expected.png b/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-when-set-via-attribute-expected.png
index 9317db5..ca4989a 100644
--- a/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-when-set-via-attribute-expected.png
+++ b/src/cobalt/layout_tests/testdata/webappapis/6-1-5-2-onload-event-fires-on-window-when-set-via-attribute-expected.png
Binary files differ
diff --git a/src/cobalt/loader/loader_factory.cc b/src/cobalt/loader/loader_factory.cc
index a0a2974..6c542e0 100644
--- a/src/cobalt/loader/loader_factory.cc
+++ b/src/cobalt/loader/loader_factory.cc
@@ -236,6 +236,9 @@
        iter != active_loaders_.end(); ++iter) {
     (*iter)->Resume(resource_provider);
   }
+
+  // Wait for all loader thread messages to be flushed before returning.
+  load_thread_.message_loop()->task_runner()->WaitForFence();
 }
 
 void LoaderFactory::OnLoaderCreated(Loader* loader) {
diff --git a/src/cobalt/media/base/sbplayer_pipeline.cc b/src/cobalt/media/base/sbplayer_pipeline.cc
index 143b238..e6a9803 100644
--- a/src/cobalt/media/base/sbplayer_pipeline.cc
+++ b/src/cobalt/media/base/sbplayer_pipeline.cc
@@ -345,10 +345,9 @@
   base::WaitableEvent waitable_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
-  task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&SbPlayerPipeline::ResumeTask,
-                                    base::Unretained(this),
-                                    window, &waitable_event));
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&SbPlayerPipeline::ResumeTask,
+                            base::Unretained(this), window, &waitable_event));
   waitable_event.Wait();
 }
 
@@ -423,8 +422,7 @@
                                  on_encrypted_media_init_data_encountered_cb,
                              const std::string& source_url,
                              const PipelineStatusCB& ended_cb,
-                             const ErrorCB& error_cb,
-                             const SeekCB& seek_cb,
+                             const ErrorCB& error_cb, const SeekCB& seek_cb,
                              const BufferingStateCB& buffering_state_cb,
                              const base::Closure& duration_change_cb,
                              const base::Closure& output_mode_change_cb,
@@ -622,6 +620,14 @@
 #endif  // SB_HAS(PLAYER_WITH_URL)
   player_->GetInfo(&statistics_.video_frames_decoded,
                    &statistics_.video_frames_dropped, &media_time);
+
+  // Guarantee that we report monotonically increasing media time
+  if (media_time.ToSbTime() < last_media_time_) {
+    DLOG(WARNING) << "The new media timestamp player reported ("
+                  << media_time.ToSbTime() << ") is less than the last one ("
+                  << last_media_time_ << ").";
+    media_time = base::TimeDelta::FromMicroseconds(last_media_time_);
+  }
   StoreMediaTime(media_time);
   return media_time;
 }
diff --git a/src/cobalt/media/decoder_buffer_allocator.cc b/src/cobalt/media/decoder_buffer_allocator.cc
index 13de0b0..8a70a3b 100644
--- a/src/cobalt/media/decoder_buffer_allocator.cc
+++ b/src/cobalt/media/decoder_buffer_allocator.cc
@@ -33,35 +33,22 @@
 const bool kEnableAllocationLog = false;
 
 const std::size_t kAllocationRecordGranularity = 512 * 1024;
+// Used to determine if the memory allocated is large. The underlying logic can
+// be different.
 const std::size_t kSmallAllocationThreshold = 512;
 
 bool IsLargeAllocation(std::size_t size) {
   return size > kSmallAllocationThreshold;
 }
 
-bool IsMemoryPoolEnabled() {
-  return SbMediaIsBufferUsingMemoryPool();
-}
-
-bool IsMemoryPoolAllocatedOnDemand() {
-  return SbMediaIsBufferPoolAllocateOnDemand();
-}
-
-int GetInitialBufferCapacity() {
-  return SbMediaGetInitialBufferCapacity();
-}
-
-int GetBufferAllocationUnit() {
-  return SbMediaGetBufferAllocationUnit();
-}
-
 }  // namespace
 
 DecoderBufferAllocator::DecoderBufferAllocator()
-    : using_memory_pool_(IsMemoryPoolEnabled()),
-      is_memory_pool_allocated_on_demand_(IsMemoryPoolAllocatedOnDemand()),
-      initial_capacity_(GetInitialBufferCapacity()),
-      allocation_unit_(GetBufferAllocationUnit()) {
+    : using_memory_pool_(SbMediaIsBufferUsingMemoryPool()),
+      is_memory_pool_allocated_on_demand_(
+          SbMediaIsBufferPoolAllocateOnDemand()),
+      initial_capacity_(SbMediaGetInitialBufferCapacity()),
+      allocation_unit_(SbMediaGetBufferAllocationUnit()) {
   if (!using_memory_pool_) {
     DLOG(INFO) << "Allocated media buffer memory using SbMemory* functions.";
     return;
@@ -105,6 +92,7 @@
   TRACK_MEMORY_SCOPE("Media");
 
   if (!using_memory_pool_) {
+    sbmemory_bytes_used_.fetch_add(size);
     return Allocations(SbMemoryAllocateAligned(alignment, size), size);
   }
 
@@ -150,6 +138,7 @@
 
   if (!using_memory_pool_) {
     for (int i = 0; i < allocations.number_of_buffers(); ++i) {
+      sbmemory_bytes_used_.fetch_sub(allocations.buffer_sizes()[i]);
       SbMemoryDeallocateAligned(allocations.buffers()[i]);
     }
     return;
@@ -220,7 +209,7 @@
     return free_block_iter;
   }
 
-  *allocate_from_front = IsLargeAllocation(size);
+  *allocate_from_front = size > kSmallAllocationThreshold;
   *allocate_from_front = context == 1;
   if (*allocate_from_front) {
     for (FreeBlockSet::iterator it = begin; it != end; ++it) {
@@ -242,6 +231,37 @@
   return end;
 }
 
+std::size_t DecoderBufferAllocator::GetAllocatedMemory() const {
+  if (!using_memory_pool_) {
+    return sbmemory_bytes_used_.load();
+  }
+  starboard::ScopedLock scoped_lock(mutex_);
+  return reuse_allocator_ ? reuse_allocator_->GetAllocated() : 0;
+}
+
+std::size_t DecoderBufferAllocator::GetCurrentMemoryCapacity() const {
+  if (!using_memory_pool_) {
+    return sbmemory_bytes_used_.load();
+  }
+  starboard::ScopedLock scoped_lock(mutex_);
+  return reuse_allocator_ ? reuse_allocator_->GetCapacity() : 0;
+}
+
+std::size_t DecoderBufferAllocator::GetMaximumMemoryCapacity() const {
+  starboard::ScopedLock scoped_lock(mutex_);
+  if (video_codec_ == kSbMediaVideoCodecNone) {
+    return 0;
+  }
+  if (!using_memory_pool_) {
+    return SbMediaGetMaxBufferCapacity(video_codec_, resolution_width_,
+                                       resolution_height_, bits_per_pixel_);
+  }
+  return reuse_allocator_
+             ? reuse_allocator_->max_capacity()
+             : SbMediaGetMaxBufferCapacity(video_codec_, resolution_width_,
+                                           resolution_height_, bits_per_pixel_);
+}
+
 bool DecoderBufferAllocator::UpdateAllocationRecord() const {
 #if !defined(COBALT_BUILD_TYPE_GOLD)
   // This code is not quite multi-thread safe but is safe enough for tracking
@@ -261,9 +281,9 @@
     new_max_reached = true;
   }
   if (new_max_reached) {
-    SB_LOG(ERROR) << "New Media Buffer Allocation Record: "
-                  << "Max Allocated: " << max_allocated
-                  << "  Max Capacity: " << max_capacity;
+    SB_LOG(INFO) << "New Media Buffer Allocation Record: "
+                 << "Max Allocated: " << max_allocated
+                 << "  Max Capacity: " << max_capacity;
     // TODO: Enable the following line once PrintAllocations() accepts max line
     // as a parameter.
     // reuse_allocator_->PrintAllocations();
@@ -271,10 +291,10 @@
 #endif  // !defined(COBALT_BUILD_TYPE_GOLD)
 
   if (reuse_allocator_->CapacityExceeded()) {
-    SB_LOG(ERROR) << "Cobalt media buffer capacity "
-                  << reuse_allocator_->GetCapacity()
-                  << " exceeded max capacity "
-                  << reuse_allocator_->max_capacity();
+    SB_LOG(WARNING) << "Cobalt media buffer capacity "
+                    << reuse_allocator_->GetCapacity()
+                    << " exceeded max capacity "
+                    << reuse_allocator_->max_capacity();
     return false;
   }
   return true;
diff --git a/src/cobalt/media/decoder_buffer_allocator.h b/src/cobalt/media/decoder_buffer_allocator.h
index 485efb7..0504a6e 100644
--- a/src/cobalt/media/decoder_buffer_allocator.h
+++ b/src/cobalt/media/decoder_buffer_allocator.h
@@ -21,15 +21,18 @@
 #include "cobalt/media/base/decoder_buffer.h"
 #include "cobalt/media/base/video_decoder_config.h"
 #include "cobalt/media/base/video_resolution.h"
+#include "cobalt/media/decoder_buffer_memory_info.h"
 #include "nb/bidirectional_fit_reuse_allocator.h"
 #include "nb/starboard_memory_allocator.h"
+#include "starboard/atomic.h"
 #include "starboard/common/mutex.h"
 #include "starboard/media.h"
 
 namespace cobalt {
 namespace media {
 
-class DecoderBufferAllocator : public DecoderBuffer::Allocator {
+class DecoderBufferAllocator : public DecoderBuffer::Allocator,
+                               public DecoderBufferMemoryInfo {
  public:
   DecoderBufferAllocator();
   ~DecoderBufferAllocator() override;
@@ -38,6 +41,9 @@
                        intptr_t context) override;
   void Free(Allocations allocations) override;
   void UpdateVideoConfig(const VideoDecoderConfig& video_config) override;
+  size_t GetAllocatedMemory() const override;
+  size_t GetCurrentMemoryCapacity() const override;
+  size_t GetMaximumMemoryCapacity() const override;
 
  private:
   class ReuseAllocator : public nb::BidirectionalFitReuseAllocator {
@@ -68,6 +74,9 @@
   int resolution_width_ = -1;
   int resolution_height_ = -1;
   int bits_per_pixel_ = -1;
+
+  // Monitor memory allocation and use when |using_memory_pool_| is false
+  starboard::atomic_int32_t sbmemory_bytes_used_;
 };
 
 }  // namespace media
diff --git a/src/cobalt/media/decoder_buffer_memory_info.h b/src/cobalt/media/decoder_buffer_memory_info.h
new file mode 100644
index 0000000..af79574
--- /dev/null
+++ b/src/cobalt/media/decoder_buffer_memory_info.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef COBALT_MEDIA_DECODER_BUFFER_MEMORY_INFO_H_
+#define COBALT_MEDIA_DECODER_BUFFER_MEMORY_INFO_H_
+
+#include "starboard/media.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace media {
+
+class DecoderBufferMemoryInfo {
+ public:
+  virtual ~DecoderBufferMemoryInfo() {}
+
+  virtual size_t GetAllocatedMemory() const = 0;
+  virtual size_t GetCurrentMemoryCapacity() const = 0;
+  virtual size_t GetMaximumMemoryCapacity() const = 0;
+};
+
+class StubDecoderBufferMemoryInfo : public DecoderBufferMemoryInfo {
+  public:
+   ~StubDecoderBufferMemoryInfo() override {}
+
+   size_t GetAllocatedMemory() const override { return 0; }
+   size_t GetCurrentMemoryCapacity() const override { return 0; }
+   size_t GetMaximumMemoryCapacity() const override { return 0; }
+};
+
+}  // namespace media
+}  // namespace cobalt
+
+#endif  // COBALT_MEDIA_DECODER_BUFFER_MEMORY_INFO_H_
diff --git a/src/cobalt/media/media.gyp b/src/cobalt/media/media.gyp
index 4b31fc0..42567fa 100644
--- a/src/cobalt/media/media.gyp
+++ b/src/cobalt/media/media.gyp
@@ -24,6 +24,7 @@
       'sources': [
         'decoder_buffer_allocator.cc',
         'decoder_buffer_allocator.h',
+        'decoder_buffer_memory_info.h',
         'fetcher_buffered_data_source.cc',
         'fetcher_buffered_data_source.h',
         'media_module.cc',
diff --git a/src/cobalt/media/media_module.h b/src/cobalt/media/media_module.h
index 31d3064..c2c3df8 100644
--- a/src/cobalt/media/media_module.h
+++ b/src/cobalt/media/media_module.h
@@ -63,8 +63,10 @@
   // Returns true when the setting is set successfully or if the setting has
   // already been set to the expected value.  Returns false when the setting is
   // invalid or not set to the expected value.
-  bool SetConfiguration(const std::string& name, int32 value) {
-    return false;
+  bool SetConfiguration(const std::string& name, int32 value) { return false; }
+
+  const DecoderBufferAllocator* GetDecoderBufferAllocator() const {
+    return &decoder_buffer_allocator_;
   }
 
   // WebMediaPlayerFactory methods
diff --git a/src/cobalt/media_session/media_session_client.cc b/src/cobalt/media_session/media_session_client.cc
index dc767a3..d2454d4 100644
--- a/src/cobalt/media_session/media_session_client.cc
+++ b/src/cobalt/media_session/media_session_client.cc
@@ -13,13 +13,14 @@
 // limitations under the License.
 
 #include "cobalt/media_session/media_session_client.h"
-#include "cobalt/script/sequence.h"
 
 #include <algorithm>
 #include <cmath>
 #include <memory>
+#include <string>
 
 #include "base/logging.h"
+#include "cobalt/script/sequence.h"
 #include "starboard/time.h"
 
 using MediaImageSequence = ::cobalt::script::Sequence<MediaImage>;
@@ -34,14 +35,14 @@
 
 // Guess the media position state for the media session.
 void GuessMediaPositionState(MediaSessionState* session_state,
-    const media::WebMediaPlayer** guess_player,
-    const media::WebMediaPlayer* current_player) {
+                             const media::WebMediaPlayer** guess_player,
+                             const media::WebMediaPlayer* current_player) {
   // Assume the player with the biggest video size is the one controlled by the
   // media session. This isn't perfect, so it's best that the web app set the
   // media position state explicitly.
   if (*guess_player == nullptr ||
       (*guess_player)->GetNaturalSize().GetArea() <
-      current_player->GetNaturalSize().GetArea()) {
+          current_player->GetNaturalSize().GetArea()) {
     *guess_player = current_player;
 
     MediaPositionState position_state;
@@ -56,18 +57,15 @@
     position_state.set_playback_rate((*guess_player)->GetPlaybackRate());
     position_state.set_position((*guess_player)->GetCurrentTime());
 
-    *session_state = MediaSessionState(
-        session_state->metadata(),
-        SbTimeGetMonotonicNow(),
-        position_state,
-        session_state->actual_playback_state(),
-        session_state->available_actions());
+    *session_state = MediaSessionState(session_state->metadata(),
+                                       SbTimeGetMonotonicNow(), position_state,
+                                       session_state->actual_playback_state(),
+                                       session_state->available_actions());
   }
 }
 }  // namespace
 
-MediaSessionClient::MediaSessionClient(
-    MediaSession* media_session)
+MediaSessionClient::MediaSessionClient(MediaSession* media_session)
     : media_session_(media_session),
       platform_playback_state_(kMediaSessionPlaybackStateNone) {
 #if SB_API_VERSION < 11
@@ -252,18 +250,15 @@
   }
 
   session_state_ = MediaSessionState(
-      metadata,
-      media_session_->last_position_updated_time_,
-      media_session_->media_position_state_,
-      ComputeActualPlaybackState(),
+      metadata, media_session_->last_position_updated_time_,
+      media_session_->media_position_state_, ComputeActualPlaybackState(),
       ComputeAvailableActions());
 
   // Compute the media position state if it's not set in the media session.
   if (!media_session_->media_position_state_ && media_player_factory_) {
     const media::WebMediaPlayer* player = nullptr;
-    media_player_factory_->EnumerateWebMediaPlayers(
-        base::BindRepeating(&GuessMediaPositionState,
-                            &session_state_, &player));
+    media_player_factory_->EnumerateWebMediaPlayers(base::BindRepeating(
+        &GuessMediaPositionState, &session_state_, &player));
 
     // The media duration may be reported as 0 when seeking. Re-query the
     // media session state after a delay.
@@ -294,6 +289,7 @@
     ext_state.actual_playback_rate = session_state.actual_playback_rate();
     ext_state.current_playback_position =
         session_state.current_playback_position();
+    ext_state.has_position_state = session_state.has_position_state();
     ext_state.actual_playback_state =
         ConvertPlaybackState(session_state.actual_playback_state());
     ConvertMediaSessionActions(session_state.available_actions(),
diff --git a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
index 1f04c7a..56f3a81 100644
--- a/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/hardware_rasterizer.cc
@@ -308,13 +308,6 @@
                                            0, info);
 
   uint32_t flags = 0;
-  if (!force_deterministic_rendering) {
-    // Distance field fonts are known to result in non-deterministic graphical,
-    // since the output depends on the size of the glyph that enters the atlas
-    // first (which would get re-used for similarly but unequal sized
-    // subsequent glyphs).
-    flags = SkSurfaceProps::kUseDistanceFieldFonts_Flag;
-  }
   SkSurfaceProps skia_surface_props(flags,
                                     SkSurfaceProps::kLegacyFontHost_InitType);
   return SkSurface::MakeFromBackendRenderTarget(
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index 8064da1..f169ec8 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -153,13 +153,6 @@
 
 SkSurfaceProps GetRenderTargetSurfaceProps(bool force_deterministic_rendering) {
   uint32_t flags = 0;
-  if (!force_deterministic_rendering) {
-    // Distance field fonts are known to result in non-deterministic graphical
-    // output since the output depends on the size of the glyph that enters the
-    // atlas first (which would get re-used for similarly but unequal sized
-    // subsequent glyphs).
-    flags = SkSurfaceProps::kUseDistanceFieldFonts_Flag;
-  }
   return SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
 }
 
diff --git a/src/cobalt/site/docs/starboard/porting.md b/src/cobalt/site/docs/starboard/porting.md
index 4c19ff2..4447f30 100644
--- a/src/cobalt/site/docs/starboard/porting.md
+++ b/src/cobalt/site/docs/starboard/porting.md
@@ -110,7 +110,7 @@
 *   `thread_types_public.h`
 
 We recommend that you copy the files from the Stub reference implementation,
-located at `src/third_party/stub/` to your `binary-variant` directories.
+located at `src/starboard/stub/` to your `binary-variant` directories.
 In this approach, you will essentially start with a clean slate of stub
 interfaces that need to be modified to work with your platform.
 
diff --git a/src/cobalt/speech/sandbox/speech_sandbox.cc b/src/cobalt/speech/sandbox/speech_sandbox.cc
index 52c1303..b930aa9 100644
--- a/src/cobalt/speech/sandbox/speech_sandbox.cc
+++ b/src/cobalt/speech/sandbox/speech_sandbox.cc
@@ -77,8 +77,8 @@
     const dom::DOMSettings::Options& dom_settings_options) {
   std::unique_ptr<script::EnvironmentSettings> environment_settings(
       new dom::DOMSettings(kDOMMaxElementDepth, NULL, network_module_.get(),
-                           NULL, NULL, NULL, NULL, NULL, null_debugger_hooks_,
-                           NULL, dom_settings_options));
+                           NULL, NULL, NULL, NULL, NULL, NULL,
+                           null_debugger_hooks_, NULL, dom_settings_options));
   DCHECK(environment_settings);
 
   speech_recognition_ = new SpeechRecognition(environment_settings.get());
diff --git a/src/cobalt/tools/automated_testing/cobalt_runner.py b/src/cobalt/tools/automated_testing/cobalt_runner.py
index 003edf5..da482b4 100644
--- a/src/cobalt/tools/automated_testing/cobalt_runner.py
+++ b/src/cobalt/tools/automated_testing/cobalt_runner.py
@@ -27,8 +27,7 @@
 # Pattern to match Cobalt log line for when a WindowDriver has been created.
 RE_WINDOWDRIVER_CREATED = re.compile(
     (r'^\[[\d:]+/[\d.]+:INFO:browser_module\.cc\(\d+\)\] Created WindowDriver: '
-     r'ID=\S+')
-)
+     r'ID=\S+'))
 # Pattern to match Cobalt log line for when a WebModule is has been loaded.
 RE_WEBMODULE_LOADED = re.compile(
     r'^\[[\d:]+/[\d.]+:INFO:browser_module\.cc\(\d+\)\] Loaded WebModule')
@@ -346,7 +345,11 @@
 
   def ExecuteJavaScript(self, js_code):
     retry_count = 0
-    while retry_count < EXECUTE_JAVASCRIPT_RETRY_LIMIT:
+    while True:
+      if retry_count >= EXECUTE_JAVASCRIPT_RETRY_LIMIT:
+        raise TimeoutException(
+            'Selenium element or window not found in {} tries'.format(
+                EXECUTE_JAVASCRIPT_RETRY_LIMIT))
       retry_count += 1
       try:
         result = self.webdriver.execute_script(js_code)
@@ -354,9 +357,6 @@
               selenium_exceptions.NoSuchWindowException):
         time.sleep(0.2)
         continue
-      except Exception:
-        sys.excepthook(*sys.exc_info())
-        logging.exception("Failed with unexpected exception")
       break
     return result
 
@@ -465,14 +465,16 @@
     Returns:
       Array of selected elements
     """
-    elements = None
-
     # The retry part below is a temporary workaround to handle command
     # failures during a short window of stale Cobalt WindowDriver
     # after navigation. We only introduced it because of limited time budget
     # at the moment, please don't introduce any code that relies on it.
     retry_count = 0
-    while retry_count < FIND_ELEMENT_RETRY_LIMIT:
+    while True:
+      if retry_count >= FIND_ELEMENT_RETRY_LIMIT:
+        raise TimeoutException(
+            'Selenium element or window not found in {} tries'.format(
+                FIND_ELEMENT_RETRY_LIMIT))
       retry_count += 1
       try:
         elements = self.webdriver.find_elements_by_css_selector(css_selector)
@@ -480,11 +482,8 @@
               selenium_exceptions.NoSuchWindowException):
         time.sleep(0.2)
         continue
-      except Exception:
-        sys.excepthook(*sys.exc_info())
-        logging.exception("Failed with unexpected exception")
       break
-    if expected_num is not None and len(elements) != expected_num:
+    if expected_num and len(elements) != expected_num:
       raise CobaltRunner.AssertException(
           'Expected number of element {} is: {}, got {}'.format(
               css_selector, expected_num, len(elements)))
diff --git a/src/cobalt/ui_navigation/nav_item.cc b/src/cobalt/ui_navigation/nav_item.cc
index 7ddc7fa..a9b02b4 100644
--- a/src/cobalt/ui_navigation/nav_item.cc
+++ b/src/cobalt/ui_navigation/nav_item.cc
@@ -27,7 +27,14 @@
 // These data structures support queuing of UI navigation changes so they can
 // be executed as a batch to atomically update the UI.
 SbAtomic32 g_pending_updates_lock(starboard::kSpinLockStateReleased);
-std::vector<base::Closure>* g_pending_updates = nullptr;
+
+struct PendingUpdate {
+  PendingUpdate(NativeItem nav_item, const base::Closure& closure)
+      : nav_item(nav_item), closure(closure) {}
+  NativeItem nav_item;
+  base::Closure closure;
+};
+std::vector<PendingUpdate>* g_pending_updates = nullptr;
 
 // Pending focus change should always be done after all updates. This ensures
 // the focus target is up-to-date.
@@ -45,7 +52,7 @@
 // This processes all pending updates assuming the update spinlock is locked.
 void ProcessPendingChangesLocked(void* /* context */) {
   for (size_t i = 0; i < g_pending_updates->size(); ++i) {
-    (*g_pending_updates)[i].Run();
+    (*g_pending_updates)[i].closure.Run();
   }
   g_pending_updates->clear();
   if (g_pending_focus != kNativeItemInvalid) {
@@ -58,16 +65,31 @@
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
   ProcessPendingChangesLocked(context);
 }
+
+// Remove any pending changes associated with the specified item.
+void RemovePendingChangesLocked(NativeItem nav_item) {
+  DCHECK(nav_item != kNativeItemInvalid);
+
+  for (size_t i = 0; i < g_pending_updates->size();) {
+    if ((*g_pending_updates)[i].nav_item == nav_item) {
+      g_pending_updates->erase(g_pending_updates->begin() + i);
+      continue;
+    }
+    ++i;
+  }
+
+  if (g_pending_focus == nav_item) {
+    g_pending_focus = kNativeItemInvalid;
+  }
+}
+
 }  // namespace
 
 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,
+NavItem::NavItem(NativeItemType type, const base::Closure& onblur_callback,
                  const base::Closure& onfocus_callback,
                  const base::Closure& onscroll_callback)
     : onblur_callback_(onblur_callback),
@@ -75,22 +97,19 @@
       onscroll_callback_(onscroll_callback),
       nav_item_type_(type),
       nav_item_(GetInterface().create_item(type, &s_callbacks_, this)),
-      enabled_(false) {
+      state_(kStateNew) {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
   if (++g_nav_item_count == 1) {
-    g_pending_updates = new std::vector<base::Closure>();
+    g_pending_updates = new std::vector<PendingUpdate>();
     g_pending_focus = kNativeItemInvalid;
   }
 }
 
 NavItem::~NavItem() {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
-  GetInterface().set_item_enabled(nav_item_, false);
-  if (g_pending_focus == nav_item_) {
-    g_pending_focus = kNativeItemInvalid;
-  }
+  DCHECK(state_ == kStatePendingDelete);
   g_pending_updates->emplace_back(
-      base::Bind(GetInterface().destroy_item, nav_item_));
+      nav_item_, base::Bind(GetInterface().destroy_item, nav_item_));
   if (--g_nav_item_count == 0) {
     ProcessPendingChangesLocked(nullptr);
     delete g_pending_updates;
@@ -104,7 +123,7 @@
 
 void NavItem::Focus() {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
-  if (enabled_) {
+  if (state_ == kStateEnabled) {
     if (g_pending_updates->empty()) {
       // Immediately update focus if nothing else is queued for update.
       g_pending_focus = kNativeItemInvalid;
@@ -120,21 +139,27 @@
   g_pending_focus = kNativeItemInvalid;
 #if SB_API_VERSION >= SB_UI_NAVIGATION2_VERSION
   g_pending_updates->emplace_back(
+      kNativeItemInvalid,
       base::Bind(GetInterface().set_focus, kNativeItemInvalid));
 #endif
 }
 
 void NavItem::SetEnabled(bool enabled) {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
-  enabled_ = enabled;
   if (enabled) {
-    g_pending_updates->emplace_back(
-        base::Bind(GetInterface().set_item_enabled, nav_item_, enabled));
+    if (state_ == kStateNew) {
+      state_ = kStateEnabled;
+      g_pending_updates->emplace_back(
+          nav_item_,
+          base::Bind(GetInterface().set_item_enabled, nav_item_, enabled));
+    }
   } else {
-    // Disable immediately to avoid errant callbacks on this item.
-    GetInterface().set_item_enabled(nav_item_, enabled);
-    if (g_pending_focus == nav_item_) {
-      g_pending_focus = kNativeItemInvalid;
+    if (state_ != kStatePendingDelete) {
+      state_ = kStatePendingDelete;
+      // Remove any pending changes associated with this item.
+      RemovePendingChangesLocked(nav_item_);
+      // Disable immediately to avoid errant callbacks on this item.
+      GetInterface().set_item_enabled(nav_item_, enabled);
     }
   }
 }
@@ -147,13 +172,14 @@
 void NavItem::SetSize(float width, float height) {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
   g_pending_updates->emplace_back(
+      nav_item_,
       base::Bind(GetInterface().set_item_size, nav_item_, width, height));
 }
 
 void NavItem::SetTransform(const NativeMatrix2x3* transform) {
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
   g_pending_updates->emplace_back(
-      base::Bind(&SetTransformHelper, nav_item_, *transform));
+      nav_item_, base::Bind(&SetTransformHelper, nav_item_, *transform));
 }
 
 bool NavItem::GetFocusTransform(NativeMatrix4* out_transform) {
@@ -176,6 +202,7 @@
   container_ = container;
   starboard::ScopedSpinLock lock(&g_pending_updates_lock);
   g_pending_updates->emplace_back(
+      nav_item_,
       base::Bind(GetInterface().set_item_container_item, nav_item_,
                  container ? container->nav_item_ : kNativeItemInvalid));
 }
diff --git a/src/cobalt/ui_navigation/nav_item.h b/src/cobalt/ui_navigation/nav_item.h
index a0579f7..8b3a955 100644
--- a/src/cobalt/ui_navigation/nav_item.h
+++ b/src/cobalt/ui_navigation/nav_item.h
@@ -25,14 +25,11 @@
 // This wraps a NativeItem to make it ref-counted.
 class NavItem : public base::RefCountedThreadSafe<NavItem> {
  public:
-  NavItem(NativeItemType type,
-          const base::Closure& onblur_callback,
+  NavItem(NativeItemType type, const base::Closure& onblur_callback,
           const base::Closure& onfocus_callback,
           const base::Closure& onscroll_callback);
 
-  NativeItemType GetType() const {
-    return nav_item_type_;
-  }
+  NativeItemType GetType() const { return nav_item_type_; }
 
   bool IsContainer() const {
     return nav_item_type_ == kNativeItemTypeContainer;
@@ -73,7 +70,13 @@
 
   NativeItemType nav_item_type_;
   NativeItem nav_item_;
-  bool enabled_;
+
+  enum State {
+    kStateNew,
+    kStateEnabled,
+    kStatePendingDelete,
+  };
+  State state_;
 
   static NativeCallbacks s_callbacks_;
 };
diff --git a/src/cobalt/updater/configurator.cc b/src/cobalt/updater/configurator.cc
index f48c66a..f7d5785 100644
--- a/src/cobalt/updater/configurator.cc
+++ b/src/cobalt/updater/configurator.cc
@@ -5,6 +5,7 @@
 #include "cobalt/updater/configurator.h"
 
 #include <set>
+#include <utility>
 
 #include "base/version.h"
 #include "cobalt/script/javascript_engine.h"
@@ -53,11 +54,11 @@
 };
 
 #if defined(COBALT_BUILD_TYPE_DEBUG) || defined(COBALT_BUILD_TYPE_DEVEL)
-const std::string kDefaultUpdaterChannel = "dev";
+const const char kDefaultUpdaterChannel[] = "dev";
 #elif defined(COBALT_BUILD_TYPE_QA)
-const std::string kDefaultUpdaterChannel = "qa";
+const const char kDefaultUpdaterChannel[] = "qa";
 #elif defined(COBALT_BUILD_TYPE_GOLD)
-const std::string kDefaultUpdaterChannel = "prod";
+const const char kDefaultUpdaterChannel[] = "prod";
 #endif
 
 std::string GetDeviceProperty(SbSystemPropertyId id) {
@@ -231,7 +232,6 @@
 void Configurator::SetChannel(const std::string& updater_channel) {
   base::AutoLock auto_lock(updater_channel_lock_);
   updater_channel_ = updater_channel;
-  persisted_data_->SetUpdaterChannel(GetAppGuid(), updater_channel);
 }
 
 bool Configurator::IsChannelValid(const std::string& channel) {
@@ -254,5 +254,16 @@
   updater_status_ = status;
 }
 
+std::string Configurator::GetPreviousUpdaterStatus() const {
+  base::AutoLock auto_lock(
+      const_cast<base::Lock&>(previous_updater_status_lock_));
+  return previous_updater_status_;
+}
+
+void Configurator::SetPreviousUpdaterStatus(const std::string& status) {
+  base::AutoLock auto_lock(previous_updater_status_lock_);
+  previous_updater_status_ = status;
+}
+
 }  // namespace updater
 }  // namespace cobalt
diff --git a/src/cobalt/updater/configurator.h b/src/cobalt/updater/configurator.h
index e335b4f..cfd1488 100644
--- a/src/cobalt/updater/configurator.h
+++ b/src/cobalt/updater/configurator.h
@@ -81,9 +81,12 @@
 
   bool IsChannelValid(const std::string& channel);
 
-  std::string GetUpdaterStatus() const;
+  std::string GetUpdaterStatus() const override;
   void SetUpdaterStatus(const std::string& status);
 
+  std::string GetPreviousUpdaterStatus() const override;
+  void SetPreviousUpdaterStatus(const std::string& status) override;
+
  private:
   friend class base::RefCountedThreadSafe<Configurator>;
   ~Configurator() override;
@@ -98,6 +101,8 @@
   SbAtomic32 is_channel_changed_;
   std::string updater_status_;
   base::Lock updater_status_lock_;
+  std::string previous_updater_status_;
+  base::Lock previous_updater_status_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(Configurator);
 };
diff --git a/src/cobalt/updater/updater_module.cc b/src/cobalt/updater/updater_module.cc
index 2f0452b..e213a08 100644
--- a/src/cobalt/updater/updater_module.cc
+++ b/src/cobalt/updater/updater_module.cc
@@ -50,8 +50,8 @@
     0x9e, 0x8b, 0x2d, 0x22, 0x65, 0x19, 0xb1, 0xfa, 0xba, 0x02, 0x04,
     0x3a, 0xb2, 0x7a, 0xf6, 0xfe, 0xd5, 0x35, 0xa1, 0x19, 0xd9};
 
-// The map to translate updater status from enum to readable string.
-const std::map<ComponentState, const char*> updater_status_map = {
+// The map to translate update state from ComponentState to readable string.
+const std::map<ComponentState, const char*> update_state_map = {
     {ComponentState::kNew, "Will check for update soon"},
     {ComponentState::kChecking, "Checking for update"},
     {ComponentState::kCanUpdate, "Update is available"},
@@ -78,9 +78,15 @@
 void Observer::OnEvent(Events event, const std::string& id) {
   std::string status;
   if (update_client_->GetCrxUpdateState(id, &crx_update_item_)) {
-    auto status_iterator = updater_status_map.find(crx_update_item_.state);
-    if (status_iterator == updater_status_map.end()) {
+    auto status_iterator = update_state_map.find(crx_update_item_.state);
+    if (status_iterator == update_state_map.end()) {
       status = "Status is unknown.";
+    } else if (crx_update_item_.state == ComponentState::kUpToDate &&
+               updater_configurator_->GetPreviousUpdaterStatus().compare(
+                   update_state_map.find(ComponentState::kUpdated)->second) ==
+                   0) {
+      status =
+          std::string(update_state_map.find(ComponentState::kUpdated)->second);
     } else {
       status = std::string(status_iterator->second);
     }
@@ -288,5 +294,21 @@
   }
 }
 
+int UpdaterModule::GetInstallationIndex() const {
+  auto installation_manager =
+      static_cast<const CobaltExtensionInstallationManagerApi*>(
+          SbSystemGetExtension(kCobaltExtensionInstallationManagerName));
+  if (!installation_manager) {
+    SB_LOG(ERROR) << "Updater failed to get installation manager extension.";
+    return -1;
+  }
+  int index = installation_manager->GetCurrentInstallationIndex();
+  if (index == IM_EXT_ERROR) {
+    SB_LOG(ERROR) << "Updater failed to get current installation index.";
+    return -1;
+  }
+  return index;
+}
+
 }  // namespace updater
 }  // namespace cobalt
diff --git a/src/cobalt/updater/updater_module.h b/src/cobalt/updater/updater_module.h
index d275556..076f42a 100644
--- a/src/cobalt/updater/updater_module.h
+++ b/src/cobalt/updater/updater_module.h
@@ -78,6 +78,8 @@
 
   void ResetInstallations();
 
+  int GetInstallationIndex() const;
+
  private:
   base::Thread updater_thread_;
   scoped_refptr<update_client::UpdateClient> update_client_;
diff --git a/src/cobalt/websocket/web_socket_impl_test.cc b/src/cobalt/websocket/web_socket_impl_test.cc
index 7e2a627..8db8285 100644
--- a/src/cobalt/websocket/web_socket_impl_test.cc
+++ b/src/cobalt/websocket/web_socket_impl_test.cc
@@ -12,9 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "cobalt/websocket/web_socket.h"
 #include "cobalt/websocket/web_socket_impl.h"
 
+#include "cobalt/websocket/web_socket.h"
+
 #include <memory>
 #include <vector>
 
@@ -50,7 +51,7 @@
 class FakeSettings : public dom::DOMSettings {
  public:
   FakeSettings()
-      : dom::DOMSettings(0, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+      : dom::DOMSettings(0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                          null_debugger_hooks_, NULL),
         base_("https://127.0.0.1:1234") {
     network_module_.reset(new network::NetworkModule());
diff --git a/src/components/update_client/component.cc b/src/components/update_client/component.cc
index 50ec274..8cd63fe 100644
--- a/src/components/update_client/component.cc
+++ b/src/components/update_client/component.cc
@@ -559,6 +559,12 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   auto& component = State::component();
+
+#if defined(OS_STARBOARD)
+  auto& config = component.update_context_.config;
+  config->SetPreviousUpdaterStatus(config->GetUpdaterStatus());
+#endif
+
   if (component.crx_component()) {
     TransitionState(std::make_unique<StateChecking>(&component));
   } else {
@@ -597,6 +603,21 @@
 void Component::StateChecking::UpdateCheckComplete() {
   DCHECK(thread_checker_.CalledOnValidThread());
   auto& component = State::component();
+
+#if defined(OS_STARBOARD)
+  auto& config = component.update_context_.config;
+  auto metadata = component.update_context_.update_checker->GetPersistedData();
+  if (metadata != nullptr) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&PersistedData::SetUpdaterChannel,
+                                  base::Unretained(metadata), component.id_,
+                                  config->GetChannel()));
+  } else {
+    SB_LOG(WARNING) << "Failed to get the persisted data store to write the "
+                       "updater channel.";
+  }
+#endif
+
   if (!component.error_code_) {
     if (component.status_ == "ok") {
       TransitionState(std::make_unique<StateCanUpdate>(&component));
diff --git a/src/components/update_client/configurator.h b/src/components/update_client/configurator.h
index ab7e01e..64d931a 100644
--- a/src/components/update_client/configurator.h
+++ b/src/components/update_client/configurator.h
@@ -171,6 +171,11 @@
   // parameters.
   virtual void SetChannel(const std::string& channel) = 0;
 
+  virtual std::string GetPreviousUpdaterStatus() const = 0;
+  virtual void SetPreviousUpdaterStatus(const std::string& status) = 0;
+
+  virtual std::string GetUpdaterStatus() const = 0;
+
   // Compare and swap the is_channel_changed flag.
   virtual void CompareAndSwapChannelChanged(int old_value, int new_value) = 0;
 
diff --git a/src/precommit_hooks/clang_format_wrapper.py b/src/precommit_hooks/clang_format_wrapper.py
new file mode 100755
index 0000000..d21854c
--- /dev/null
+++ b/src/precommit_hooks/clang_format_wrapper.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+# 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.
+"""Get correct clang-format installation and run it."""
+
+import os
+import platform
+import subprocess
+import sys
+
+if __name__ == '__main__':
+  clang_format_args = sys.argv[1:]
+  path_to_clang_format = [os.getcwd(), 'buildtools']
+
+  system = platform.system()
+  if system == 'Linux':
+    path_to_clang_format += ['linux64', 'clang-format']
+  elif system == 'Darwin':
+    path_to_clang_format += ['mac', 'clang-format']
+  elif system == 'Windows':
+    path_to_clang_format += ['win', 'clang-format.exe']
+  else:
+    sys.exit(1)
+
+  clang_format_executable = os.path.join(*path_to_clang_format)
+  sys.exit(subprocess.call([clang_format_executable] + clang_format_args))
diff --git a/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py b/src/precommit_hooks/custom_hooks/check_copyright_year.py
similarity index 96%
rename from src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py
rename to src/precommit_hooks/custom_hooks/check_copyright_year.py
index 692e44f..a75e8b9 100755
--- a/src/third_party/precommit-hooks/custom_hooks/check_copyright_year.py
+++ b/src/precommit_hooks/custom_hooks/check_copyright_year.py
@@ -12,6 +12,7 @@
 # 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.
+"""Check that the copyright header line adheres to the required format."""
 
 import datetime
 import os
@@ -92,5 +93,5 @@
   return False
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
   sys.exit(CheckCopyrightYear(sys.argv[1:]))
diff --git a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py b/src/precommit_hooks/gcheckstyle_wrapper.py
similarity index 64%
copy from src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
copy to src/precommit_hooks/gcheckstyle_wrapper.py
index a49568b..def89b3 100755
--- a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
+++ b/src/precommit_hooks/gcheckstyle_wrapper.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python3
-#
 # Copyright 2020 The Cobalt Authors. All Rights Reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,14 +12,20 @@
 # 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.
+"""See if internal tool gcheckstyle is available."""
 
+import subprocess
 import sys
 
 try:
-  import sync_keyboxes
+  from internal_tools_paths import checkstyle_path
 except ImportError:
-  print('sync_keyboxes.py not found, skipping.')
-  sys.exit(0)
+  checkstyle_path = None
 
-if __name__ == "__main__":
-  sys.exit(sync_keyboxes.SyncKeyboxesForCurrentBranch())
+if __name__ == '__main__':
+  gcheckstyle_args = sys.argv[1:]
+  try:
+    sys.exit(subprocess.call([checkstyle_path] + gcheckstyle_args))
+  except OSError:
+    print('Checkstyle not found, skipping.')
+    sys.exit(0)
diff --git a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py b/src/precommit_hooks/google_java_format_wrapper.py
similarity index 68%
copy from src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
copy to src/precommit_hooks/google_java_format_wrapper.py
index a49568b..ad3448c 100755
--- a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
+++ b/src/precommit_hooks/google_java_format_wrapper.py
@@ -13,14 +13,15 @@
 # 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.
+"""Wrapper to check for google-java-format tool."""
 
+import platform
+import subprocess
 import sys
 
-try:
-  import sync_keyboxes
-except ImportError:
-  print('sync_keyboxes.py not found, skipping.')
-  sys.exit(0)
+if __name__ == '__main__':
+  if platform.system() != 'Linux':
+    sys.exit(0)
 
-if __name__ == "__main__":
-  sys.exit(sync_keyboxes.SyncKeyboxesForCurrentBranch())
+  google_java_format_args = sys.argv[1:]
+  sys.exit(subprocess.call(['google-java-format'] + google_java_format_args))
diff --git a/src/precommit_hooks/python3_check.py b/src/precommit_hooks/python3_check.py
new file mode 100644
index 0000000..fdc9abd
--- /dev/null
+++ b/src/precommit_hooks/python3_check.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# 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.
+"""Warns if python code isn't compatible with python 3."""
+
+import os
+import py_compile
+import sys
+import tempfile
+from typing import List
+
+
+def _CheckFileForPython3Compatibility(filename: str) -> bool:
+  if not os.path.exists(filename):
+    print(f'{filename} is not a valid path, skipping.')
+    return False
+
+  temp_file = tempfile.NamedTemporaryFile()
+  try:
+    py_compile.compile(filename, cfile=temp_file.name, doraise=True)
+    return False
+  except py_compile.PyCompileError as e:
+    print(e)
+    print(f'{filename} is not valid in Python 3, consider updating it.')
+    return True
+
+
+def CheckFilesForPython3Compatibility(files: List[str]) -> bool:
+  rets = [_CheckFileForPython3Compatibility(file) for file in files]
+  return any(rets)
+
+
+if __name__ == '__main__':
+  sys.exit(CheckFilesForPython3Compatibility(sys.argv[1:]))
diff --git a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py b/src/precommit_hooks/sync_keyboxes_wrapper.py
similarity index 90%
rename from src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
rename to src/precommit_hooks/sync_keyboxes_wrapper.py
index a49568b..0e21be1 100755
--- a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
+++ b/src/precommit_hooks/sync_keyboxes_wrapper.py
@@ -13,6 +13,7 @@
 # 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.
+"""Wrapper to check for internal tool sync_keyboxes."""
 
 import sys
 
@@ -22,5 +23,5 @@
   print('sync_keyboxes.py not found, skipping.')
   sys.exit(0)
 
-if __name__ == "__main__":
+if __name__ == '__main__':
   sys.exit(sync_keyboxes.SyncKeyboxesForCurrentBranch())
diff --git a/src/starboard/android/apk/app/build.gradle b/src/starboard/android/apk/app/build.gradle
index 5ab0feb..8e527e2 100644
--- a/src/starboard/android/apk/app/build.gradle
+++ b/src/starboard/android/apk/app/build.gradle
@@ -105,8 +105,6 @@
             signingConfig signingConfigs.debugConfig
         }
         qa {
-            debuggable true
-            jniDebuggable true
             externalNativeBuild {
                 cmake.arguments "-DCOBALT_CONFIG=qa"
             }
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
index 89b4be8..9665619 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/CobaltActivity.java
@@ -29,6 +29,7 @@
 import android.widget.FrameLayout;
 import dev.cobalt.media.MediaCodecUtil;
 import dev.cobalt.media.VideoSurfaceView;
+import dev.cobalt.util.DisplayUtil;
 import dev.cobalt.util.Log;
 import dev.cobalt.util.UsedByNative;
 import java.util.ArrayList;
@@ -118,14 +119,14 @@
       createNewSurfaceView();
     }
 
+    DisplayUtil.cacheDefaultDisplay(this);
+
     getStarboardBridge().onActivityStart(this, keyboardEditor);
-    getStarboardBridge().stopMediaPlaybackService();
     super.onStart();
   }
 
   @Override
   protected void onStop() {
-    getStarboardBridge().startMediaPlaybackService();
     getStarboardBridge().onActivityStop(this);
     super.onStop();
 
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
index 8c01db9..84212ad 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/coat/StarboardBridge.java
@@ -31,7 +31,7 @@
 import android.os.Build;
 import android.util.Size;
 import android.util.SizeF;
-import android.view.WindowManager;
+import android.view.Display;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
 import androidx.annotation.RequiresApi;
@@ -191,9 +191,9 @@
   protected void beforeSuspend() {
     try {
       Log.i(TAG, "Prepare to suspend");
-      // We want the MediaSession to be deactivated immediately before suspending so that by the time
-      // the launcher is visible our "Now Playing" card is already gone. Then Cobalt and the web app
-      // can take their time suspending after that.
+      // We want the MediaSession to be deactivated immediately before suspending so that by the
+      // time, the launcher is visible our "Now Playing" card is already gone. Then Cobalt and
+      // the web app can take their time suspending after that.
       cobaltMediaSession.suspend();
       for (CobaltService service : cobaltServices.values()) {
         service.beforeSuspend();
@@ -338,13 +338,13 @@
   @SuppressWarnings("unused")
   @UsedByNative
   SizeF getDisplayDpi() {
-    return DisplayUtil.getDisplayDpi(appContext);
+    return DisplayUtil.getDisplayDpi();
   }
 
   @SuppressWarnings("unused")
   @UsedByNative
   Size getDisplaySize() {
-    return DisplayUtil.getSystemDisplaySize(appContext);
+    return DisplayUtil.getSystemDisplaySize();
   }
 
   /**
@@ -559,18 +559,12 @@
       return false;
     }
 
-    Activity activity = activityHolder.get();
-    if (activity == null) {
+    Display defaultDisplay = DisplayUtil.getDefaultDisplay();
+    if (defaultDisplay == null) {
       return false;
     }
 
-    WindowManager windowManager = activity.getWindowManager();
-    if (windowManager == null) {
-      return false;
-    }
-
-    int[] supportedHdrTypes =
-        windowManager.getDefaultDisplay().getHdrCapabilities().getSupportedHdrTypes();
+    int[] supportedHdrTypes = defaultDisplay.getHdrCapabilities().getSupportedHdrTypes();
     for (int supportedType : supportedHdrTypes) {
       if (supportedType == hdrType) {
         return true;
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
index 17dae73..f131da7 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/ArtworkLoader.java
@@ -23,6 +23,7 @@
 import android.util.Pair;
 import android.util.Size;
 import androidx.annotation.NonNull;
+import dev.cobalt.util.DisplayUtil;
 import dev.cobalt.util.Log;
 import java.io.IOException;
 import java.io.InputStream;
@@ -43,11 +44,9 @@
 
   private final Handler handler = new Handler(Looper.getMainLooper());
   private final Callback callback;
-  private final Size displaySize;
 
-  public ArtworkLoader(Callback callback, Size displaySize) {
+  public ArtworkLoader(Callback callback) {
     this.callback = callback;
-    this.displaySize = displaySize;
   }
 
   /**
@@ -55,7 +54,7 @@
    * the background, and then when ready the callback will be called with the image.
    */
   public synchronized Bitmap getOrLoadArtwork(MediaImage[] artwork) {
-    MediaImage image = getBestFitImage(artwork);
+    MediaImage image = getBestFitImage(artwork, DisplayUtil.getDisplaySize());
     String url = (image == null) ? "" : image.src;
 
     // Check if this artwork is already loaded or requested.
@@ -76,7 +75,7 @@
    * TV launcher, or any other observer of the MediaSession), so we use display size as the largest
    * useful size on any particular device.
    */
-  private MediaImage getBestFitImage(MediaImage[] artwork) {
+  private MediaImage getBestFitImage(MediaImage[] artwork, Size displaySize) {
     if (artwork == null || artwork.length == 0) {
       return null;
     }
@@ -162,12 +161,13 @@
       }
 
       final Pair<String, Bitmap> urlBitmapPair = Pair.create(url, bitmap);
-      handler.post(new Runnable() {
-        @Override
-        public void run() {
-          onDownloadFinished(urlBitmapPair);
-        }
-      });
+      handler.post(
+          new Runnable() {
+            @Override
+            public void run() {
+              onDownloadFinished(urlBitmapPair);
+            }
+          });
     }
   }
 }
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
index 2bfce23..ff6fa9e 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/CobaltMediaSession.java
@@ -31,7 +31,6 @@
 import android.support.v4.media.session.PlaybackStateCompat;
 import android.view.WindowManager;
 import androidx.annotation.RequiresApi;
-import dev.cobalt.util.DisplayUtil;
 import dev.cobalt.util.Holder;
 import dev.cobalt.util.Log;
 
@@ -102,7 +101,7 @@
     this.activityHolder = activityHolder;
 
     this.volumeListener = volumeListener;
-    artworkLoader = new ArtworkLoader(this, DisplayUtil.getDisplaySize(context));
+    artworkLoader = new ArtworkLoader(this);
     setMediaSession();
   }
 
@@ -116,7 +115,9 @@
 
   private void setMediaSession() {
     Log.i(TAG, "MediaSession new");
-    mediaSession = new MediaSessionCompat(context, TAG);
+    if (mediaSession == null) {
+      mediaSession = new MediaSessionCompat(context, TAG);
+    }
     mediaSession.setFlags(MEDIA_SESSION_FLAG_HANDLES_TRANSPORT_CONTROLS);
     mediaSession.setCallback(
         new MediaSessionCompat.Callback() {
@@ -204,8 +205,12 @@
     wakeLock(playbackState == PLAYBACK_STATE_PLAYING);
     audioFocus(playbackState == PLAYBACK_STATE_PLAYING);
 
-    boolean activating = playbackState != PLAYBACK_STATE_NONE && !mediaSession.isActive();
-    boolean deactivating = playbackState == PLAYBACK_STATE_NONE && mediaSession.isActive();
+    boolean activating = true;
+    boolean deactivating = false;
+    if (mediaSession != null) {
+      activating = playbackState != PLAYBACK_STATE_NONE && !mediaSession.isActive();
+      deactivating = playbackState == PLAYBACK_STATE_NONE && mediaSession.isActive();
+    }
     if (activating) {
       // Resuming or new playbacks land here.
       setMediaSession();
@@ -219,6 +224,7 @@
       // Suspending lands here.
       Log.i(TAG, "MediaSession release");
       mediaSession.release();
+      mediaSession = null;
     }
   }
 
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
index d0585e9..e108efd 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecBridge.java
@@ -23,6 +23,7 @@
 import android.media.AudioFormat;
 import android.media.MediaCodec;
 import android.media.MediaCodec.CryptoInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.VideoCapabilities;
 import android.media.MediaCrypto;
 import android.media.MediaFormat;
@@ -32,6 +33,7 @@
 import dev.cobalt.util.Log;
 import dev.cobalt.util.UsedByNative;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 /** A wrapper of the MediaCodec class. */
 @SuppressWarnings("unused")
@@ -80,6 +82,8 @@
   private double mPlaybackRate = 1.0;
   private int mFps = 30;
 
+  private MediaCodec.OnFrameRenderedListener mTunnelModeFrameRendererListener;
+
   // Functions that require this will be called frequently in a tight loop.
   // Only create one of these and reuse it to avoid excessive allocations,
   // which would cause GC cycles long enough to impact playback.
@@ -345,15 +349,25 @@
         float whitePointChromaticityX,
         float whitePointChromaticityY,
         float maxMasteringLuminance,
-        float minMasteringLuminance) {
+        float minMasteringLuminance,
+        int maxCll,
+        int maxFall) {
       this.colorRange = colorRange;
       this.colorStandard = colorStandard;
       this.colorTransfer = colorTransfer;
 
+      if (maxCll <= 0) {
+        maxCll = DEFAULT_MAX_CLL;
+      }
+      if (maxFall <= 0) {
+        maxFall = DEFAULT_MAX_FALL;
+      }
+
       // This logic is inspired by
       // https://github.com/google/ExoPlayer/blob/deb9b301b2c7ef66fdd7d8a3e58298a79ba9c619/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java#L1803.
       byte[] hdrStaticInfoData = new byte[25];
-      ByteBuffer hdrStaticInfo = ByteBuffer.wrap(hdrStaticInfoData);
+      ByteBuffer hdrStaticInfo = ByteBuffer.wrap(hdrStaticInfoData).order(ByteOrder.LITTLE_ENDIAN);
+      ;
       hdrStaticInfo.put((byte) 0);
       hdrStaticInfo.putShort((short) ((primaryRChromaticityX * MAX_CHROMATICITY) + 0.5f));
       hdrStaticInfo.putShort((short) ((primaryRChromaticityY * MAX_CHROMATICITY) + 0.5f));
@@ -365,8 +379,8 @@
       hdrStaticInfo.putShort((short) ((whitePointChromaticityY * MAX_CHROMATICITY) + 0.5f));
       hdrStaticInfo.putShort((short) (maxMasteringLuminance + 0.5f));
       hdrStaticInfo.putShort((short) (minMasteringLuminance + 0.5f));
-      hdrStaticInfo.putShort((short) DEFAULT_MAX_CLL);
-      hdrStaticInfo.putShort((short) DEFAULT_MAX_FALL);
+      hdrStaticInfo.putShort((short) maxCll);
+      hdrStaticInfo.putShort((short) maxFall);
       hdrStaticInfo.rewind();
       this.hdrStaticInfo = hdrStaticInfo;
     }
@@ -404,7 +418,8 @@
       MediaCodec mediaCodec,
       String mime,
       boolean adaptivePlaybackSupported,
-      BitrateAdjustmentTypes bitrateAdjustmentType) {
+      BitrateAdjustmentTypes bitrateAdjustmentType,
+      int tunnelModeAudioSessionId) {
     if (mediaCodec == null) {
       throw new IllegalArgumentException();
     }
@@ -477,6 +492,24 @@
           }
         };
     mMediaCodec.setCallback(mCallback);
+
+    // TODO: support OnFrameRenderedListener for non tunnel mode
+    if (tunnelModeAudioSessionId != -1 && Build.VERSION.SDK_INT >= 23) {
+      mTunnelModeFrameRendererListener =
+          new MediaCodec.OnFrameRenderedListener() {
+            @Override
+            public void onFrameRendered(MediaCodec codec, long presentationTimeUs, long nanoTime) {
+              synchronized (this) {
+                if (mNativeMediaCodecBridge == 0) {
+                  return;
+                }
+                nativeOnMediaCodecFrameRendered(
+                    mNativeMediaCodecBridge, presentationTimeUs, nanoTime);
+              }
+            }
+          };
+      mMediaCodec.setOnFrameRenderedListener(mTunnelModeFrameRendererListener, null);
+    }
   }
 
   @SuppressWarnings("unused")
@@ -507,7 +540,12 @@
     }
     MediaCodecBridge bridge =
         new MediaCodecBridge(
-            nativeMediaCodecBridge, mediaCodec, mime, true, BitrateAdjustmentTypes.NO_ADJUSTMENT);
+            nativeMediaCodecBridge,
+            mediaCodec,
+            mime,
+            true,
+            BitrateAdjustmentTypes.NO_ADJUSTMENT,
+            -1);
 
     MediaFormat mediaFormat = createAudioFormat(mime, sampleRate, channelCount);
     setFrameHasADTSHeader(mediaFormat);
@@ -537,19 +575,22 @@
       Surface surface,
       MediaCrypto crypto,
       ColorInfo colorInfo,
+      int tunnelModeAudioSessionId,
       CreateMediaCodecBridgeResult outCreateMediaCodecBridgeResult) {
     MediaCodec mediaCodec = null;
     outCreateMediaCodecBridgeResult.mMediaCodecBridge = null;
 
     boolean findHDRDecoder = android.os.Build.VERSION.SDK_INT >= 24 && colorInfo != null;
+    boolean findTunneledDecoder = tunnelModeAudioSessionId != -1;
     // On first pass, try to find a decoder with HDR if the color info is non-null.
     MediaCodecUtil.FindVideoDecoderResult findVideoDecoderResult =
         MediaCodecUtil.findVideoDecoder(
-            mime, isSecure, 0, 0, 0, 0, findHDRDecoder, requireSoftwareCodec);
+            mime, isSecure, 0, 0, 0, 0, findHDRDecoder, requireSoftwareCodec, findTunneledDecoder);
     if (findVideoDecoderResult.name.equals("") && findHDRDecoder) {
       // On second pass, forget HDR.
       findVideoDecoderResult =
-          MediaCodecUtil.findVideoDecoder(mime, isSecure, 0, 0, 0, 0, false, requireSoftwareCodec);
+          MediaCodecUtil.findVideoDecoder(
+              mime, isSecure, 0, 0, 0, 0, false, requireSoftwareCodec, findTunneledDecoder);
     }
     try {
       String decoderName = findVideoDecoderResult.name;
@@ -573,7 +614,12 @@
     }
     MediaCodecBridge bridge =
         new MediaCodecBridge(
-            nativeMediaCodecBridge, mediaCodec, mime, true, BitrateAdjustmentTypes.NO_ADJUSTMENT);
+            nativeMediaCodecBridge,
+            mediaCodec,
+            mime,
+            true,
+            BitrateAdjustmentTypes.NO_ADJUSTMENT,
+            tunnelModeAudioSessionId);
     MediaFormat mediaFormat =
         createVideoDecoderFormat(mime, width, height, findVideoDecoderResult.videoCapabilities);
 
@@ -592,6 +638,15 @@
       mediaFormat.setByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO, colorInfo.hdrStaticInfo);
     }
 
+    if (tunnelModeAudioSessionId != -1) {
+      mediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
+      mediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelModeAudioSessionId);
+      Log.d(
+          TAG,
+          String.format(
+              "Enabled tunnel mode playback on audio session %d", tunnelModeAudioSessionId));
+    }
+
     VideoCapabilities videoCapabilities = findVideoDecoderResult.videoCapabilities;
     int maxWidth = videoCapabilities.getSupportedWidths().getUpper();
     int maxHeight = videoCapabilities.getSupportedHeights().getUpper();
@@ -1138,4 +1193,7 @@
       int size);
 
   private native void nativeOnMediaCodecOutputFormatChanged(long nativeMediaCodecBridge);
+
+  private native void nativeOnMediaCodecFrameRendered(
+      long nativeMediaCodecBridge, long presentationTimeUs, long renderAtSystemTimeNs);
 }
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
index 03fb7cc..c03b931 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/MediaCodecUtil.java
@@ -397,7 +397,7 @@
       boolean mustSupportHdr) {
     FindVideoDecoderResult findVideoDecoderResult =
         findVideoDecoder(
-            mimeType, secure, frameWidth, frameHeight, bitrate, fps, mustSupportHdr, false);
+            mimeType, secure, frameWidth, frameHeight, bitrate, fps, mustSupportHdr, false, false);
     return !findVideoDecoderResult.name.equals("")
         && (!mustSupportHdr || isHdrCapableVideoDecoder(mimeType, findVideoDecoderResult));
   }
@@ -431,10 +431,19 @@
     }
 
     FindVideoDecoderResult findVideoDecoderResult =
-        findVideoDecoder(mimeType, false, 0, 0, 0, 0, true, false);
+        findVideoDecoder(mimeType, false, 0, 0, 0, 0, true, false, false);
     return isHdrCapableVideoDecoder(mimeType, findVideoDecoderResult);
   }
 
+  /** Determine whether the system support tunneled playback */
+  @SuppressWarnings("unused")
+  @UsedByNative
+  public static boolean hasTunneledCapableDecoder(String mimeType, boolean isSecure) {
+    FindVideoDecoderResult findVideoDecoderResult =
+        findVideoDecoder(mimeType, isSecure, 0, 0, 0, 0, false, false, true);
+    return !findVideoDecoderResult.name.equals("");
+  }
+
   /** Determine whether findVideoDecoderResult is capable of playing HDR */
   public static boolean isHdrCapableVideoDecoder(
       String mimeType, FindVideoDecoderResult findVideoDecoderResult) {
@@ -473,15 +482,24 @@
       int frameHeight,
       int bitrate,
       int fps,
-      boolean hdr,
-      boolean requireSoftwareCodec) {
+      boolean hdr, // TODO: Move all boolean feature parameters after |secure|
+      boolean requireSoftwareCodec,
+      boolean requireTunneledPlayback) {
     Log.v(
         TAG,
         String.format(
-            "Searching for video decoder with parameters "
-                + "mimeType: %s, secure: %b, frameWidth: %d, frameHeight: %d,"
-                + " bitrate: %d, fps: %d, hdr: %b, requireSoftwareCodec: %b",
-            mimeType, secure, frameWidth, frameHeight, bitrate, fps, hdr, requireSoftwareCodec));
+            "Searching for video decoder with parameters mimeType: %s, secure: %b, frameWidth: %d,"
+                + " frameHeight: %d, bitrate: %d, fps: %d, hdr: %b, requireSoftwareCodec: %b,"
+                + " requireTunneledPlayback: %b",
+            mimeType,
+            secure,
+            frameWidth,
+            frameHeight,
+            bitrate,
+            fps,
+            hdr,
+            requireSoftwareCodec,
+            requireTunneledPlayback));
     Log.v(
         TAG,
         String.format(
@@ -547,8 +565,9 @@
                   "Rejecting %s, reason: want secure decoder and !FEATURE_SecurePlayback", name));
           continue;
         }
-        if (codecCapabilities.isFeatureRequired(
-            MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback)) {
+        if (!requireTunneledPlayback
+            && codecCapabilities.isFeatureRequired(
+                MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback)) {
           Log.v(
               TAG,
               String.format("Rejecting %s, reason: codec requires FEATURE_TunneledPlayback", name));
@@ -562,6 +581,16 @@
               String.format("Rejecting %s, reason: code requires FEATURE_SecurePlayback", name));
           continue;
         }
+        if (requireTunneledPlayback
+            && !codecCapabilities.isFeatureSupported(
+                MediaCodecInfo.CodecCapabilities.FEATURE_TunneledPlayback)) {
+          Log.v(
+              TAG,
+              String.format(
+                  "Rejecting %s, reason: want tunneled playback and !FEATURE_TunneledPlayback",
+                  name));
+          continue;
+        }
 
         // VideoCapabilties is not implemented correctly on this device.
         if (Build.VERSION.SDK_INT < 23
@@ -573,17 +602,13 @@
         }
 
         VideoCapabilities videoCapabilities = codecCapabilities.getVideoCapabilities();
-        if (frameWidth != 0 && frameHeight != 0) {
-          if (!videoCapabilities.isSizeSupported(frameWidth, frameHeight)) {
-            Log.v(
-                TAG,
-                String.format(
-                    "Rejecting %s, reason: width %s is not compatible with height %d",
-                    name, frameWidth, frameHeight));
-            continue;
-          }
-        } else if (frameWidth != 0) {
-          if (!videoCapabilities.getSupportedWidths().contains(frameWidth)) {
+
+        // Disable the improved support check based on more specific APIs, like isSizeSupported() or
+        // areSizeAndRateSupported().  These APIs are theoretically more accurate, but we are unsure
+        // about their level of support on various Android TV platforms.
+        final boolean fallbackToMaximumSupportedCheck = true;
+        if (fallbackToMaximumSupportedCheck) {
+          if (frameWidth != 0 && !videoCapabilities.getSupportedWidths().contains(frameWidth)) {
             Log.v(
                 TAG,
                 String.format(
@@ -591,8 +616,7 @@
                     name, videoCapabilities.getSupportedWidths().toString(), frameWidth));
             continue;
           }
-        } else if (frameHeight != 0) {
-          if (!videoCapabilities.getSupportedHeights().contains(frameHeight)) {
+          if (frameHeight != 0 && !videoCapabilities.getSupportedHeights().contains(frameHeight)) {
             Log.v(
                 TAG,
                 String.format(
@@ -600,6 +624,35 @@
                     name, videoCapabilities.getSupportedHeights().toString(), frameHeight));
             continue;
           }
+        } else {
+          if (frameWidth != 0 && frameHeight != 0) {
+            if (!videoCapabilities.isSizeSupported(frameWidth, frameHeight)) {
+              Log.v(
+                  TAG,
+                  String.format(
+                      "Rejecting %s, reason: width %s is not compatible with height %d",
+                      name, frameWidth, frameHeight));
+              continue;
+            }
+          } else if (frameWidth != 0) {
+            if (!videoCapabilities.getSupportedWidths().contains(frameWidth)) {
+              Log.v(
+                  TAG,
+                  String.format(
+                      "Rejecting %s, reason: supported widths %s does not contain %d",
+                      name, videoCapabilities.getSupportedWidths().toString(), frameWidth));
+              continue;
+            }
+          } else if (frameHeight != 0) {
+            if (!videoCapabilities.getSupportedHeights().contains(frameHeight)) {
+              Log.v(
+                  TAG,
+                  String.format(
+                      "Rejecting %s, reason: supported heights %s does not contain %d",
+                      name, videoCapabilities.getSupportedHeights().toString(), frameHeight));
+              continue;
+            }
+          }
         }
         if (bitrate != 0 && !videoCapabilities.getBitrateRange().contains(bitrate)) {
           Log.v(
@@ -609,29 +662,40 @@
                   name, videoCapabilities.getBitrateRange().toString(), bitrate));
           continue;
         }
-        if (fps != 0) {
-          if (frameHeight != 0 && frameWidth != 0) {
-            if (!videoCapabilities.areSizeAndRateSupported(frameWidth, frameHeight, fps)) {
-              Log.v(
-                  TAG,
-                  String.format(
-                      "Rejecting %s, reason: supported frame rates %s does not contain %d",
-                      name,
-                      videoCapabilities
-                          .getSupportedFrameRatesFor(frameWidth, frameHeight)
-                          .toString(),
-                      fps));
-              continue;
-            }
-          } else {
-            // At least one of frameHeight or frameWidth is 0
-            if (!videoCapabilities.getSupportedFrameRates().contains(fps)) {
-              Log.v(
-                  TAG,
-                  String.format(
-                      "Rejecting %s, reason: supported frame rates %s does not contain %d",
-                      name, videoCapabilities.getSupportedFrameRates().toString(), fps));
-              continue;
+        if (fallbackToMaximumSupportedCheck) {
+          if (fps != 0 && !videoCapabilities.getSupportedFrameRates().contains(fps)) {
+            Log.v(
+                TAG,
+                String.format(
+                    "Rejecting %s, reason: supported frame rates %s does not contain %d",
+                    name, videoCapabilities.getSupportedFrameRates().toString(), fps));
+            continue;
+          }
+        } else {
+          if (fps != 0) {
+            if (frameHeight != 0 && frameWidth != 0) {
+              if (!videoCapabilities.areSizeAndRateSupported(frameWidth, frameHeight, fps)) {
+                Log.v(
+                    TAG,
+                    String.format(
+                        "Rejecting %s, reason: supported frame rates %s does not contain %d",
+                        name,
+                        videoCapabilities
+                            .getSupportedFrameRatesFor(frameWidth, frameHeight)
+                            .toString(),
+                        fps));
+                continue;
+              }
+            } else {
+              // At least one of frameHeight or frameWidth is 0
+              if (!videoCapabilities.getSupportedFrameRates().contains(fps)) {
+                Log.v(
+                    TAG,
+                    String.format(
+                        "Rejecting %s, reason: supported frame rates %s does not contain %d",
+                        name, videoCapabilities.getSupportedFrameRates().toString(), fps));
+                continue;
+              }
             }
           }
         }
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
index 0274811..6afac46 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/media/VideoFrameReleaseTimeHelper.java
@@ -29,14 +29,14 @@
 
 package dev.cobalt.media;
 
-import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.view.Choreographer;
 import android.view.Choreographer.FrameCallback;
-import android.view.WindowManager;
+import android.view.Display;
 import androidx.annotation.RequiresApi;
+import dev.cobalt.util.DisplayUtil;
 import dev.cobalt.util.UsedByNative;
 
 /** Makes a best effort to adjust frame release timestamps for a smoother visual result. */
@@ -72,20 +72,9 @@
    * default display's vsync signal.
    */
   @SuppressWarnings("unused")
-  public VideoFrameReleaseTimeHelper() {
-    this(DISPLAY_REFRESH_RATE_UNKNOWN);
-  }
-
-  /**
-   * Constructs an instance that smooths frame release timestamps and aligns them with the default
-   * display's vsync signal.
-   *
-   * @param context A context from which information about the default display can be retrieved.
-   */
-  @SuppressWarnings("unused")
   @UsedByNative
-  public VideoFrameReleaseTimeHelper(Context context) {
-    this(getDefaultDisplayRefreshRate(context));
+  public VideoFrameReleaseTimeHelper() {
+    this(getDefaultDisplayRefreshRate());
   }
 
   private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) {
@@ -220,11 +209,9 @@
     return snappedAfterDiff < snappedBeforeDiff ? snappedAfterNs : snappedBeforeNs;
   }
 
-  private static double getDefaultDisplayRefreshRate(Context context) {
-    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-    return manager.getDefaultDisplay() != null
-        ? manager.getDefaultDisplay().getRefreshRate()
-        : DISPLAY_REFRESH_RATE_UNKNOWN;
+  private static double getDefaultDisplayRefreshRate() {
+    Display defaultDisplay = DisplayUtil.getDefaultDisplay();
+    return defaultDisplay != null ? defaultDisplay.getRefreshRate() : DISPLAY_REFRESH_RATE_UNKNOWN;
   }
 
   /**
diff --git a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java
index 4b23394..c49cacb 100644
--- a/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java
+++ b/src/starboard/android/apk/app/src/main/java/dev/cobalt/util/DisplayUtil.java
@@ -15,53 +15,105 @@
 package dev.cobalt.util;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.DisplayMetrics;
 import android.util.Size;
 import android.util.SizeF;
+import android.view.Display;
 import android.view.WindowManager;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
 /** Utility functions for querying display attributes. */
 public class DisplayUtil {
 
   private DisplayUtil() {}
 
-  /**
-   * Returns the physical pixels per inch of the screen in the X and Y
-   * dimensions.
-   */
-  public static SizeF getDisplayDpi(Context context) {
-    DisplayMetrics metrics = getDisplayMetrics(context);
+  private static Display defaultDisplay;
+
+  /** Returns the physical pixels per inch of the screen in the X and Y dimensions. */
+  public static SizeF getDisplayDpi() {
+    DisplayMetrics metrics = getDisplayMetrics();
     return new SizeF(metrics.xdpi, metrics.ydpi);
   }
 
+  /** Returns the default display associated with a context. */
+  @Nullable
+  public static Display getDefaultDisplay() {
+    synchronized (DisplayUtil.class) {
+      if (defaultDisplay != null && !defaultDisplay.isValid()) {
+        return null;
+      }
+
+      return defaultDisplay;
+    }
+  }
+
+  /** Cache the default display, this will be triggered when a NativeActivity starts. */
+  public static void cacheDefaultDisplay(Context context) {
+    Display display = getDisplayFromContext(context);
+    synchronized (DisplayUtil.class) {
+      defaultDisplay = display;
+    }
+  }
+
+  /**
+   * Returns the default display associated with a context. When API Level >= 30, pass {@link
+   * android.app.Activity} for the context parameter.
+   */
+  @Nullable
+  public static Display getDisplayFromContext(Context context) {
+    if (context == null) {
+      return null;
+    }
+    if (android.os.Build.VERSION.SDK_INT >= 30) {
+      return getDefaultDisplayV30(context);
+    } else {
+      return getDefaultDisplayDeprecated(context);
+    }
+  }
+
+  @Nullable
+  @SuppressWarnings("deprecation")
+  private static Display getDefaultDisplayDeprecated(Context context) {
+    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+    return (wm == null) ? null : wm.getDefaultDisplay();
+  }
+
+  @Nullable
+  @RequiresApi(30)
+  private static Display getDefaultDisplayV30(Context context) {
+    return context.getDisplay();
+  }
+
   /**
    * Returns the size of the physical display size in pixels.
    *
-   * <p>This differs from {@link #getSystemDisplaySize(Context)} because it only uses
-   * {@link DisplayMetrics}.
+   * <p>This differs from {@link #getSystemDisplaySize()} because it only uses {@link
+   * DisplayMetrics}.
    */
-  public static Size getDisplaySize(Context context) {
-    DisplayMetrics metrics = getDisplayMetrics(context);
+  public static Size getDisplaySize() {
+    DisplayMetrics metrics = getDisplayMetrics();
     return new Size(metrics.widthPixels, metrics.heightPixels);
   }
 
   /**
    * Returns the size of the current physical display size in pixels.
    *
-   * <p>This differs from {@link #getDisplaySize(Context)} because it allows the
-   * system property "sys.display-size" to override {@link DisplayMetrics}.
+   * <p>This differs from {@link #getDisplaySize()} because it allows the system property
+   * "sys.display-size" to override {@link DisplayMetrics}.
    */
-  public static Size getSystemDisplaySize(Context context) {
+  public static Size getSystemDisplaySize() {
     Size widthAndHeightPx = getSystemDisplayWidthAndHeightPxInternal();
     if (widthAndHeightPx == null) {
-      widthAndHeightPx = getDisplaySize(context);
+      widthAndHeightPx = getDisplaySize();
     }
     return widthAndHeightPx;
   }
 
   /**
-   * Returns the size of the current physical display size in pixels.
-   * or {@code null} if unavailable.
+   * Returns the size of the current physical display size in pixels. or {@code null} if
+   * unavailable.
    */
   private static Size getSystemDisplayWidthAndHeightPxInternal() {
     final String displaySize = SystemPropertiesHelper.getString("sys.display-size");
@@ -81,11 +133,14 @@
 
   private static DisplayMetrics cachedDisplayMetrics = null;
 
-  private static DisplayMetrics getDisplayMetrics(Context context) {
+  private static DisplayMetrics getDisplayMetrics() {
+    Resources.getSystem().getDisplayMetrics();
     if (cachedDisplayMetrics == null) {
       cachedDisplayMetrics = new DisplayMetrics();
-      ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
-          .getDefaultDisplay().getRealMetrics(cachedDisplayMetrics);
+      Display display = getDefaultDisplay();
+      if (display != null) {
+        display.getRealMetrics(cachedDisplayMetrics);
+      }
     }
     return cachedDisplayMetrics;
   }
diff --git a/src/starboard/android/apk/build.id b/src/starboard/android/apk/build.id
index d3b971d..e6dfba3 100644
--- a/src/starboard/android/apk/build.id
+++ b/src/starboard/android/apk/build.id
@@ -1 +1 @@
-289402
\ No newline at end of file
+291977
\ No newline at end of file
diff --git a/src/starboard/android/shared/accessibility_get_caption_settings.cc b/src/starboard/android/shared/accessibility_get_caption_settings.cc
index 66fe44f..dac3d5d 100644
--- a/src/starboard/android/shared/accessibility_get_caption_settings.cc
+++ b/src/starboard/android/shared/accessibility_get_caption_settings.cc
@@ -14,91 +14,26 @@
 
 #include <cmath>
 #include <cstdlib>
-#include <limits>
 #include <string>
 
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-
 #include "starboard/accessibility.h"
 #include "starboard/android/shared/jni_env_ext.h"
 #include "starboard/android/shared/jni_utils.h"
 #include "starboard/common/log.h"
 #include "starboard/configuration.h"
 #include "starboard/memory.h"
+#include "starboard/shared/starboard/accessibility_internal.h"
 
 using starboard::android::shared::JniEnvExt;
 using starboard::android::shared::ScopedLocalJavaRef;
+using starboard::shared::starboard::GetClosestCaptionColor;
+using starboard::shared::starboard::GetClosestFontSizePercentage;
+using starboard::shared::starboard::GetClosestOpacity;
 
 namespace {
 
-const int kRgbWhite = 0xFFFFFF;
-const int kRgbBlack = 0x000000;
-const int kRgbRed = 0xFF0000;
-const int kRgbYellow = 0xFFFF00;
-const int kRgbGreen = 0x00FF00;
-const int kRgbCyan = 0x00FFFF;
-const int kRgbBlue = 0x0000FF;
-const int kRgbMagenta = 0xFF00FF;
-
-const int kRgbColors[] = {
-  kRgbWhite,
-  kRgbBlack,
-  kRgbRed,
-  kRgbYellow,
-  kRgbGreen,
-  kRgbCyan,
-  kRgbBlue,
-  kRgbMagenta,
-};
-
-SbAccessibilityCaptionColor GetClosestCaptionColor(int color) {
-  int ref_color = kRgbWhite;
-  int min_distance = std::numeric_limits<int>::max();
-
-  int r = 0xFF & (color >> 16);
-  int g = 0xFF & (color >> 8);
-  int b = 0xFF & (color);
-
-  // Find the reference color with the least distance (squared).
-  for (int i = 0; i < SB_ARRAY_SIZE(kRgbColors); i++) {
-    int r_ref = 0xFF & (kRgbColors[i] >> 16);
-    int g_ref = 0xFF & (kRgbColors[i] >> 8);
-    int b_ref = 0xFF & (kRgbColors[i]);
-    int distance_squared = pow(r - r_ref, 2) +
-                           pow(g - g_ref, 2) +
-                           pow(b - b_ref, 2);
-    if (distance_squared < min_distance) {
-      ref_color = kRgbColors[i];
-      min_distance = distance_squared;
-    }
-  }
-
-  switch (ref_color) {
-    case kRgbWhite:
-      return kSbAccessibilityCaptionColorWhite;
-    case kRgbBlack:
-      return kSbAccessibilityCaptionColorBlack;
-    case kRgbRed:
-      return kSbAccessibilityCaptionColorRed;
-    case kRgbYellow:
-      return kSbAccessibilityCaptionColorYellow;
-    case kRgbGreen:
-      return kSbAccessibilityCaptionColorGreen;
-    case kRgbCyan:
-      return kSbAccessibilityCaptionColorCyan;
-    case kRgbBlue:
-      return kSbAccessibilityCaptionColorBlue;
-    case kRgbMagenta:
-      return kSbAccessibilityCaptionColorMagenta;
-    default:
-      NOTREACHED() << "Invalid RGB color conversion";
-      return kSbAccessibilityCaptionColorWhite;
-  }
-}
-
-SbAccessibilityCaptionCharacterEdgeStyle
-AndroidEdgeTypeToSbEdgeStyle(int edge_type) {
+SbAccessibilityCaptionCharacterEdgeStyle AndroidEdgeTypeToSbEdgeStyle(
+    int edge_type) {
   switch (edge_type) {
     case 0:
       return kSbAccessibilityCaptionCharacterEdgeStyleNone;
@@ -111,7 +46,7 @@
     case 4:
       return kSbAccessibilityCaptionCharacterEdgeStyleDepressed;
     default:
-      NOTREACHED() << "Invalid edge type conversion";
+      SB_NOTREACHED() << "Invalid edge type conversion";
       return kSbAccessibilityCaptionCharacterEdgeStyleNone;
   }
 }
@@ -133,104 +68,11 @@
     case 6:
       return kSbAccessibilityCaptionFontFamilySmallCapitals;
     default:
-      NOTREACHED() << "Invalid font family conversion";
+      SB_NOTREACHED() << "Invalid font family conversion";
       return kSbAccessibilityCaptionFontFamilyCasual;
   }
 }
 
-int FindClosestReferenceValue(int value, const int reference[],
-                              size_t reference_size) {
-  int result = reference[0];
-  int min_difference = std::numeric_limits<int>::max();
-
-  for (int i = 0; i < reference_size; i++) {
-    int difference = abs(reference[i] - value);
-    if (difference < min_difference) {
-      result = reference[i];
-      min_difference = difference;
-    }
-  }
-  return result;
-}
-
-const int kFontSizes[] = {
-  25,
-  50,
-  75,
-  100,
-  125,
-  150,
-  175,
-  200,
-  225,
-  250,
-  275,
-  300
-};
-
-SbAccessibilityCaptionFontSizePercentage GetClosestFontSizePercentage(
-    int font_size_percent) {
-  int reference_size = FindClosestReferenceValue(
-      font_size_percent, kFontSizes, SB_ARRAY_SIZE(kFontSizes));
-  switch (reference_size) {
-    case 25:
-      return kSbAccessibilityCaptionFontSizePercentage25;
-    case 50:
-      return kSbAccessibilityCaptionFontSizePercentage50;
-    case 75:
-      return kSbAccessibilityCaptionFontSizePercentage75;
-    case 100:
-      return kSbAccessibilityCaptionFontSizePercentage100;
-    case 125:
-      return kSbAccessibilityCaptionFontSizePercentage125;
-    case 150:
-      return kSbAccessibilityCaptionFontSizePercentage150;
-    case 175:
-      return kSbAccessibilityCaptionFontSizePercentage175;
-    case 200:
-      return kSbAccessibilityCaptionFontSizePercentage200;
-    case 225:
-      return kSbAccessibilityCaptionFontSizePercentage225;
-    case 250:
-      return kSbAccessibilityCaptionFontSizePercentage250;
-    case 275:
-      return kSbAccessibilityCaptionFontSizePercentage275;
-    case 300:
-      return kSbAccessibilityCaptionFontSizePercentage300;
-    default:
-      NOTREACHED() << "Invalid font size";
-      return kSbAccessibilityCaptionFontSizePercentage100;
-  }
-}
-
-const int kOpacities[] = {
-  0,
-  25,
-  50,
-  75,
-  100,
-};
-
-SbAccessibilityCaptionOpacityPercentage GetClosestOpacity(int opacity_percent) {
-  int reference_opacity_percent = FindClosestReferenceValue(
-      opacity_percent, kOpacities, SB_ARRAY_SIZE(kOpacities));
-  switch (reference_opacity_percent) {
-    case 0:
-      return kSbAccessibilityCaptionOpacityPercentage0;
-    case 25:
-      return kSbAccessibilityCaptionOpacityPercentage25;
-    case 50:
-      return kSbAccessibilityCaptionOpacityPercentage50;
-    case 75:
-      return kSbAccessibilityCaptionOpacityPercentage75;
-    case 100:
-      return kSbAccessibilityCaptionOpacityPercentage100;
-    default:
-      NOTREACHED() << "Invalid opacity percentage";
-      return kSbAccessibilityCaptionOpacityPercentage100;
-  }
-}
-
 SbAccessibilityCaptionState BooleanToCaptionState(bool is_set) {
   if (is_set) {
     return kSbAccessibilityCaptionStateSet;
@@ -260,7 +102,7 @@
 }  // namespace
 
 bool SbAccessibilityGetCaptionSettings(
-  SbAccessibilityCaptionSettings* caption_settings) {
+    SbAccessibilityCaptionSettings* caption_settings) {
   if (!caption_settings ||
       !SbMemoryIsZero(caption_settings,
                       sizeof(SbAccessibilityCaptionSettings))) {
@@ -288,33 +130,29 @@
 
   caption_settings->character_edge_style = AndroidEdgeTypeToSbEdgeStyle(
       env->GetIntFieldOrAbort(j_caption_settings.Get(), "edgeType", "I"));
-  caption_settings->character_edge_style_state = BooleanToCaptionState(
-      env->GetBooleanFieldOrAbort(j_caption_settings.Get(),
-                                  "hasEdgeType", "Z"));
+  caption_settings->character_edge_style_state =
+      BooleanToCaptionState(env->GetBooleanFieldOrAbort(
+          j_caption_settings.Get(), "hasEdgeType", "Z"));
 
   SetColorProperties(
       j_caption_settings.Get(), "foregroundColor", "hasForegroundColor",
-      &caption_settings->font_color,
-      &caption_settings->font_color_state,
-      &caption_settings->font_opacity,
-      &caption_settings->font_opacity_state);
+      &caption_settings->font_color, &caption_settings->font_color_state,
+      &caption_settings->font_opacity, &caption_settings->font_opacity_state);
 
-  SetColorProperties(
-      j_caption_settings.Get(), "backgroundColor", "hasBackgroundColor",
-      &caption_settings->background_color,
-      &caption_settings->background_color_state,
-      &caption_settings->background_opacity,
-      &caption_settings->background_opacity_state);
+  SetColorProperties(j_caption_settings.Get(), "backgroundColor",
+                     "hasBackgroundColor", &caption_settings->background_color,
+                     &caption_settings->background_color_state,
+                     &caption_settings->background_opacity,
+                     &caption_settings->background_opacity_state);
 
-  SetColorProperties(
-      j_caption_settings.Get(), "windowColor", "hasWindowColor",
-      &caption_settings->window_color,
-      &caption_settings->window_color_state,
-      &caption_settings->window_opacity,
-      &caption_settings->window_opacity_state);
+  SetColorProperties(j_caption_settings.Get(), "windowColor", "hasWindowColor",
+                     &caption_settings->window_color,
+                     &caption_settings->window_color_state,
+                     &caption_settings->window_opacity,
+                     &caption_settings->window_opacity_state);
 
   caption_settings->is_enabled =
-     env->GetBooleanFieldOrAbort(j_caption_settings.Get(), "isEnabled", "Z");
+      env->GetBooleanFieldOrAbort(j_caption_settings.Get(), "isEnabled", "Z");
   caption_settings->supports_is_enabled = true;
   caption_settings->supports_set_enabled = false;
 
diff --git a/src/starboard/android/shared/android_media_session_client.cc b/src/starboard/android/shared/android_media_session_client.cc
index afa436c..68f846f 100644
--- a/src/starboard/android/shared/android_media_session_client.cc
+++ b/src/starboard/android/shared/android_media_session_client.cc
@@ -201,10 +201,6 @@
   SbOnce(&once_flag, OnceInit);
   SbMutexAcquire(&mutex);
 
-  if (playback_state == kNone && g_callback_context != NULL) {
-    g_callback_context = NULL;
-  }
-
   SbMutexRelease(&mutex);
 
   jlong playback_state_actions = MediaSessionActionsToPlaybackStateActions(
diff --git a/src/starboard/android/shared/application_android.cc b/src/starboard/android/shared/application_android.cc
index 06adff2..39195dc 100644
--- a/src/starboard/android/shared/application_android.cc
+++ b/src/starboard/android/shared/application_android.cc
@@ -193,6 +193,21 @@
   env->CallStarboardVoidMethodOrAbort("beforeStartOrResume", "()V");
 }
 
+void ApplicationAndroid::OnSuspend() {
+  JniEnvExt* env = JniEnvExt::Get();
+  env->CallStarboardVoidMethodOrAbort("beforeSuspend", "()V");
+}
+
+void ApplicationAndroid::StartMediaPlaybackService() {
+  JniEnvExt* env = JniEnvExt::Get();
+  env->CallStarboardVoidMethodOrAbort("startMediaPlaybackService", "()V");
+}
+
+void ApplicationAndroid::StopMediaPlaybackService() {
+  JniEnvExt* env = JniEnvExt::Get();
+  env->CallStarboardVoidMethodOrAbort("stopMediaPlaybackService", "()V");
+}
+
 void ApplicationAndroid::ProcessAndroidCommand() {
   JniEnvExt* env = JniEnvExt::Get();
   AndroidCommand cmd;
@@ -234,6 +249,10 @@
         if (window_) {
           window_->native_window = native_window_;
         }
+        // Media playback service is tied to UI window being created/destroyed
+        // (rather than to the Activity lifecycle), the service should be
+        // stopped before native window being created.
+        StopMediaPlaybackService();
         // Now that we have the window, signal that the Android UI thread can
         // continue, before we start or resume the Starboard app.
         android_command_condition_.Signal();
@@ -243,8 +262,8 @@
         // have a window.
         env->CallStarboardVoidMethodOrAbort("beforeStartOrResume", "()V");
         DispatchStart();
-      } else if (state() == kStateConcealed) {
-        DispatchAndDelete(new Event(kSbEventTypeReveal, NULL, NULL));
+      } else if (state() == kStateConcealed || state() == kStateFrozen) {
+          DispatchAndDelete(new Event(kSbEventTypeReveal, NULL, NULL));
       } else {
         // Now that we got a window back, change the command for the switch
         // below to sync up with the current activity lifecycle.
@@ -256,6 +275,10 @@
       // early in SendAndroidCommand().
       {
         ScopedLock lock(android_command_mutex_);
+        // Media playback service is tied to UI window being created/destroyed
+        // (rather than to the Activity lifecycle). The service should be
+        // started after window being destroyed.
+        StartMediaPlaybackService();
         // Cobalt can't keep running without a window, even if the Activity
         // hasn't stopped yet. DispatchAndDelete() will inject events as needed
         // if we're not already paused.
@@ -333,7 +356,7 @@
         DispatchAndDelete(new Event(kSbEventTypeBlur, NULL, NULL));
         break;
       case AndroidCommand::kStop:
-        if (state() != kStateConcealed) {
+        if (state() != kStateConcealed && state() != kStateFrozen) {
           // We usually conceal when losing the window above, but if the window
           // wasn't destroyed (e.g. when Daydream starts) then we still have to
           // conceal when the Activity is stopped.
diff --git a/src/starboard/android/shared/application_android.h b/src/starboard/android/shared/application_android.h
index 6dad099..223ae8d 100644
--- a/src/starboard/android/shared/application_android.h
+++ b/src/starboard/android/shared/application_android.h
@@ -97,6 +97,7 @@
   void Teardown() override;
   bool IsStartImmediate() override { return false; }
   void OnResume() override;
+  void OnSuspend() override;
 
   // --- QueueApplication overrides ---
   bool MayHaveSystemEvents() override { return true; }
@@ -133,6 +134,10 @@
   void ProcessAndroidCommand();
   void ProcessAndroidInput();
   void ProcessKeyboardInject();
+
+  // Methods to start/stop Media playback service.
+  void StartMediaPlaybackService();
+  void StopMediaPlaybackService();
 };
 
 }  // namespace shared
diff --git a/src/starboard/android/shared/audio_decoder.h b/src/starboard/android/shared/audio_decoder.h
index ca7bc89..45460f5 100644
--- a/src/starboard/android/shared/audio_decoder.h
+++ b/src/starboard/android/shared/audio_decoder.h
@@ -64,6 +64,7 @@
   bool InitializeCodec();
   void ProcessOutputBuffer(MediaCodecBridge* media_codec_bridge,
                            const DequeueOutputResult& output) override;
+  void OnEndOfStreamWritten(MediaCodecBridge* media_codec_bridge) override {}
   void RefreshOutputFormat(MediaCodecBridge* media_codec_bridge) override;
   bool Tick(MediaCodecBridge* media_codec_bridge) override { return false; }
   void OnFlushing() override {}
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.cc b/src/starboard/android/shared/audio_track_audio_sink_type.cc
index cf9d744..c2ab013 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.cc
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.cc
@@ -164,7 +164,7 @@
   } else {
     SB_NOTREACHED();
   }
-  SB_CHECK(j_audio_data_) << "Failed to allocate |j_audio_data_|";
+  SB_DCHECK(j_audio_data_) << "Failed to allocate |j_audio_data_|";
 
   j_audio_data_ = env->ConvertLocalRefToGlobalRef(j_audio_data_);
 
@@ -331,6 +331,7 @@
 
     expected_written_frames =
         std::min(expected_written_frames, max_frames_per_request_);
+
     if (expected_written_frames == 0) {
       // It is possible that all the frames in buffer are written to the
       // soundcard, but those are not being consumed. If eos is reached,
@@ -393,7 +394,14 @@
     auto sync_time = start_time_ + accumulated_written_frames * kSbTimeSecond /
                                        sampling_frequency_hz_;
 
-    SB_CHECK(start_position + expected_written_frames <= frames_per_channel_);
+    SB_DCHECK(start_position + expected_written_frames <= frames_per_channel_)
+        << "start_position: " << start_position
+        << ", expected_written_frames: " << expected_written_frames
+        << ", frames_per_channel_: " << frames_per_channel_
+        << ", frames_in_buffer: " << frames_in_buffer
+        << ", written_frames_: " << written_frames_
+        << ", offset_in_frames: " << offset_in_frames;
+
     int written_frames = WriteData(
         env,
         IncrementPointerByBytes(frame_buffer_, start_position * channels_ *
diff --git a/src/starboard/android/shared/audio_track_audio_sink_type.h b/src/starboard/android/shared/audio_track_audio_sink_type.h
index c5b1ba7..4df64e9 100644
--- a/src/starboard/android/shared/audio_track_audio_sink_type.h
+++ b/src/starboard/android/shared/audio_track_audio_sink_type.h
@@ -125,21 +125,20 @@
 
   int WriteData(JniEnvExt* env, void* buffer, int size, SbTime sync_time);
 
-  // TODO: Add const to the following variables where appropriate.
-  Type* type_;
-  int channels_;
-  int sampling_frequency_hz_;
-  SbMediaAudioSampleType sample_type_;
+  Type* const type_;
+  const int channels_;
+  const int sampling_frequency_hz_;
+  const SbMediaAudioSampleType sample_type_;
   void* frame_buffer_;
-  int frames_per_channel_;
-  SbAudioSinkUpdateSourceStatusFunc update_source_status_func_;
-  ConsumeFramesFunc consume_frames_func_;
-  SbAudioSinkPrivate::ErrorFunc error_func_;
+  const int frames_per_channel_;
+  const SbAudioSinkUpdateSourceStatusFunc update_source_status_func_;
+  const ConsumeFramesFunc consume_frames_func_;
+  const SbAudioSinkPrivate::ErrorFunc error_func_;
   const SbTime start_time_;
   const int tunnel_mode_audio_session_id_;
   const int max_frames_per_request_;
 
-  void* context_;
+  void* const context_;
   int last_playback_head_position_ = 0;
   jobject j_audio_track_bridge_ = nullptr;
   jobject j_audio_data_ = nullptr;
diff --git a/src/starboard/android/shared/gyp_configuration.gypi b/src/starboard/android/shared/gyp_configuration.gypi
index 4267214..01b65db 100644
--- a/src/starboard/android/shared/gyp_configuration.gypi
+++ b/src/starboard/android/shared/gyp_configuration.gypi
@@ -22,6 +22,7 @@
     'gtest_target_type': 'shared_library',
     'sb_widevine_platform': 'android',
     'sb_enable_benchmark': 1,
+    'cobalt_licenses_platform': 'android',
 
     'gl_type': 'system_gles2',
     'enable_remote_debugging': 0,
diff --git a/src/starboard/android/shared/media_codec_bridge.cc b/src/starboard/android/shared/media_codec_bridge.cc
index f78c347..8711118 100644
--- a/src/starboard/android/shared/media_codec_bridge.cc
+++ b/src/starboard/android/shared/media_codec_bridge.cc
@@ -84,6 +84,19 @@
 }  // namespace
 
 extern "C" SB_EXPORT_PLATFORM void
+Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecFrameRendered(
+    JNIEnv* env,
+    jobject unused_this,
+    jlong native_media_codec_bridge,
+    jlong presentation_time_us,
+    jlong render_at_system_time_ns) {
+  MediaCodecBridge* media_codec_bridge =
+      reinterpret_cast<MediaCodecBridge*>(native_media_codec_bridge);
+  SB_DCHECK(media_codec_bridge);
+  media_codec_bridge->OnMediaCodecFrameRendered(presentation_time_us);
+}
+
+extern "C" SB_EXPORT_PLATFORM void
 Java_dev_cobalt_media_MediaCodecBridge_nativeOnMediaCodecError(
     JniEnvExt* env,
     jobject unused_this,
@@ -181,6 +194,7 @@
     jobject j_media_crypto,
     const SbMediaColorMetadata* color_metadata,
     bool require_software_codec,
+    int tunnel_mode_audio_session_id,
     std::string* error_message) {
   SB_DCHECK(error_message);
 
@@ -205,7 +219,7 @@
         color_range != COLOR_VALUE_UNKNOWN) {
       const auto& mastering_metadata = color_metadata->mastering_metadata;
       j_color_info.Reset(env->NewObjectOrAbort(
-          "dev/cobalt/media/MediaCodecBridge$ColorInfo", "(IIIFFFFFFFFFF)V",
+          "dev/cobalt/media/MediaCodecBridge$ColorInfo", "(IIIFFFFFFFFFFII)V",
           color_range, color_standard, color_transfer,
           mastering_metadata.primary_r_chromaticity_x,
           mastering_metadata.primary_r_chromaticity_y,
@@ -215,7 +229,8 @@
           mastering_metadata.primary_b_chromaticity_y,
           mastering_metadata.white_point_chromaticity_x,
           mastering_metadata.white_point_chromaticity_y,
-          mastering_metadata.luminance_max, mastering_metadata.luminance_min));
+          mastering_metadata.luminance_max, mastering_metadata.luminance_min,
+          color_metadata->max_cll, color_metadata->max_fall));
     }
   }
 
@@ -231,11 +246,12 @@
       "(JLjava/lang/String;ZZIILandroid/view/Surface;"
       "Landroid/media/MediaCrypto;"
       "Ldev/cobalt/media/MediaCodecBridge$ColorInfo;"
+      "I"
       "Ldev/cobalt/media/MediaCodecBridge$CreateMediaCodecBridgeResult;)"
       "V",
       reinterpret_cast<jlong>(native_media_codec_bridge.get()), j_mime.Get(),
       !!j_media_crypto, require_software_codec, width, height, j_surface,
-      j_media_crypto, j_color_info.Get(),
+      j_media_crypto, j_color_info.Get(), tunnel_mode_audio_session_id,
       j_create_media_codec_bridge_result.Get());
 
   jobject j_media_codec_bridge = env->CallObjectMethodOrAbort(
@@ -379,8 +395,9 @@
     return {status, 0, 0};
   }
 
-  return {status, env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
-                                            "sampleRate", "()I"),
+  return {status,
+          env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
+                                    "sampleRate", "()I"),
           env->CallIntMethodOrAbort(j_reused_get_output_format_result_,
                                     "channelCount", "()I")};
 }
@@ -409,6 +426,10 @@
   handler_->OnMediaCodecOutputFormatChanged();
 }
 
+void MediaCodecBridge::OnMediaCodecFrameRendered(SbTime frame_timestamp) {
+  handler_->OnMediaCodecFrameRendered(frame_timestamp);
+}
+
 MediaCodecBridge::MediaCodecBridge(Handler* handler) : handler_(handler) {
   SB_DCHECK(handler_);
 }
diff --git a/src/starboard/android/shared/media_codec_bridge.h b/src/starboard/android/shared/media_codec_bridge.h
index e68c69a..b472a57 100644
--- a/src/starboard/android/shared/media_codec_bridge.h
+++ b/src/starboard/android/shared/media_codec_bridge.h
@@ -88,6 +88,8 @@
                                                    int64_t presentation_time_us,
                                                    int size) = 0;
     virtual void OnMediaCodecOutputFormatChanged() = 0;
+    // This is only called on video decoder when tunnel mode is enabled.
+    virtual void OnMediaCodecFrameRendered(SbTime frame_timestamp) = 0;
 
    protected:
     ~Handler() {}
@@ -108,6 +110,7 @@
       jobject j_media_crypto,
       const SbMediaColorMetadata* color_metadata,
       bool require_software_codec,
+      int tunnel_mode_audio_session_id,
       std::string* error_message);
 
   ~MediaCodecBridge();
@@ -146,6 +149,7 @@
                                          int64_t presentation_time_us,
                                          int size);
   void OnMediaCodecOutputFormatChanged();
+  void OnMediaCodecFrameRendered(SbTime frame_timestamp);
 
  private:
   // |MediaCodecBridge|s must only be created through its factory methods.
diff --git a/src/starboard/android/shared/media_decoder.cc b/src/starboard/android/shared/media_decoder.cc
index fc5fa0d..496e509 100644
--- a/src/starboard/android/shared/media_decoder.cc
+++ b/src/starboard/android/shared/media_decoder.cc
@@ -78,7 +78,8 @@
     : media_type_(kSbMediaTypeAudio),
       host_(host),
       drm_system_(static_cast<DrmSystem*>(drm_system)),
-      condition_variable_(mutex_) {
+      condition_variable_(mutex_),
+      tunnel_mode_enabled_(false) {
   SB_DCHECK(host_);
 
   jobject j_media_crypto = drm_system_ ? drm_system_->GetMediaCrypto() : NULL;
@@ -107,16 +108,23 @@
                            SbDrmSystem drm_system,
                            const SbMediaColorMetadata* color_metadata,
                            bool require_software_codec,
+                           const FrameRenderedCB& frame_rendered_cb,
+                           int tunnel_mode_audio_session_id,
                            std::string* error_message)
     : media_type_(kSbMediaTypeVideo),
       host_(host),
       drm_system_(static_cast<DrmSystem*>(drm_system)),
+      frame_rendered_cb_(frame_rendered_cb),
+      tunnel_mode_enabled_(tunnel_mode_audio_session_id != -1),
       condition_variable_(mutex_) {
+  SB_DCHECK(frame_rendered_cb_);
+
   jobject j_media_crypto = drm_system_ ? drm_system_->GetMediaCrypto() : NULL;
   SB_DCHECK(!drm_system_ || j_media_crypto);
   media_codec_bridge_ = MediaCodecBridge::CreateVideoMediaCodecBridge(
       video_codec, width, height, this, j_output_surface, j_media_crypto,
-      color_metadata, require_software_codec, error_message);
+      color_metadata, require_software_codec, tunnel_mode_audio_session_id,
+      error_message);
   if (!media_codec_bridge_) {
     SB_LOG(ERROR) << "Failed to create video media codec bridge with error: "
                   << *error_message;
@@ -252,23 +260,35 @@
           pending_queue_input_buffer_task_ ||
           (!pending_tasks.empty() && !input_buffer_indices.empty());
       bool has_output = !dequeue_output_results.empty();
-      if (!has_input || !has_output) {
+      bool collect_pending_data = false;
+
+      if (tunnel_mode_enabled_) {
+        // We don't explicitly process output in tunnel mode.
+        collect_pending_data = !has_input;
+      } else {
+        collect_pending_data = !has_input || !has_output;
+      }
+
+      if (collect_pending_data) {
         ScopedLock scoped_lock(mutex_);
         CollectPendingData_Locked(&pending_tasks, &input_buffer_indices,
                                   &dequeue_output_results);
       }
 
-      if (!dequeue_output_results.empty()) {
-        auto& dequeue_output_result = dequeue_output_results.front();
-        if (dequeue_output_result.index < 0) {
-          host_->RefreshOutputFormat(media_codec_bridge_.get());
-        } else {
-          host_->ProcessOutputBuffer(media_codec_bridge_.get(),
-                                     dequeue_output_result);
+      if (!tunnel_mode_enabled_) {
+        // Output is only processed when tunnel mode is disabled.
+        if (!dequeue_output_results.empty()) {
+          auto& dequeue_output_result = dequeue_output_results.front();
+          if (dequeue_output_result.index < 0) {
+            host_->RefreshOutputFormat(media_codec_bridge_.get());
+          } else {
+            host_->ProcessOutputBuffer(media_codec_bridge_.get(),
+                                       dequeue_output_result);
+          }
+          dequeue_output_results.erase(dequeue_output_results.begin());
         }
-        dequeue_output_results.erase(dequeue_output_results.begin());
+        host_->Tick(media_codec_bridge_.get());
       }
-      host_->Tick(media_codec_bridge_.get());
 
       bool can_process_input =
           pending_queue_input_buffer_task_ ||
@@ -277,7 +297,11 @@
         ProcessOneInputBuffer(&pending_tasks, &input_buffer_indices);
       }
 
-      bool ticked = host_->Tick(media_codec_bridge_.get());
+      bool ticked = false;
+      if (!tunnel_mode_enabled_) {
+        // Output is only processed when tunnel mode is disabled.
+        ticked = host_->Tick(media_codec_bridge_.get());
+      }
 
       can_process_input =
           pending_queue_input_buffer_task_ ||
@@ -298,6 +322,7 @@
   SB_LOG(INFO) << "Destroying decoder thread.";
 }
 
+// TODO: Move this into dtor.
 void MediaDecoder::JoinOnThreads() {
   destroying_.store(true);
   condition_variable_.Signal();
@@ -432,6 +457,7 @@
     status = media_codec_bridge_->QueueInputBuffer(dequeue_input_result.index,
                                                    kNoOffset, size, kNoPts,
                                                    BUFFER_FLAG_END_OF_STREAM);
+    host_->OnEndOfStreamWritten(media_codec_bridge_.get());
   }
 
   if (status != MEDIA_CODEC_OK) {
@@ -561,6 +587,11 @@
   condition_variable_.Signal();
 }
 
+void MediaDecoder::OnMediaCodecFrameRendered(SbTime frame_timestamp) {
+  SB_DCHECK(tunnel_mode_enabled_);
+  frame_rendered_cb_(frame_timestamp);
+}
+
 }  // namespace shared
 }  // namespace android
 }  // namespace starboard
diff --git a/src/starboard/android/shared/media_decoder.h b/src/starboard/android/shared/media_decoder.h
index 80d0b7e..48d9826 100644
--- a/src/starboard/android/shared/media_decoder.h
+++ b/src/starboard/android/shared/media_decoder.h
@@ -44,6 +44,7 @@
  public:
   typedef ::starboard::shared::starboard::player::filter::ErrorCB ErrorCB;
   typedef ::starboard::shared::starboard::player::InputBuffer InputBuffer;
+  typedef std::function<void(SbTime)> FrameRenderedCB;
 
   // This class should be implemented by the users of MediaDecoder to receive
   // various notifications.  Note that all such functions are called on the
@@ -52,9 +53,10 @@
    public:
     virtual void ProcessOutputBuffer(MediaCodecBridge* media_codec_bridge,
                                      const DequeueOutputResult& output) = 0;
+    virtual void OnEndOfStreamWritten(MediaCodecBridge* media_codec_bridge) = 0;
     virtual void RefreshOutputFormat(MediaCodecBridge* media_codec_bridge) = 0;
     // This function gets called frequently on the decoding thread to give the
-    // Host a chance to process when the MediaDecoder is decoding video.
+    // Host a chance to process when the MediaDecoder is decoding.
     // TODO: Revise the scheduling logic to give the host a chance to process in
     //       a more elegant way.
     virtual bool Tick(MediaCodecBridge* media_codec_bridge) = 0;
@@ -79,6 +81,8 @@
                SbDrmSystem drm_system,
                const SbMediaColorMetadata* color_metadata,
                bool require_software_codec,
+               const FrameRenderedCB& frame_rendered_cb,
+               int tunnel_mode_audio_session_id,
                std::string* error_message);
   ~MediaDecoder();
 
@@ -152,17 +156,20 @@
                                          int64_t presentation_time_us,
                                          int size) override;
   void OnMediaCodecOutputFormatChanged() override;
+  void OnMediaCodecFrameRendered(SbTime frame_timestamp) override;
 
   ::starboard::shared::starboard::ThreadChecker thread_checker_;
 
   const SbMediaType media_type_;
   Host* host_;
+  DrmSystem* const drm_system_;
+  const FrameRenderedCB frame_rendered_cb_;
+  const bool tunnel_mode_enabled_;
+
   ErrorCB error_cb_;
 
   atomic_bool stream_ended_;
 
-  DrmSystem* drm_system_;
-
   atomic_bool destroying_;
 
   optional<QueueInputBufferTask> pending_queue_input_buffer_task_;
diff --git a/src/starboard/android/shared/player_components_factory.h b/src/starboard/android/shared/player_components_factory.h
index 350b00f..e31eff8 100644
--- a/src/starboard/android/shared/player_components_factory.h
+++ b/src/starboard/android/shared/player_components_factory.h
@@ -16,10 +16,16 @@
 #define STARBOARD_ANDROID_SHARED_PLAYER_COMPONENTS_FACTORY_H_
 
 #include <string>
+#include <vector>
 
 #include "starboard/android/shared/audio_decoder.h"
+#include "starboard/android/shared/audio_track_audio_sink_type.h"
+#include "starboard/android/shared/drm_system.h"
+#include "starboard/android/shared/jni_env_ext.h"
+#include "starboard/android/shared/jni_utils.h"
+#include "starboard/android/shared/media_common.h"
 #include "starboard/android/shared/video_decoder.h"
-#include "starboard/android/shared/video_render_algorithm.h"
+#include "starboard/atomic.h"
 #include "starboard/common/log.h"
 #include "starboard/common/ref_counted.h"
 #include "starboard/common/scoped_ptr.h"
@@ -39,6 +45,75 @@
 namespace android {
 namespace shared {
 
+// Tunnel mode is disabled by default.  Set the following variable to true to
+// enable tunnel mode.
+constexpr bool kTunnelModeEnabled = false;
+
+// This class allows us to force int16 sample type when tunnel mode is enabled.
+class AudioRendererSinkTunneled : public ::starboard::shared::starboard::
+                                      player::filter::AudioRendererSinkImpl {
+ public:
+  explicit AudioRendererSinkTunneled(int tunnel_mode_audio_session_id)
+      : AudioRendererSinkImpl(
+            [=](SbTime start_media_time,
+                int channels,
+                int sampling_frequency_hz,
+                SbMediaAudioSampleType audio_sample_type,
+                SbMediaAudioFrameStorageType audio_frame_storage_type,
+                SbAudioSinkFrameBuffers frame_buffers,
+                int frame_buffers_size_in_frames,
+                SbAudioSinkUpdateSourceStatusFunc update_source_status_func,
+                SbAudioSinkPrivate::ConsumeFramesFunc consume_frames_func,
+                SbAudioSinkPrivate::ErrorFunc error_func,
+                void* context) {
+              SB_DCHECK(tunnel_mode_audio_session_id != -1);
+
+              auto type = static_cast<AudioTrackAudioSinkType*>(
+                  SbAudioSinkPrivate::GetPreferredType());
+
+              return type->Create(
+                  channels, sampling_frequency_hz, audio_sample_type,
+                  audio_frame_storage_type, frame_buffers,
+                  frame_buffers_size_in_frames, update_source_status_func,
+                  consume_frames_func, error_func, start_media_time,
+                  tunnel_mode_audio_session_id, context);
+            }) {}
+
+ 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;
+  }
+};
+
+class AudioRendererSinkCallbackStub
+    : public starboard::shared::starboard::player::filter::AudioRendererSink::
+          RenderCallback {
+ public:
+  bool error_occurred() const { return error_occurred_.load(); }
+
+ private:
+  void GetSourceStatus(int* frames_in_buffer,
+                       int* offset_in_frames,
+                       bool* is_playing,
+                       bool* is_eos_reached) override {
+    *frames_in_buffer = *offset_in_frames = 0;
+    *is_playing = true;
+    *is_eos_reached = false;
+  }
+  void ConsumeFrames(int frames_consumed, SbTime frames_consumed_at) override {
+    SB_DCHECK(frames_consumed == 0);
+  }
+
+  void OnError(bool capability_changed) override {
+    error_occurred_.store(true);
+  }
+
+  atomic_bool error_occurred_;
+};
+
 class PlayerComponentsFactory : public starboard::shared::starboard::player::
                                     filter::PlayerComponents::Factory {
   typedef starboard::shared::opus::OpusAudioDecoder OpusAudioDecoder;
@@ -80,6 +155,20 @@
       std::string* error_message) override {
     SB_DCHECK(error_message);
 
+    int tunnel_mode_audio_session_id = -1;
+
+    if (IsTunnelModeSupported(creation_parameters)) {
+      tunnel_mode_audio_session_id =
+          GenerateAudioSessionId(creation_parameters);
+    }
+
+    if (tunnel_mode_audio_session_id == -1) {
+      SB_LOG(INFO) << "Create non-tunnel mode pipeline.";
+    } else {
+      SB_LOG(INFO) << "Create tunnel mode pipeline with audio session id "
+                   << tunnel_mode_audio_session_id << '.';
+    }
+
     if (creation_parameters.audio_codec() != kSbMediaAudioCodecNone) {
       SB_DCHECK(audio_decoder);
       SB_DCHECK(audio_renderer_sink);
@@ -108,7 +197,16 @@
           creation_parameters.audio_sample_info(),
           GetExtendedDrmSystem(creation_parameters.drm_system()),
           decoder_creator));
-      audio_renderer_sink->reset(new AudioRendererSinkImpl);
+      if (tunnel_mode_audio_session_id != -1) {
+        *audio_renderer_sink = CreateTunnelModeAudioRendererSink(
+            tunnel_mode_audio_session_id, creation_parameters);
+        if (!*audio_renderer_sink) {
+          tunnel_mode_audio_session_id = -1;
+        }
+      }
+      if (!*audio_renderer_sink) {
+        audio_renderer_sink->reset(new AudioRendererSinkImpl());
+      }
     }
 
     if (creation_parameters.video_codec() != kSbMediaVideoCodecNone) {
@@ -122,10 +220,10 @@
           GetExtendedDrmSystem(creation_parameters.drm_system()),
           creation_parameters.output_mode(),
           creation_parameters.decode_target_graphics_context_provider(),
-          creation_parameters.max_video_capabilities(), error_message));
+          creation_parameters.max_video_capabilities(),
+          tunnel_mode_audio_session_id, error_message));
       if (video_decoder_impl->is_valid()) {
-        video_render_algorithm->reset(
-            new VideoRenderAlgorithm(video_decoder_impl.get()));
+        *video_render_algorithm = video_decoder_impl->GetRenderAlgorithm();
         *video_renderer_sink = video_decoder_impl->GetSink();
         video_decoder->reset(video_decoder_impl.release());
       } else {
@@ -164,6 +262,117 @@
         min_frames_required * 2 + kDefaultAudioSinkMinFramesPerAppend;
     *max_cached_frames = AlignUp(*max_cached_frames, kAudioSinkFramesAlignment);
   }
+
+  bool IsTunnelModeSupported(const CreationParameters& creation_parameters) {
+    if (!kTunnelModeEnabled) {
+      SB_LOG(INFO) << "Tunnel mode is disabled globally.";
+      return false;
+    }
+
+    if (!SbAudioSinkIsAudioSampleTypeSupported(
+            kSbMediaAudioSampleTypeInt16Deprecated)) {
+      SB_LOG(INFO) << "Disable tunnel mode because int16 sample is required "
+                      "but not supported.";
+      return false;
+    }
+
+    if (creation_parameters.output_mode() != kSbPlayerOutputModePunchOut) {
+      SB_LOG(INFO)
+          << "Disable tunnel mode because output mode is not punchout.";
+      return false;
+    }
+
+    if (creation_parameters.audio_codec() == kSbMediaAudioCodecNone) {
+      SB_LOG(INFO) << "Disable tunnel mode because audio codec is none.";
+      return false;
+    }
+
+    if (creation_parameters.video_codec() == kSbMediaVideoCodecNone) {
+      SB_LOG(INFO) << "Disable tunnel mode because video codec is none.";
+      return false;
+    }
+
+    const char* mime =
+        SupportedVideoCodecToMimeType(creation_parameters.video_codec());
+    if (!mime) {
+      SB_LOG(INFO) << "Disable tunnel mode because "
+                   << creation_parameters.video_codec() << " is not supported.";
+      return false;
+    }
+    JniEnvExt* env = JniEnvExt::Get();
+    ScopedLocalJavaRef<jstring> j_mime(env->NewStringStandardUTFOrAbort(mime));
+    DrmSystem* drm_system_ptr =
+        static_cast<DrmSystem*>(creation_parameters.drm_system());
+    jobject j_media_crypto =
+        drm_system_ptr ? drm_system_ptr->GetMediaCrypto() : NULL;
+
+    if (env->CallStaticBooleanMethodOrAbort(
+            "dev/cobalt/media/MediaCodecUtil", "hasTunneledCapableDecoder",
+            "(Ljava/lang/String;Z)Z", j_mime.Get(),
+            !!j_media_crypto) == JNI_TRUE) {
+      return true;
+    }
+
+    SB_LOG(INFO) << "Disable tunnel mode because no tunneled decoder for "
+                 << mime << '.';
+    return false;
+  }
+
+  int GenerateAudioSessionId(const CreationParameters& creation_parameters) {
+    SB_DCHECK(IsTunnelModeSupported(creation_parameters));
+
+    JniEnvExt* env = JniEnvExt::Get();
+    ScopedLocalJavaRef<jobject> j_audio_output_manager(
+        env->CallStarboardObjectMethodOrAbort(
+            "getAudioOutputManager",
+            "()Ldev/cobalt/media/AudioOutputManager;"));
+    int tunnel_mode_audio_session_id = env->CallIntMethodOrAbort(
+        j_audio_output_manager.Get(), "generateTunnelModeAudioSessionId",
+        "(I)I", creation_parameters.audio_sample_info().number_of_channels);
+
+    // AudioManager.generateAudioSessionId() return ERROR (-1) to indicate a
+    // failure, please see the following url for more details:
+    // https://developer.android.com/reference/android/media/AudioManager#generateAudioSessionId()
+    SB_LOG_IF(WARNING, tunnel_mode_audio_session_id == -1)
+        << "Failed to generate audio session id for tunnel mode.";
+
+    return tunnel_mode_audio_session_id;
+  }
+
+  scoped_ptr<AudioRendererSink> CreateTunnelModeAudioRendererSink(
+      int tunnel_mode_audio_session_id,
+      const CreationParameters& creation_parameters) {
+    scoped_ptr<AudioRendererSink> audio_sink(
+        new AudioRendererSinkTunneled(tunnel_mode_audio_session_id));
+    // We need to double check if the audio sink can actually be created.
+    int max_cached_frames, min_frames_per_append;
+    GetAudioRendererParams(creation_parameters, &max_cached_frames,
+                           &min_frames_per_append);
+    AudioRendererSinkCallbackStub callback_stub;
+    std::vector<uint16_t> frame_buffer(
+        max_cached_frames *
+        creation_parameters.audio_sample_info().number_of_channels);
+    uint16_t* frame_buffers[] = {frame_buffer.data()};
+    audio_sink->Start(
+        0, creation_parameters.audio_sample_info().number_of_channels,
+        creation_parameters.audio_sample_info().samples_per_second,
+        kSbMediaAudioSampleTypeInt16Deprecated,
+        kSbMediaAudioFrameStorageTypeInterleaved,
+        reinterpret_cast<SbAudioSinkFrameBuffers>(frame_buffers),
+        max_cached_frames, &callback_stub);
+    if (audio_sink->HasStarted() && !callback_stub.error_occurred()) {
+      audio_sink->Stop();
+      return audio_sink.Pass();
+    }
+    SB_LOG(WARNING)
+        << "AudioTrack does not support tunnel mode with sample rate:"
+        << creation_parameters.audio_sample_info().samples_per_second
+        << ", channels:"
+        << creation_parameters.audio_sample_info().number_of_channels
+        << ", audio format:" << creation_parameters.audio_codec()
+        << ", and audio buffer frames:" << max_cached_frames;
+    return scoped_ptr<AudioRendererSink>();
+  }
 };
 
 }  // namespace shared
diff --git a/src/starboard/android/shared/starboard_platform.gypi b/src/starboard/android/shared/starboard_platform.gypi
index d38907b..cd25fc8 100644
--- a/src/starboard/android/shared/starboard_platform.gypi
+++ b/src/starboard/android/shared/starboard_platform.gypi
@@ -48,7 +48,11 @@
       'include_dirs': [
         '<(DEPTH)/starboard/android/shared/bionic',
       ],
+      'includes': [
+        '<(DEPTH)/starboard/shared/starboard/player/common_player_sources.gypi',
+      ],
       'sources': [
+        '<@(common_player_sources)',
         '<@(filter_based_player_sources)',
         'accessibility_get_caption_settings.cc',
         'accessibility_get_display_settings.cc',
@@ -346,7 +350,7 @@
         '<(DEPTH)/starboard/shared/signal/suspend_signals.cc',
         '<(DEPTH)/starboard/shared/signal/suspend_signals.h',
         '<(DEPTH)/starboard/shared/signal/system_request_conceal.cc',
-        '<(DEPTH)/starboard/shared/signal/system_request_freeze.cc',
+        '<(DEPTH)/starboard/shared/signal/system_request_freeze_no_freezedone_callback.cc',
         '<(DEPTH)/starboard/shared/starboard/application.cc',
         '<(DEPTH)/starboard/shared/starboard/application.h',
         '<(DEPTH)/starboard/shared/starboard/audio_sink/audio_sink_create.cc',
@@ -404,25 +408,6 @@
         '<(DEPTH)/starboard/shared/starboard/microphone/microphone_read.cc',
         '<(DEPTH)/starboard/shared/starboard/memory.cc',
         '<(DEPTH)/starboard/shared/starboard/new.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/job_queue.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/job_queue.h',
-        '<(DEPTH)/starboard/shared/starboard/player/job_thread.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/job_thread.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_current_frame.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_worker.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_write_end_of_stream.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_write_sample2.cc',
         '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
         '<(DEPTH)/starboard/shared/starboard/queue_application.h',
         '<(DEPTH)/starboard/shared/starboard/speech_recognizer/speech_recognizer_cancel.cc',
@@ -468,6 +453,14 @@
         '<(DEPTH)/starboard/shared/stub/thread_sampler_thaw.cc',
         '<(DEPTH)/starboard/shared/stub/ui_nav_get_interface.cc',
       ],
+      'sources!': [
+        # Exclude these files from common_player_sources, because they are not used by android
+        '<(DEPTH)/starboard/shared/starboard/player/player_create.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_destroy.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
+        '<(DEPTH)/starboard/shared/starboard/player/player_set_playback_rate.cc',
+      ],
       'defines': [
         # This must be defined when building Starboard, and must not when
         # building Starboard client code.
diff --git a/src/starboard/android/shared/video_decoder.cc b/src/starboard/android/shared/video_decoder.cc
index 96a490a..1c952e2 100644
--- a/src/starboard/android/shared/video_decoder.cc
+++ b/src/starboard/android/shared/video_decoder.cc
@@ -18,6 +18,8 @@
 
 #include <cmath>
 #include <functional>
+#include <list>
+#include <vector>
 
 #include "starboard/android/shared/application_android.h"
 #include "starboard/android/shared/decode_target_create.h"
@@ -25,6 +27,7 @@
 #include "starboard/android/shared/jni_env_ext.h"
 #include "starboard/android/shared/jni_utils.h"
 #include "starboard/android/shared/media_common.h"
+#include "starboard/android/shared/video_render_algorithm.h"
 #include "starboard/android/shared/window_internal.h"
 #include "starboard/common/string.h"
 #include "starboard/configuration.h"
@@ -32,6 +35,7 @@
 #include "starboard/drm.h"
 #include "starboard/memory.h"
 #include "starboard/shared/starboard/player/filter/video_frame_internal.h"
+#include "starboard/shared/starboard/thread_checker.h"
 #include "starboard/string.h"
 #include "starboard/thread.h"
 
@@ -42,6 +46,8 @@
 namespace {
 
 using ::starboard::shared::starboard::player::filter::VideoFrame;
+using VideoRenderAlgorithmBase =
+    ::starboard::shared::starboard::player::filter::VideoRenderAlgorithm;
 using std::placeholders::_1;
 using std::placeholders::_2;
 
@@ -80,10 +86,13 @@
 };
 
 const SbTime kInitialPrerollTimeout = 250 * kSbTimeMillisecond;
+const SbTime kNeedMoreInputCheckIntervalInTunnelMode = 50 * kSbTimeMillisecond;
 
 const int kInitialPrerollFrameCount = 8;
 const int kNonInitialPrerollFrameCount = 1;
 
+const int kSeekingPrerollPendingWorkSizeInTunnelMode =
+    16 + kInitialPrerollFrameCount;
 const int kMaxPendingWorkSize = 128;
 
 // Convenience HDR mastering metadata.
@@ -114,6 +123,146 @@
 
 }  // namespace
 
+// TODO: Move into a separate file and write unit tests for it.
+class VideoFrameTracker {
+ public:
+  SbTime seek_to_time() const { return seek_to_time_; }
+
+  void OnInputBuffer(SbTime timestamp) {
+    SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+    if (frames_to_be_rendered_.empty()) {
+      frames_to_be_rendered_.push_back(timestamp);
+      return;
+    }
+
+    if (frames_to_be_rendered_.size() > kMaxPendingWorkSize * 2) {
+      // OnFrameRendered() is only available after API level 23.  Cap the size
+      // of |frames_to_be_rendered_| in case OnFrameRendered() is not available.
+      frames_to_be_rendered_.pop_front();
+    }
+
+    // Sort by |timestamp|, because |timestamp| won't be monotonic if there are
+    // B frames.
+    for (auto it = frames_to_be_rendered_.end();
+         it != frames_to_be_rendered_.begin();) {
+      it--;
+      if (*it < timestamp) {
+        frames_to_be_rendered_.emplace(++it, timestamp);
+        return;
+      } else if (*it == timestamp) {
+        SB_LOG(WARNING) << "feed video AU with same time stamp " << timestamp;
+        return;
+      }
+    }
+
+    frames_to_be_rendered_.emplace_front(timestamp);
+  }
+
+  void OnFrameRendered(int64_t frame_timestamp) {
+    ScopedLock lock(rendered_frames_mutex_);
+    rendered_frames_on_decoder_thread_.push_back(frame_timestamp);
+  }
+
+  void Seek(SbTime seek_to_time) {
+    SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+    // Ensure that all dropped frames before seeking are captured.
+    UpdateDroppedFrames();
+
+    frames_to_be_rendered_.clear();
+    seek_to_time_ = seek_to_time;
+  }
+
+  int UpdateAndGetDroppedFrames() {
+    SB_DCHECK(thread_checker_.CalledOnValidThread());
+    UpdateDroppedFrames();
+    return dropped_frames_;
+  }
+
+ private:
+  // TODO:
+  // * It is possible that the initial frame rendered time is before the seek to
+  //   time, when the platform decides to render a frame earlier than the seek
+  //   to time during preroll. This shouldn't be an issue after we align seek
+  //   time to the next video key frame.
+  // * The reported frame rendering time is the real time the frame is rendered.
+  //   It can be slightly different than the timestamp associated with the
+  //   InputBuffer.  For example, the frame with timestamp 120000 may be
+  //   rendered at 120020.  We have to account for this difference, as otherwise
+  //   lots of frames will be reported as being dropped.
+  void UpdateDroppedFrames() {
+    SB_DCHECK(thread_checker_.CalledOnValidThread());
+
+    {
+      ScopedLock lock(rendered_frames_mutex_);
+      rendered_frames_on_tracker_thread_.swap(
+          rendered_frames_on_decoder_thread_);
+    }
+
+    // TODO: Refine the algorithm, and consider using std::set<> for
+    //       |frames_to_be_rendered_|.
+    for (auto timestamp : rendered_frames_on_tracker_thread_) {
+      auto it = frames_to_be_rendered_.begin();
+      while (it != frames_to_be_rendered_.end()) {
+        if (*it > timestamp) {
+          break;
+        }
+
+        if (*it < seek_to_time_) {
+          it = frames_to_be_rendered_.erase(it);
+        } else if (*it < timestamp) {
+          SB_LOG(WARNING) << "Video frame dropped:" << *it
+                          << ", current frame timestamp:" << timestamp
+                          << ", frames in the backlog:"
+                          << frames_to_be_rendered_.size();
+          ++dropped_frames_;
+          it = frames_to_be_rendered_.erase(it);
+        } else if (*it == timestamp) {
+          it = frames_to_be_rendered_.erase(it);
+        } else {
+          ++it;
+        }
+      }
+    }
+
+    rendered_frames_on_tracker_thread_.clear();
+  }
+
+  ::starboard::shared::starboard::ThreadChecker thread_checker_;
+
+  std::list<SbTime> frames_to_be_rendered_;
+
+  int dropped_frames_ = 0;
+  SbTime seek_to_time_ = 0;
+
+  std::vector<SbTime> rendered_frames_on_tracker_thread_;
+  Mutex rendered_frames_mutex_;
+  std::vector<SbTime> rendered_frames_on_decoder_thread_;
+};
+
+// TODO: Merge this with VideoFrameTracker
+class VideoRenderAlgorithmTunneled : public VideoRenderAlgorithmBase {
+ public:
+  explicit VideoRenderAlgorithmTunneled(VideoFrameTracker* frame_tracker)
+      : frame_tracker_(frame_tracker) {
+    SB_DCHECK(frame_tracker_);
+  }
+
+  void Render(MediaTimeProvider* media_time_provider,
+              std::list<scoped_refptr<VideoFrame>>* frames,
+              VideoRendererSink::DrawFrameCB draw_frame_cb) override {}
+  void Seek(SbTime seek_to_time) override {
+    frame_tracker_->Seek(seek_to_time);
+  }
+  int GetDroppedFrames() override {
+    return frame_tracker_->UpdateAndGetDroppedFrames();
+  }
+
+ private:
+  VideoFrameTracker* frame_tracker_;
+};
+
 int VideoDecoder::number_of_hardware_decoders_ = 0;
 
 class VideoDecoder::Sink : public VideoDecoder::VideoRendererSink {
@@ -135,8 +284,7 @@
     render_cb_ = render_cb;
   }
 
-  void SetBounds(int z_index, int x, int y, int width, int height) override {
-  }
+  void SetBounds(int z_index, int x, int y, int width, int height) override {}
 
   DrawFrameStatus DrawFrame(const scoped_refptr<VideoFrame>& frame,
                             int64_t release_time_in_nanoseconds) {
@@ -157,18 +305,24 @@
                            SbDecodeTargetGraphicsContextProvider*
                                decode_target_graphics_context_provider,
                            const char* max_video_capabilities,
+                           int tunnel_mode_audio_session_id,
                            std::string* error_message)
     : video_codec_(video_codec),
       drm_system_(static_cast<DrmSystem*>(drm_system)),
       output_mode_(output_mode),
       decode_target_graphics_context_provider_(
           decode_target_graphics_context_provider),
+      tunnel_mode_audio_session_id_(tunnel_mode_audio_session_id),
       has_new_texture_available_(false),
       surface_condition_variable_(surface_destroy_mutex_),
       require_software_codec_(max_video_capabilities &&
                               SbStringGetLength(max_video_capabilities) > 0) {
   SB_DCHECK(error_message);
 
+  if (tunnel_mode_audio_session_id != -1) {
+    video_frame_tracker_.reset(new VideoFrameTracker);
+  }
+
   if (require_software_codec_) {
     SB_DCHECK(output_mode_ == kSbPlayerOutputModeDecodeToTexture);
   }
@@ -200,10 +354,20 @@
   return sink_;
 }
 
+scoped_ptr<VideoDecoder::VideoRenderAlgorithm>
+VideoDecoder::GetRenderAlgorithm() {
+  if (tunnel_mode_audio_session_id_ == -1) {
+    return scoped_ptr<VideoRenderAlgorithm>(
+        new android::shared::VideoRenderAlgorithm(this));
+  }
+  return scoped_ptr<VideoRenderAlgorithm>(
+      new VideoRenderAlgorithmTunneled(video_frame_tracker_.get()));
+}
+
 void VideoDecoder::Initialize(const DecoderStatusCB& decoder_status_cb,
                               const ErrorCB& error_cb) {
+  SB_DCHECK(BelongsToCurrentThread());
   SB_DCHECK(media_decoder_);
-
   SB_DCHECK(decoder_status_cb);
   SB_DCHECK(!decoder_status_cb_);
   SB_DCHECK(error_cb);
@@ -216,14 +380,18 @@
 }
 
 size_t VideoDecoder::GetPrerollFrameCount() const {
-  if (first_buffer_received_ && first_buffer_timestamp_ != 0) {
+  // Tunnel mode uses its own preroll logic.
+  if (tunnel_mode_audio_session_id_ != -1) {
+    return 0;
+  }
+  if (input_buffer_written_ > 0 && first_buffer_timestamp_ != 0) {
     return kNonInitialPrerollFrameCount;
   }
   return kInitialPrerollFrameCount;
 }
 
 SbTime VideoDecoder::GetPrerollTimeout() const {
-  if (first_buffer_received_ && first_buffer_timestamp_ != 0) {
+  if (input_buffer_written_ > 0 && first_buffer_timestamp_ != 0) {
     return kSbTimeMax;
   }
   return kInitialPrerollTimeout;
@@ -231,12 +399,12 @@
 
 void VideoDecoder::WriteInputBuffer(
     const scoped_refptr<InputBuffer>& input_buffer) {
+  SB_DCHECK(BelongsToCurrentThread());
   SB_DCHECK(input_buffer);
   SB_DCHECK(input_buffer->sample_type() == kSbMediaTypeVideo);
   SB_DCHECK(decoder_status_cb_);
 
-  if (!first_buffer_received_) {
-    first_buffer_received_ = true;
+  if (input_buffer_written_ == 0) {
     first_buffer_timestamp_ = input_buffer->timestamp();
 
     // If color metadata is present and is not an identity mapping, then
@@ -262,8 +430,15 @@
         return;
       }
     }
+
+    if (tunnel_mode_audio_session_id_ != -1) {
+      Schedule(std::bind(&VideoDecoder::OnTunnelModePrerollTimeout, this),
+               kInitialPrerollTimeout);
+    }
   }
 
+  ++input_buffer_written_;
+
   // There's a race condition when suspending the app. If surface view is
   // destroyed before video decoder stopped, |media_decoder_| could be null
   // here. And error_cb_() could be handled asynchronously. It's possible
@@ -274,18 +449,69 @@
     return;
   }
   media_decoder_->WriteInputBuffer(input_buffer);
-  if (number_of_frames_being_decoded_.increment() < kMaxPendingWorkSize) {
+  if (media_decoder_->GetNumberOfPendingTasks() < kMaxPendingWorkSize) {
     decoder_status_cb_(kNeedMoreInput, NULL);
+  } else if (tunnel_mode_audio_session_id_ != -1) {
+    // In tunnel mode playback when need data is not signaled above, it is
+    // possible that the VideoDecoder won't get a chance to send kNeedMoreInput
+    // to the renderer again.  Schedule a task to check back.
+    Schedule(std::bind(&VideoDecoder::OnTunnelModeCheckForNeedMoreInput, this),
+             kNeedMoreInputCheckIntervalInTunnelMode);
+  }
+
+  if (tunnel_mode_audio_session_id_ != -1) {
+    video_frame_tracker_->OnInputBuffer(input_buffer->timestamp());
+
+    if (tunnel_mode_prerolling_.load()) {
+      // TODO: Refine preroll logic in tunnel mode.
+      bool enough_buffers_written_to_media_codec = false;
+      if (first_buffer_timestamp_ == 0) {
+        // Initial playback.
+        enough_buffers_written_to_media_codec =
+            (input_buffer_written_ -
+             media_decoder_->GetNumberOfPendingTasks()) >
+            kInitialPrerollFrameCount;
+      } else {
+        // Seeking.  Note that this branch can be eliminated once seeking in
+        // tunnel mode is always aligned to the next video key frame.
+        enough_buffers_written_to_media_codec =
+            (input_buffer_written_ -
+             media_decoder_->GetNumberOfPendingTasks()) >
+                kSeekingPrerollPendingWorkSizeInTunnelMode &&
+            input_buffer->timestamp() >= video_frame_tracker_->seek_to_time();
+      }
+
+      bool cache_full =
+          media_decoder_->GetNumberOfPendingTasks() >= kMaxPendingWorkSize;
+      bool prerolled = tunnel_mode_frame_rendered_.load() > 0 ||
+                       enough_buffers_written_to_media_codec || cache_full;
+
+      if (prerolled && tunnel_mode_prerolling_.exchange(false)) {
+        SB_LOG(INFO)
+            << "Tunnel mode preroll finished on enqueuing input buffer "
+            << input_buffer->timestamp() << ", for seek time "
+            << video_frame_tracker_->seek_to_time();
+        decoder_status_cb_(
+            kNeedMoreInput,
+            new VideoFrame(video_frame_tracker_->seek_to_time()));
+      }
+    }
   }
 }
 
 void VideoDecoder::WriteEndOfStream() {
+  SB_DCHECK(BelongsToCurrentThread());
   SB_DCHECK(decoder_status_cb_);
 
-  if (!first_buffer_received_) {
-    // In this case, |media_decoder_|'s decoder thread is not initialized.
-    // Return EOS frame directly.
-    first_buffer_received_ = true;
+  if (end_of_stream_written_) {
+    SB_LOG(WARNING) << "WriteEndOfStream() is called more than once.";
+    return;
+  }
+  end_of_stream_written_ = true;
+
+  if (input_buffer_written_ == 0) {
+    // In this case, |media_decoder_|'s decoder thread is not initialized,
+    // return EOS frame directly.
     first_buffer_timestamp_ = 0;
     decoder_status_cb_(kBufferFull, VideoFrame::CreateEOSFrame());
     return;
@@ -301,13 +527,25 @@
         << "Trying to write end of stream when codec is not available.";
     return;
   }
+
   media_decoder_->WriteEndOfStream();
 }
 
 void VideoDecoder::Reset() {
+  SB_DCHECK(BelongsToCurrentThread());
+
   TeardownCodec();
-  number_of_frames_being_decoded_.store(0);
-  first_buffer_received_ = false;
+  CancelPendingJobs();
+
+  tunnel_mode_prerolling_.store(true);
+  tunnel_mode_frame_rendered_.store(false);
+  input_buffer_written_ = 0;
+  end_of_stream_written_ = false;
+
+  // TODO: We rely on VideoRenderAlgorithmTunneled::Seek() to be called inside
+  //       VideoRenderer::Seek() after calling VideoDecoder::Reset() to update
+  //       the seek status of |video_frame_tracker_|.  This is slightly flaky as
+  //       it depends on the behavior of the video renderer.
 }
 
 bool VideoDecoder::InitializeCodec(std::string* error_message) {
@@ -345,7 +583,7 @@
       env->CallVoidMethodOrAbort(decode_target->data->surface_texture,
                                  "setOnFrameAvailableListener", "(J)V", this);
 
-      starboard::ScopedLock lock(decode_target_mutex_);
+      ScopedLock lock(decode_target_mutex_);
       decode_target_ = decode_target;
     } break;
     case kSbPlayerOutputModeInvalid: {
@@ -371,7 +609,8 @@
   media_decoder_.reset(new MediaDecoder(
       this, video_codec_, width, height, j_output_surface, drm_system_,
       color_metadata_ ? &*color_metadata_ : nullptr, require_software_codec_,
-      error_message));
+      std::bind(&VideoDecoder::OnTunnelModeFrameRendered, this, _1),
+      tunnel_mode_audio_session_id_, error_message));
   if (media_decoder_->is_valid()) {
     if (error_cb_) {
       media_decoder_->Initialize(
@@ -395,7 +634,7 @@
 
   SbDecodeTarget decode_target_to_release = kSbDecodeTargetInvalid;
   {
-    starboard::ScopedLock lock(decode_target_mutex_);
+    ScopedLock lock(decode_target_mutex_);
     if (SbDecodeTargetIsValid(decode_target_)) {
       // Remove OnFrameAvailableListener to make sure the callback
       // would not be called.
@@ -424,13 +663,27 @@
   }
 }
 
+void VideoDecoder::OnEndOfStreamWritten(MediaCodecBridge* media_codec_bridge) {
+  if (tunnel_mode_audio_session_id_ == -1) {
+    return;
+  }
+
+  SB_DCHECK(decoder_status_cb_);
+
+  tunnel_mode_prerolling_.store(false);
+
+  // TODO: Refactor the VideoDecoder and the VideoRendererImpl to improve the
+  //       handling of preroll and EOS for pure punchout decoders.
+  decoder_status_cb_(kBufferFull, VideoFrame::CreateEOSFrame());
+  sink_->Render();
+}
+
 void VideoDecoder::ProcessOutputBuffer(
     MediaCodecBridge* media_codec_bridge,
     const DequeueOutputResult& dequeue_output_result) {
   SB_DCHECK(decoder_status_cb_);
   SB_DCHECK(dequeue_output_result.index >= 0);
 
-  number_of_frames_being_decoded_.decrement();
   bool is_end_of_stream =
       dequeue_output_result.flags & BUFFER_FLAG_END_OF_STREAM;
   decoder_status_cb_(
@@ -441,7 +694,8 @@
 void VideoDecoder::RefreshOutputFormat(MediaCodecBridge* media_codec_bridge) {
   SB_DCHECK(media_codec_bridge);
   SB_DLOG(INFO) << "Output format changed, trying to dequeue again.";
-  starboard::ScopedLock lock(decode_target_mutex_);
+
+  ScopedLock lock(decode_target_mutex_);
   // Record the latest width/height of the decoded input.
   SurfaceDimensions output_dimensions =
       media_codec_bridge->GetOutputDimensions();
@@ -450,6 +704,9 @@
 }
 
 bool VideoDecoder::Tick(MediaCodecBridge* media_codec_bridge) {
+  // Tunnel mode renders frames in MediaCodec automatically and shouldn't reach
+  // here.
+  SB_DCHECK(tunnel_mode_audio_session_id_ == -1);
   return sink_->Render();
 }
 
@@ -547,7 +804,7 @@
   SB_DCHECK(output_mode_ == kSbPlayerOutputModeDecodeToTexture);
   // We must take a lock here since this function can be called from a separate
   // thread.
-  starboard::ScopedLock lock(decode_target_mutex_);
+  ScopedLock lock(decode_target_mutex_);
   if (SbDecodeTargetIsValid(decode_target_)) {
     bool has_new_texture = has_new_texture_available_.exchange(false);
     if (has_new_texture) {
@@ -589,6 +846,41 @@
   has_new_texture_available_.store(true);
 }
 
+void VideoDecoder::OnTunnelModeFrameRendered(SbTime frame_timestamp) {
+  SB_DCHECK(tunnel_mode_audio_session_id_ != -1);
+
+  tunnel_mode_frame_rendered_.store(true);
+  video_frame_tracker_->OnFrameRendered(frame_timestamp);
+}
+
+void VideoDecoder::OnTunnelModePrerollTimeout() {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(tunnel_mode_audio_session_id_ != -1);
+
+  if (tunnel_mode_prerolling_.exchange(false)) {
+    SB_LOG(INFO) << "Tunnel mode preroll finished due to timeout.";
+    // TODO: Currently the decoder sends a dummy frame to the renderer to signal
+    //       preroll finish.  We should investigate a better way for prerolling
+    //       when the video is rendered directly by the decoder, maybe by always
+    //       sending placeholder frames.
+    decoder_status_cb_(kNeedMoreInput,
+                       new VideoFrame(video_frame_tracker_->seek_to_time()));
+  }
+}
+
+void VideoDecoder::OnTunnelModeCheckForNeedMoreInput() {
+  SB_DCHECK(BelongsToCurrentThread());
+  SB_DCHECK(tunnel_mode_audio_session_id_ != -1);
+
+  if (media_decoder_->GetNumberOfPendingTasks() < kMaxPendingWorkSize) {
+    decoder_status_cb_(kNeedMoreInput, NULL);
+    return;
+  }
+
+  Schedule(std::bind(&VideoDecoder::OnTunnelModeCheckForNeedMoreInput, this),
+           kNeedMoreInputCheckIntervalInTunnelMode);
+}
+
 void VideoDecoder::OnSurfaceDestroyed() {
   if (!BelongsToCurrentThread()) {
     // Wait until codec is stoped.
diff --git a/src/starboard/android/shared/video_decoder.h b/src/starboard/android/shared/video_decoder.h
index 508817f..2b5366b 100644
--- a/src/starboard/android/shared/video_decoder.h
+++ b/src/starboard/android/shared/video_decoder.h
@@ -32,6 +32,7 @@
 #include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
 #include "starboard/shared/starboard/player/filter/video_decoder_internal.h"
+#include "starboard/shared/starboard/player/filter/video_render_algorithm.h"
 #include "starboard/shared/starboard/player/filter/video_renderer_sink.h"
 #include "starboard/shared/starboard/player/input_buffer_internal.h"
 #include "starboard/shared/starboard/player/job_queue.h"
@@ -40,12 +41,16 @@
 namespace android {
 namespace shared {
 
+class VideoFrameTracker;
+
 class VideoDecoder
     : public ::starboard::shared::starboard::player::filter::VideoDecoder,
       private MediaDecoder::Host,
       private ::starboard::shared::starboard::player::JobQueue::JobOwner,
       private VideoSurfaceHolder {
  public:
+  typedef ::starboard::shared::starboard::player::filter::VideoRenderAlgorithm
+      VideoRenderAlgorithm;
   typedef ::starboard::shared::starboard::player::filter::VideoRendererSink
       VideoRendererSink;
 
@@ -61,10 +66,12 @@
                SbDecodeTargetGraphicsContextProvider*
                    decode_target_graphics_context_provider,
                const char* max_video_capabilities,
+               int tunnel_mode_audio_session_id,
                std::string* error_message);
   ~VideoDecoder() override;
 
   scoped_refptr<VideoRendererSink> GetSink();
+  scoped_ptr<VideoRenderAlgorithm> GetRenderAlgorithm();
 
   void Initialize(const DecoderStatusCB& decoder_status_cb,
                   const ErrorCB& error_cb) override;
@@ -77,8 +84,8 @@
   // buffer.
   size_t GetMaxNumberOfCachedFrames() const override { return 12; }
 
-  void WriteInputBuffer(const scoped_refptr<InputBuffer>& input_buffer)
-      override;
+  void WriteInputBuffer(
+      const scoped_refptr<InputBuffer>& input_buffer) override;
   void WriteEndOfStream() override;
   void Reset() override;
   SbDecodeTarget GetCurrentDecodeTarget() override;
@@ -97,10 +104,16 @@
 
   void ProcessOutputBuffer(MediaCodecBridge* media_codec_bridge,
                            const DequeueOutputResult& output) override;
+  void OnEndOfStreamWritten(MediaCodecBridge* media_codec_bridge);
   void RefreshOutputFormat(MediaCodecBridge* media_codec_bridge) override;
   bool Tick(MediaCodecBridge* media_codec_bridge) override;
   void OnFlushing() override;
 
+  void TryToSignalPrerollForTunnelMode();
+  void OnTunnelModeFrameRendered(SbTime frame_timestamp);
+  void OnTunnelModePrerollTimeout();
+  void OnTunnelModeCheckForNeedMoreInput();
+
   void OnSurfaceDestroyed() override;
   void ReportError(SbPlayerError error, const std::string& error_message);
 
@@ -121,6 +134,12 @@
   // the main player and SW decoder for sub players.
   const bool require_software_codec_;
 
+  const int tunnel_mode_audio_session_id_ = -1;
+  scoped_ptr<VideoFrameTracker> video_frame_tracker_;
+  // Preroll in tunnel mode is handled in this class instead of in the renderer.
+  atomic_bool tunnel_mode_prerolling_{true};
+  atomic_bool tunnel_mode_frame_rendered_;
+
   // If decode-to-texture is enabled, then we store the decode target texture
   // inside of this |decode_target_| member.
   SbDecodeTarget decode_target_ = kSbDecodeTargetInvalid;
@@ -129,7 +148,7 @@
   // to obtain the current decode target (which ultimately ends up being a
   // copy of |decode_target_|), we need to safe-guard access to |decode_target_|
   // and we do so through this mutex.
-  starboard::Mutex decode_target_mutex_;
+  Mutex decode_target_mutex_;
 
   // The width and height of the latest decoded frame.
   int32_t frame_width_ = 0;
@@ -145,8 +164,9 @@
   atomic_int32_t number_of_frames_being_decoded_;
   scoped_refptr<Sink> sink_;
 
-  bool first_buffer_received_ = false;
+  int input_buffer_written_ = 0;
   bool first_texture_received_ = false;
+  bool end_of_stream_written_ = false;
   volatile SbTime first_buffer_timestamp_;
   atomic_bool has_new_texture_available_;
 
@@ -154,8 +174,8 @@
   // invocation of ReleaseVideoSurface(), though ReleaseVideoSurface() would
   // do nothing if not own the surface.
   bool owns_video_surface_ = false;
-  starboard::Mutex surface_destroy_mutex_;
-  starboard::ConditionVariable surface_condition_variable_;
+  Mutex surface_destroy_mutex_;
+  ConditionVariable surface_condition_variable_;
 };
 
 }  // namespace shared
diff --git a/src/starboard/android/shared/video_frame_release_time_adjuster.cc b/src/starboard/android/shared/video_frame_release_time_adjuster.cc
deleted file mode 100644
index 30f4b07..0000000
--- a/src/starboard/android/shared/video_frame_release_time_adjuster.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2018 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/video_frame_release_time_adjuster.h"
-
-namespace starboard {
-namespace android {
-namespace shared {
-
-VideoFrameReleaseTimeHelper::VideoFrameReleaseTimeHelper() {
-  this(DISPLAY_REFRESH_RATE_UNKNOWN);
-}
-
-VideoFrameReleaseTimeHelper::VideoFrameReleaseTimeHelper(Context context) {
-  this(getDefaultDisplayRefreshRate(context));
-}
-
-VideoFrameReleaseTimeHelper::VideoFrameReleaseTimeHelper(
-    double defaultDisplayRefreshRate) {
-  useDefaultDisplayVsync =
-      defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN;
-  if (useDefaultDisplayVsync) {
-    vsyncSampler = VSyncSampler.getInstance();
-    vsyncDurationNs = (long)(NANOS_PER_SECOND / defaultDisplayRefreshRate);
-    vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100;
-  } else {
-    vsyncSampler = null;
-    vsyncDurationNs = -1;  // Value unused.
-    vsyncOffsetNs = -1;    // Value unused.
-  }
-}
-
-void VideoFrameReleaseTimeHelper::enable() {
-  haveSync = false;
-  if (useDefaultDisplayVsync) {
-    vsyncSampler.addObserver();
-  }
-}
-
-void VideoFrameReleaseTimeHelper::disable() {
-  if (useDefaultDisplayVsync) {
-    vsyncSampler.removeObserver();
-  }
-}
-
-long VideoFrameReleaseTimeHelper::adjustReleaseTime(
-    long framePresentationTimeUs,
-    long unadjustedReleaseTimeNs) {
-  long framePresentationTimeNs = framePresentationTimeUs * 1000;
-
-  // Until we know better, the adjustment will be a no-op.
-  long adjustedFrameTimeNs = framePresentationTimeNs;
-  long adjustedReleaseTimeNs = unadjustedReleaseTimeNs;
-
-  if (haveSync) {
-    // See if we've advanced to the next frame.
-    if (framePresentationTimeUs != lastFramePresentationTimeUs) {
-      frameCount++;
-      adjustedLastFrameTimeNs = pendingAdjustedFrameTimeNs;
-    }
-    if (frameCount >= MIN_FRAMES_FOR_ADJUSTMENT) {
-      // We're synced and have waited the required number of frames to apply an
-      // adjustment. Calculate the average frame time across all the frames
-      // we've seen since the last sync. This will typically give us a frame
-      // rate at a finer granularity than the frame times themselves (which
-      // often only have millisecond granularity).
-      long averageFrameDurationNs =
-          (framePresentationTimeNs - syncFramePresentationTimeNs) / frameCount;
-      // Project the adjusted frame time forward using the average.
-      long candidateAdjustedFrameTimeNs =
-          adjustedLastFrameTimeNs + averageFrameDurationNs;
-
-      if (isDriftTooLarge(candidateAdjustedFrameTimeNs,
-                          unadjustedReleaseTimeNs)) {
-        haveSync = false;
-      } else {
-        adjustedFrameTimeNs = candidateAdjustedFrameTimeNs;
-        adjustedReleaseTimeNs = syncUnadjustedReleaseTimeNs +
-                                adjustedFrameTimeNs -
-                                syncFramePresentationTimeNs;
-      }
-    } else {
-      // We're synced but haven't waited the required number of frames to apply
-      // an adjustment. Check drift anyway.
-      if (isDriftTooLarge(framePresentationTimeNs, unadjustedReleaseTimeNs)) {
-        haveSync = false;
-      }
-    }
-  }
-
-  // If we need to sync, do so now.
-  if (!haveSync) {
-    syncFramePresentationTimeNs = framePresentationTimeNs;
-    syncUnadjustedReleaseTimeNs = unadjustedReleaseTimeNs;
-    frameCount = 0;
-    haveSync = true;
-    onSynced();
-  }
-
-  lastFramePresentationTimeUs = framePresentationTimeUs;
-  pendingAdjustedFrameTimeNs = adjustedFrameTimeNs;
-
-  if (vsyncSampler == null || vsyncSampler.sampledVsyncTimeNs == 0) {
-    return adjustedReleaseTimeNs;
-  }
-
-  // Find the timestamp of the closest vsync. This is the vsync that we're
-  // targeting.
-  long snappedTimeNs = closestVsync(
-      adjustedReleaseTimeNs, vsyncSampler.sampledVsyncTimeNs, vsyncDurationNs);
-  // Apply an offset so that we release before the target vsync, but after the
-  // previous one.
-  return snappedTimeNs - vsyncOffsetNs;
-}
-
-void VideoFrameReleaseTimeHelper::onSynced() {
-  // Do nothing.
-}
-
-boolean VideoFrameReleaseTimeHelper::isDriftTooLarge(long frameTimeNs,
-                                                     long releaseTimeNs) {
-  long elapsedFrameTimeNs = frameTimeNs - syncFramePresentationTimeNs;
-  long elapsedReleaseTimeNs = releaseTimeNs - syncUnadjustedReleaseTimeNs;
-  return Math.abs(elapsedReleaseTimeNs - elapsedFrameTimeNs) >
-         MAX_ALLOWED_DRIFT_NS;
-}
-
-static long VideoFrameReleaseTimeHelper::closestVsync(long releaseTime,
-                                                      long sampledVsyncTime,
-                                                      long vsyncDuration) {
-  long vsyncCount = (releaseTime - sampledVsyncTime) / vsyncDuration;
-  long snappedTimeNs = sampledVsyncTime + (vsyncDuration * vsyncCount);
-  long snappedBeforeNs;
-  long snappedAfterNs;
-  if (releaseTime <= snappedTimeNs) {
-    snappedBeforeNs = snappedTimeNs - vsyncDuration;
-    snappedAfterNs = snappedTimeNs;
-  } else {
-    snappedBeforeNs = snappedTimeNs;
-    snappedAfterNs = snappedTimeNs + vsyncDuration;
-  }
-  long snappedAfterDiff = snappedAfterNs - releaseTime;
-  long snappedBeforeDiff = releaseTime - snappedBeforeNs;
-  return snappedAfterDiff < snappedBeforeDiff ? snappedAfterNs
-                                              : snappedBeforeNs;
-}
-
-static double VideoFrameReleaseTimeHelper::getDefaultDisplayRefreshRate(
-    Context context) {
-  WindowManager manager =
-      (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-  return manager.getDefaultDisplay() != null
-             ? manager.getDefaultDisplay().getRefreshRate()
-             : DISPLAY_REFRESH_RATE_UNKNOWN;
-}
-
-}  // namespace shared
-}  // namespace android
-}  // namespace starboard
diff --git a/src/starboard/android/shared/video_frame_release_time_adjuster.h b/src/starboard/android/shared/video_frame_release_time_adjuster.h
deleted file mode 100644
index a345660..0000000
--- a/src/starboard/android/shared/video_frame_release_time_adjuster.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2018 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_VIDEO_FRAME_RELEASE_TIME_ADJUSTER_H_
-#define STARBOARD_ANDROID_SHARED_VIDEO_FRAME_RELEASE_TIME_ADJUSTER_H_
-
-namespace starboard {
-namespace android {
-namespace shared {
-
-class VideoFrameReleaseTimeAdjuster {
- public:
-  /**
-   * Constructs an instance that smooths frame release timestamps but does not
-   * align them with the default display's vsync signal.
-   */
-  VideoFrameReleaseTimeHelper();
-
-  /**
-   * Constructs an instance that smooths frame release timestamps and aligns
-   * them with the default display's vsync signal.
-   *
-   * @param context A context from which information about the default display
-   * can be retrieved.
-   */
-  VideoFrameReleaseTimeHelper(Context context);
-
-  /** Enables the helper. */
-  void enable();
-
-  /** Disables the helper. */
-  void disable();
-
-  /**
-   * Adjusts a frame release timestamp.
-   *
-   * @param framePresentationTimeUs The frame's presentation time, in
-   * microseconds.
-   * @param unadjustedReleaseTimeNs The frame's unadjusted release time, in
-   * nanoseconds and in the same time base as {@link System#nanoTime()}.
-   * @return The adjusted frame release timestamp, in nanoseconds and in the
-   * same time base as
-   *     {@link System#nanoTime()}.
-   */
-  long adjustReleaseTime(long framePresentationTimeUs,
-                         long unadjustedReleaseTimeNs);
-
- protected:
-  void onSynced();
-
- private:
-  VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate);
-
-  boolean isDriftTooLarge(long frameTimeNs, long releaseTimeNs);
-
-  static long closestVsync(long releaseTime,
-                           long sampledVsyncTime,
-                           long vsyncDuration);
-
-  static double getDefaultDisplayRefreshRate(Context context);
-
-  /**
-   * Samples display vsync timestamps. A single instance using a single {@link
-   * Choreographer} is shared by all {@link VideoFrameReleaseTimeHelper}
-   * instances. This is done to avoid a resource leak in the platform on API
-   * levels prior to 23.
-   */
-  class VSyncSampler implements FrameCallback, Handler.Callback {
-   public:
-    static VSyncSampler getInstance() { return INSTANCE; }
-
-    VSyncSampler() {
-      choreographerOwnerThread =
-          new HandlerThread("ChoreographerOwner:Handler");
-      choreographerOwnerThread.start();
-      handler = new Handler(choreographerOwnerThread.getLooper(), this);
-      handler.sendEmptyMessage(CREATE_CHOREOGRAPHER);
-    }
-
-    /**
-     * Notifies the sampler that a {@link VideoFrameReleaseTimeHelper} is
-     * observing {@link #sampledVsyncTimeNs}, and hence that the value should be
-     * periodically updated.
-     */
-    void addObserver() { handler.sendEmptyMessage(MSG_ADD_OBSERVER); }
-
-    /**
-     * Notifies the sampler that a {@link VideoFrameReleaseTimeHelper} is no
-     * longer observing {@link #sampledVsyncTimeNs}.
-     */
-    void removeObserver() { handler.sendEmptyMessage(MSG_REMOVE_OBSERVER); }
-
-    void doFrame(long vsyncTimeNs) {
-      sampledVsyncTimeNs = vsyncTimeNs;
-      choreographer.postFrameCallbackDelayed(this,
-                                             CHOREOGRAPHER_SAMPLE_DELAY_MILLIS);
-    }
-
-    boolean handleMessage(Message message) {
-      switch (message.what) {
-        case CREATE_CHOREOGRAPHER: {
-          createChoreographerInstanceInternal();
-          return true;
-        }
-        case MSG_ADD_OBSERVER: {
-          addObserverInternal();
-          return true;
-        }
-        case MSG_REMOVE_OBSERVER: {
-          removeObserverInternal();
-          return true;
-        }
-        default: { return false; }
-      }
-    }
-
-    volatile long sampledVsyncTimeNs;
-
-   private:
-    void createChoreographerInstanceInternal() {
-      choreographer = Choreographer.getInstance();
-    }
-
-    void addObserverInternal() {
-      observerCount++;
-      if (observerCount == 1) {
-        choreographer.postFrameCallback(this);
-      }
-    }
-
-    void removeObserverInternal() {
-      observerCount--;
-      if (observerCount == 0) {
-        choreographer.removeFrameCallback(this);
-        sampledVsyncTimeNs = 0;
-      }
-    }
-
-    static final int CREATE_CHOREOGRAPHER = 0;
-    static final int MSG_ADD_OBSERVER = 1;
-    static final int MSG_REMOVE_OBSERVER = 2;
-
-    static final VSyncSampler INSTANCE = new VSyncSampler();
-
-    final Handler handler;
-    final HandlerThread choreographerOwnerThread;
-    Choreographer choreographer;
-    int observerCount;
-  };
-
-  static final double DISPLAY_REFRESH_RATE_UNKNOWN = -1;
-  static final long CHOREOGRAPHER_SAMPLE_DELAY_MILLIS = 500;
-  static final long MAX_ALLOWED_DRIFT_NS = 20000000;
-
-  static final long VSYNC_OFFSET_PERCENTAGE = 80;
-  static final int MIN_FRAMES_FOR_ADJUSTMENT = 6;
-  static final long NANOS_PER_SECOND = 1000000000L;
-
-  final VSyncSampler vsyncSampler;
-  final boolean useDefaultDisplayVsync;
-  final long vsyncDurationNs;
-  final long vsyncOffsetNs;
-
-  long lastFramePresentationTimeUs;
-  long adjustedLastFrameTimeNs;
-  long pendingAdjustedFrameTimeNs;
-
-  boolean haveSync;
-  long syncUnadjustedReleaseTimeNs;
-  long syncFramePresentationTimeNs;
-  long frameCount;
-};
-
-}  // namespace shared
-}  // namespace android
-}  // namespace starboard
-
-#endif  // STARBOARD_ANDROID_SHARED_VIDEO_FRAME_RELEASE_TIME_ADJUSTER_H_
diff --git a/src/starboard/android/shared/video_render_algorithm.cc b/src/starboard/android/shared/video_render_algorithm.cc
index b234937..1b9fcc4 100644
--- a/src/starboard/android/shared/video_render_algorithm.cc
+++ b/src/starboard/android/shared/video_render_algorithm.cc
@@ -102,11 +102,8 @@
 VideoRenderAlgorithm::VideoFrameReleaseTimeHelper::
     VideoFrameReleaseTimeHelper() {
   auto* env = JniEnvExt::Get();
-  ScopedLocalJavaRef<jobject> j_context(env->CallStarboardObjectMethodOrAbort(
-      "getApplicationContext", "()Landroid/content/Context;"));
-  j_video_frame_release_time_helper_ =
-      env->NewObjectOrAbort("dev/cobalt/media/VideoFrameReleaseTimeHelper",
-                            "(Landroid/content/Context;)V", j_context.Get());
+  j_video_frame_release_time_helper_ = env->NewObjectOrAbort(
+      "dev/cobalt/media/VideoFrameReleaseTimeHelper", "()V");
   j_video_frame_release_time_helper_ =
       env->ConvertLocalRefToGlobalRef(j_video_frame_release_time_helper_);
   env->CallVoidMethod(j_video_frame_release_time_helper_, "enable", "()V");
diff --git a/src/starboard/build/copy_data.py b/src/starboard/build/copy_data.py
index b43f75b..b0d88e3 100644
--- a/src/starboard/build/copy_data.py
+++ b/src/starboard/build/copy_data.py
@@ -21,11 +21,13 @@
 """
 
 import argparse
+import logging
 import os
 import posixpath
 import shutil
 import sys
 if os.name == 'nt':
+  import pywintypes
   import win32api
 
 # The name of an environment variable that when set to |'1'|, signals to us
@@ -83,9 +85,12 @@
     if os.name == 'nt':
       # Some of the files (especially for layout tests) result in very long
       # paths (especially on build machines) such that shutil.copy fails.
-      filename = win32api.GetShortPathName(filename)
-      output_basedir = win32api.GetShortPathName(output_basedir)
-
+      try:
+        filename = win32api.GetShortPathName(filename)
+        output_basedir = win32api.GetShortPathName(output_basedir)
+      except pywintypes.error:
+        logging.error('Failed to get ShortPathName for filename: \"%s\" and output_basedir: \"%s\"', filename, output_basedir)
+        raise
     # In certain cases, files would fail to open on windows if relative paths
     # were provided.  Using absolute paths fixes this.
     filename = os.path.abspath(filename)
@@ -132,10 +137,9 @@
     if options.output_dir is not None:
       print >> sys.stderr, 'COPY_LOG:', options.output_dir
 
-  escaped_files = [EscapePath(x) for x in options.input_paths]
-  files_to_copy = CalcInputs(escaped_files)
+  files_to_copy = CalcInputs(options.input_paths)
   if options.list_inputs:
-    return '\n'.join([x[0] for x in files_to_copy])
+    return '\n'.join([EscapePath(x[0]) for x in files_to_copy])
 
   if not options.output_dir:
     raise WrongNumberOfArgumentsException('-o required.')
@@ -149,6 +153,10 @@
 
 
 def main(argv):
+  logging_format = '[%(levelname)s:%(filename)s:%(lineno)s] %(message)s'
+  logging.basicConfig(
+      level=logging.INFO, format=logging_format, datefmt='%H:%M:%S')
+
   try:
     result = DoMain(argv[1:])
   except WrongNumberOfArgumentsException, e:
diff --git a/src/starboard/build/gyp_functions.py b/src/starboard/build/gyp_functions.py
index e6f466d..911f008 100644
--- a/src/starboard/build/gyp_functions.py
+++ b/src/starboard/build/gyp_functions.py
@@ -73,6 +73,13 @@
   def call(self):
     return getattr(self, self.command)()
 
+  def wrap_windows_path(self):
+    """Fixup a windows-style path by dealing with separators and spaces."""
+    path = os.path.normpath('/'.join(self.argv))
+    ret = path.replace(os.sep, '/')
+    ret = '"' + ret.strip() + '"'
+    return ret
+
   def file_glob(self):
     """Glob files in dir, with pattern glob."""
     args = ExtensionCommandParser(['dir', 'pattern']).parse_args(self.argv)
diff --git a/src/starboard/configuration.h b/src/starboard/configuration.h
index 9a4477a..d5e7d28 100644
--- a/src/starboard/configuration.h
+++ b/src/starboard/configuration.h
@@ -39,7 +39,7 @@
 
 // The maximum API version allowed by this version of the Starboard headers,
 // inclusive.
-#define SB_MAXIMUM_API_VERSION 13
+#define SB_MAXIMUM_API_VERSION 14
 
 // The API version that is currently open for changes, and therefore is not
 // stable or frozen. Production-oriented ports should avoid declaring that they
@@ -51,7 +51,7 @@
 // version, but be aware that small incompatible changes may still be made to
 // it.
 // The following will be uncommented when an API version is a release candidate.
-#define SB_RELEASE_CANDIDATE_API_VERSION 12
+// #define SB_RELEASE_CANDIDATE_API_VERSION 13
 
 // --- Experimental Feature Defines ------------------------------------------
 
diff --git a/src/starboard/doc/evergreen/cobalt_evergreen_overview.md b/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
index dff2965..5fe1c88 100644
--- a/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
+++ b/src/starboard/doc/evergreen/cobalt_evergreen_overview.md
@@ -242,7 +242,7 @@
 we would use the following command to run NPLB:
 
 ```
-.../elf_loader_sandbox --evergreen_library=app/nplb/lib/libcobalt.so
+.../elf_loader_sandbox --evergreen_library=app/nplb/lib/libnplb.so
                        --evergreen_content=app/nplb/content
 ```
 
@@ -413,12 +413,12 @@
 ```
 .
 ├── content <--(kSbSystemPathContentDirectory)
-│   └── fonts <--(kSbSystemPathFontDirectory, to be explained below)
+│   └── fonts <--(kSbSystemPathFontDirectory, `standard` or `limit` configuration, to be explained below)
 │   └── app
 │       └── cobalt <--(SLOT_0)
 │           ├── content <--(relative path defined in kSystemImageContentPath)
-│           │   ├── fonts
-│           │   ├── icu
+│           │   ├── fonts <--(`minimal` configuration)
+│           │   ├── (icu) <--(only present when it needs to be updated by Cobalt Update)
 │           │   ├── licenses
 │           │   ├── ssl
 │           ├── lib
@@ -438,8 +438,8 @@
     ├── installation_1 <--(SLOT_1 - currently unused)
     ├── installation_2 <--(SLOT_2 - contains new Cobalt version)
     │   ├── content
-    │   │   ├── fonts
-    │   │   ├── icu
+    │   │   ├── fonts <--(`minimal` configuration)
+    │   │   ├── (icu) <--(only present when it needs to be updated by Cobalt Update)
     │   │   ├── licenses
     │   │   ├── ssl
     │   ├── lib
@@ -447,7 +447,7 @@
     │   ├── manifest.fingerprint
     │   └── manifest.json <-- (Evergreen version information of libcobalt.so under SLOT_2)
     ├── installation_store_<APP_KEY>.pb
-    └── icu (To be explained below)
+    └── icu (default location shared by installation slots, to be explained below)
 ```
 
 #### App metadata
@@ -601,7 +601,7 @@
 
 loader_app --url="<YOUR_APP_1_URL>"
 loader_app --url="<YOUR_APP_2_URL>"
-loader_app --csp_mode=disable --allow_http --url="file:///<PATH_TO_APP_3>/index.html" --content="/<PATH_TO_APP_3>/content"
+loader_app --csp_mode=disable --allow_http --url="file:///<PATH_TO_APP_3>/index.html" --content="/<PATH_TO_APP_3>/content" --disable_updates
 ```
 
 Please see
diff --git a/src/starboard/elf_loader/elf_loader.gyp b/src/starboard/elf_loader/elf_loader.gyp
index 4970ae0..843c7de 100644
--- a/src/starboard/elf_loader/elf_loader.gyp
+++ b/src/starboard/elf_loader/elf_loader.gyp
@@ -109,6 +109,7 @@
       'dependencies': [
         'elf_loader',
         '<(DEPTH)/cobalt/content/fonts/fonts.gyp:copy_font_data',
+        '<(DEPTH)/starboard/elf_loader/sabi_string.gyp:sabi_string',
         '<(DEPTH)/starboard/starboard.gyp:starboard',
         # TODO: Remove this dependency once MediaSession is migrated to use CobaltExtensions.
         '<@(cobalt_platform_dependencies)',
diff --git a/src/starboard/elf_loader/sabi_string.cc b/src/starboard/elf_loader/sabi_string.cc
new file mode 100644
index 0000000..fd0f29a
--- /dev/null
+++ b/src/starboard/elf_loader/sabi_string.cc
@@ -0,0 +1,48 @@
+// 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 "starboard/elf_loader/sabi_string.h"
+
+#include "starboard/common/log.h"
+#include "starboard/string.h"
+
+extern "C" {
+
+const char* GetEvergreenSabiString() {
+#if SB_API_VERSION >= 12
+  return SB_SABI_JSON_ID;
+#else
+  return NULL;
+#endif  // SB_API_VERSION >= 12
+}
+
+}  // extern "C"
+
+bool CheckSabi(const char* (*sabi_function)()) {
+#if SB_API_VERSION >= 12
+  if (!sabi_function) {
+    SB_LOG(ERROR) << "Missing sabi_function";
+    return false;
+  }
+  SB_DLOG(INFO) << "sabi_function result: " << sabi_function();
+  if (SbStringCompareAll(sabi_function(), SB_SABI_JSON_ID) != 0) {
+    SB_LOG(ERROR) << "Expected SB_SABI_JSON_ID=" << SB_SABI_JSON_ID;
+    SB_LOG(ERROR) << "Actual   SB_SABI_JSON_ID=" << sabi_function();
+    return false;
+  }
+  return true;
+#else
+  return false;
+#endif  // SB_API_VERSION >= 12
+}
diff --git a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py b/src/starboard/elf_loader/sabi_string.gyp
old mode 100755
new mode 100644
similarity index 71%
copy from src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
copy to src/starboard/elf_loader/sabi_string.gyp
index a49568b..a39390e
--- a/src/third_party/precommit-hooks/sync_keyboxes_wrapper.py
+++ b/src/starboard/elf_loader/sabi_string.gyp
@@ -1,5 +1,3 @@
-#!/usr/bin/env python3
-#
 # Copyright 2020 The Cobalt Authors. All Rights Reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,13 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import sys
-
-try:
-  import sync_keyboxes
-except ImportError:
-  print('sync_keyboxes.py not found, skipping.')
-  sys.exit(0)
-
-if __name__ == "__main__":
-  sys.exit(sync_keyboxes.SyncKeyboxesForCurrentBranch())
+{
+  'targets': [
+    {
+      'target_name': 'sabi_string',
+      'type': 'static_library',
+      'sources': [
+        'sabi_string.cc',
+        'sabi_string.h',
+      ],
+    },
+  ],
+}
diff --git a/src/starboard/elf_loader/sabi_string.h b/src/starboard/elf_loader/sabi_string.h
new file mode 100644
index 0000000..5920654
--- /dev/null
+++ b/src/starboard/elf_loader/sabi_string.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef STARBOARD_ELF_LOADER_SABI_STRING_H_
+#define STARBOARD_ELF_LOADER_SABI_STRING_H_
+
+#include "starboard/export.h"
+
+extern "C" {
+
+// Retrieve the SABI ID. The function is exported by all Evergreen
+// binaries for verification purposes. The loader should call it
+// to enforce matching of the Evergreen SABI to its own SABI configuration.
+SB_IMPORT const char* GetEvergreenSabiString();
+
+}  // extern "C"
+
+// Check whether the |sabi_function| returns the same string as SB_SABI_JSON_ID.
+bool CheckSabi(const char* (*sabi_function)());
+
+#endif  // STARBOARD_ELF_LOADER_SABI_STRING_H_
diff --git a/src/starboard/elf_loader/sandbox.cc b/src/starboard/elf_loader/sandbox.cc
index 9dd2f73..2b1059d 100644
--- a/src/starboard/elf_loader/sandbox.cc
+++ b/src/starboard/elf_loader/sandbox.cc
@@ -18,6 +18,7 @@
 #include "starboard/elf_loader/elf_loader.h"
 #include "starboard/elf_loader/elf_loader_switches.h"
 #include "starboard/elf_loader/evergreen_info.h"
+#include "starboard/elf_loader/sabi_string.h"
 #include "starboard/event.h"
 #include "starboard/mutex.h"
 #include "starboard/shared/starboard/command_line.h"
@@ -61,6 +62,14 @@
     SB_LOG(INFO) << "Loaded Cobalt library information into Crashpad.";
   }
 
+  auto get_evergreen_sabi_string_func = reinterpret_cast<const char* (*)()>(
+      g_elf_loader.LookupSymbol("GetEvergreenSabiString"));
+
+  if (!CheckSabi(get_evergreen_sabi_string_func)) {
+    SB_LOG(ERROR) << "CheckSabi failed";
+    return;
+  }
+
   g_sb_event_func = reinterpret_cast<void (*)(const SbEvent*)>(
       g_elf_loader.LookupSymbol("SbEventHandle"));
 
@@ -93,11 +102,9 @@
   SB_CHECK(SbMutexAcquire(&mutex) == kSbMutexAcquired);
 
   if (!g_sb_event_func) {
-    const SbEventStartData* data =
-        static_cast<SbEventStartData*>(event->data);
+    const SbEventStartData* data = static_cast<SbEventStartData*>(event->data);
     const starboard::shared::starboard::CommandLine command_line(
-        data->argument_count,
-        const_cast<const char**>(data->argument_values));
+        data->argument_count, const_cast<const char**>(data->argument_values));
     LoadLibraryAndInitialize(
         command_line.GetSwitchValue(starboard::elf_loader::kEvergreenLibrary),
         command_line.GetSwitchValue(starboard::elf_loader::kEvergreenContent));
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index e92dc61..5feb9f1 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -288,31 +288,7 @@
       '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
       '<(DEPTH)/starboard/shared/starboard/memory.cc',
       '<(DEPTH)/starboard/shared/starboard/new.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.h',
-      '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.h',
-      '<(DEPTH)/starboard/shared/starboard/player/job_queue.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/job_queue.h',
-      '<(DEPTH)/starboard/shared/starboard/player/job_thread.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/job_thread.h',
-      '<(DEPTH)/starboard/shared/starboard/player/player_create.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_destroy.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_get_current_frame.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
       '<(DEPTH)/starboard/shared/starboard/player/player_output_mode_supported.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_set_playback_rate.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_worker.h',
-      '<(DEPTH)/starboard/shared/starboard/player/player_write_end_of_stream.cc',
-      '<(DEPTH)/starboard/shared/starboard/player/player_write_sample2.cc',
       '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
       '<(DEPTH)/starboard/shared/starboard/string_concat.cc',
       '<(DEPTH)/starboard/shared/starboard/string_concat_wide.cc',
@@ -384,6 +360,7 @@
       '<(DEPTH)/starboard/linux/shared/starboard_base_symbolize.gyp:starboard_base_symbolize',
       '<(DEPTH)/starboard/shared/ffmpeg/ffmpeg.gyp:ffmpeg_dynamic_load',
       '<(DEPTH)/starboard/shared/starboard/media/media.gyp:media_util',
+      '<(DEPTH)/starboard/shared/starboard/player/player.gyp:player',
       '<(DEPTH)/third_party/aom_includes/aom_includes.gyp:aom',
       '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto',
       '<(DEPTH)/third_party/de265_includes/de265_includes.gyp:de265',
diff --git a/src/starboard/loader_app/loader_app.cc b/src/starboard/loader_app/loader_app.cc
index 1c661af..d53919d 100644
--- a/src/starboard/loader_app/loader_app.cc
+++ b/src/starboard/loader_app/loader_app.cc
@@ -19,6 +19,7 @@
 #include "starboard/configuration_constants.h"
 #include "starboard/elf_loader/elf_loader.h"
 #include "starboard/elf_loader/evergreen_info.h"
+#include "starboard/elf_loader/sabi_string.h"
 #include "starboard/event.h"
 #include "starboard/file.h"
 #include "starboard/loader_app/app_key.h"
@@ -110,6 +111,14 @@
     SB_LOG(INFO) << "Loaded Cobalt library information into Crashpad.";
   }
 
+  auto get_evergreen_sabi_string_func = reinterpret_cast<const char* (*)()>(
+      g_elf_loader.LookupSymbol("GetEvergreenSabiString"));
+
+  if (!CheckSabi(get_evergreen_sabi_string_func)) {
+    SB_LOG(ERROR) << "CheckSabi failed";
+    return;
+  }
+
   auto get_user_agent_func = reinterpret_cast<const char* (*)()>(
       g_elf_loader.LookupSymbol("GetCobaltUserAgentString"));
   if (!get_user_agent_func) {
diff --git a/src/starboard/loader_app/loader_app.gyp b/src/starboard/loader_app/loader_app.gyp
index e8f730e..89f7121 100644
--- a/src/starboard/loader_app/loader_app.gyp
+++ b/src/starboard/loader_app/loader_app.gyp
@@ -22,6 +22,7 @@
       'system_get_extension_shim.cc',
     ],
     'common_loader_app_dependencies': [
+      '<(DEPTH)/starboard/elf_loader/sabi_string.gyp:sabi_string',
       '<(DEPTH)/starboard/loader_app/app_key.gyp:app_key',
       '<(DEPTH)/starboard/loader_app/installation_manager.gyp:installation_manager',
       '<(DEPTH)/starboard/loader_app/slot_management.gyp:slot_management',
diff --git a/src/starboard/loader_app/slot_management.cc b/src/starboard/loader_app/slot_management.cc
index 5dc1212..f2766cb 100644
--- a/src/starboard/loader_app/slot_management.cc
+++ b/src/starboard/loader_app/slot_management.cc
@@ -18,6 +18,7 @@
 
 #include "starboard/common/log.h"
 #include "starboard/configuration_constants.h"
+#include "starboard/elf_loader/sabi_string.h"
 #include "starboard/event.h"
 #include "starboard/file.h"
 #include "starboard/loader_app/app_key_files.h"
@@ -244,6 +245,22 @@
       SB_LOG(INFO) << "Loaded Cobalt library information into Crashpad.";
     }
 
+    auto get_evergreen_sabi_string_func = reinterpret_cast<const char* (*)()>(
+        library_loader->Resolve("GetEvergreenSabiString"));
+
+    if (!CheckSabi(get_evergreen_sabi_string_func)) {
+      SB_LOG(ERROR) << "CheckSabi failed";
+      // Hard failure. Discard the image and auto rollback, but only if
+      // the current image is not the system image.
+      if (current_installation != 0) {
+        current_installation = RevertBack(current_installation, app_key);
+        continue;
+      } else {
+        // The system image at index 0 failed.
+        return NULL;
+      }
+    }
+
     auto get_user_agent_func = reinterpret_cast<const char* (*)()>(
         library_loader->Resolve("GetCobaltUserAgentString"));
     if (!get_user_agent_func) {
diff --git a/src/starboard/loader_app/slot_management.gyp b/src/starboard/loader_app/slot_management.gyp
index d68c502..85c58ae 100644
--- a/src/starboard/loader_app/slot_management.gyp
+++ b/src/starboard/loader_app/slot_management.gyp
@@ -22,6 +22,7 @@
         'slot_management.h',
       ],
       'dependencies': [
+        '<(DEPTH)/starboard/elf_loader/sabi_string.gyp:sabi_string',
         '<(DEPTH)/starboard/loader_app/app_key_files.gyp:app_key_files',
         '<(DEPTH)/starboard/loader_app/drain_file.gyp:drain_file',
         '<(DEPTH)/starboard/loader_app/installation_manager.gyp:installation_manager',
diff --git a/src/starboard/loader_app/slot_management_test.cc b/src/starboard/loader_app/slot_management_test.cc
index 5ff9e20..3c0aca6 100644
--- a/src/starboard/loader_app/slot_management_test.cc
+++ b/src/starboard/loader_app/slot_management_test.cc
@@ -19,6 +19,7 @@
 
 #include "gmock/gmock.h"
 #include "starboard/configuration_constants.h"
+#include "starboard/elf_loader/sabi_string.h"
 #include "starboard/event.h"
 #include "starboard/loader_app/app_key_files.h"
 #include "starboard/loader_app/drain_file.h"
@@ -37,6 +38,10 @@
 
 void SbEventFake(const SbEvent*) {}
 
+const char* GetEvergreenSabiStringFake() {
+  return "bad";
+}
+
 const char* GetCobaltUserAgentStringFake() {
   return "";
 }
@@ -136,6 +141,10 @@
                 Load(testing::EndsWith(lib), testing::EndsWith(content)))
         .Times(1)
         .WillOnce(testing::Return(true));
+    EXPECT_CALL(library_loader, Resolve("GetEvergreenSabiString"))
+        .Times(1)
+        .WillOnce(
+            testing::Return(reinterpret_cast<void*>(&GetEvergreenSabiString)));
     EXPECT_CALL(library_loader, Resolve("GetCobaltUserAgentString"))
         .Times(1)
         .WillOnce(testing::Return(
@@ -269,6 +278,11 @@
                                    testing::EndsWith("/foo")))
       .Times(1)
       .WillOnce(testing::Return(true));
+  EXPECT_CALL(library_loader, Resolve("GetEvergreenSabiString"))
+      .Times(1)
+      .WillOnce(
+          testing::Return(reinterpret_cast<void*>(&GetEvergreenSabiString)));
+
   EXPECT_CALL(library_loader, Resolve("GetCobaltUserAgentString"))
       .Times(1)
       .WillOnce(testing::Return(
@@ -279,6 +293,57 @@
   ASSERT_EQ(&SbEventFake,
             LoadSlotManagedLibrary(kTestAppKey, "/foo", &library_loader));
 }
+
+TEST_F(SlotManagementTest, BadSabi) {
+  if (!storage_path_implemented_) {
+    return;
+  }
+  ImInitialize(3, kTestAppKey);
+  ImReset();
+  ASSERT_EQ(IM_SUCCESS, ImRollForward(1));
+  ASSERT_EQ(IM_SUCCESS, ImMarkInstallationSuccessful(1));
+  ASSERT_EQ(1, ImGetCurrentInstallationIndex());
+  CreateGoodFile(1, kTestAppKey);
+
+  ASSERT_EQ(IM_SUCCESS, ImRollForward(2));
+  ASSERT_EQ(IM_SUCCESS, ImMarkInstallationSuccessful(2));
+  ASSERT_EQ(2, ImGetCurrentInstallationIndex());
+  CreateGoodFile(2, kTestAppKey);
+
+  ImUninitialize();
+
+  MockLibraryLoader library_loader;
+
+  EXPECT_CALL(library_loader, Load(testing::EndsWith(slot_2_libcobalt_path_),
+                                   testing::EndsWith(slot_2_content_path_)))
+      .Times(1)
+      .WillOnce(testing::Return(true));
+
+  EXPECT_CALL(library_loader, Resolve("GetEvergreenSabiString"))
+      .Times(2)
+      .WillOnce(
+          testing::Return(reinterpret_cast<void*>(&GetEvergreenSabiStringFake)))
+      .WillOnce(
+          testing::Return(reinterpret_cast<void*>(&GetEvergreenSabiString)));
+
+  EXPECT_CALL(library_loader, Load(testing::EndsWith(slot_1_libcobalt_path_),
+                                   testing::EndsWith(slot_1_content_path_)))
+      .Times(1)
+      .WillOnce(testing::Return(true));
+
+  EXPECT_CALL(library_loader, Resolve("GetCobaltUserAgentString"))
+      .Times(1)
+      .WillOnce(testing::Return(
+          reinterpret_cast<void*>(&GetCobaltUserAgentStringFake)));
+
+  EXPECT_CALL(library_loader, Resolve("SbEventHandle"))
+      .Times(1)
+      .WillOnce(testing::Return(reinterpret_cast<void*>(&SbEventFake)));
+
+  ASSERT_EQ(&SbEventFake,
+            LoadSlotManagedLibrary(kTestAppKey, "", &library_loader));
+}
+
 }  // namespace
 }  // namespace loader_app
 }  // namespace starboard
diff --git a/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc b/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc
index 86faf88..44ec016 100644
--- a/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc
+++ b/src/starboard/nplb/media_can_play_mime_and_key_system_test.cc
@@ -67,7 +67,11 @@
       "audio/mp4; codecs=\"mp4a.40.2\"; channels=2", "");
   ASSERT_EQ(result, kSbMediaSupportTypeProbably);
   // Opus
-  SbMediaCanPlayMimeAndKeySystem("audio/webm; codecs=\"opus\"; channels=2", "");
+  result = SbMediaCanPlayMimeAndKeySystem(
+      "audio/webm; codecs=\"opus\"; channels=2", "");
+#if SB_API_VERSION >= 12
+  ASSERT_EQ(result, kSbMediaSupportTypeProbably);
+#endif  // SB_API_VERSION >= 12
 }
 
 TEST(SbMediaCanPlayMimeAndKeySystem, Invalid) {
diff --git a/src/starboard/nplb/memory_reporter_test.cc b/src/starboard/nplb/memory_reporter_test.cc
index e327035..6dde02b 100644
--- a/src/starboard/nplb/memory_reporter_test.cc
+++ b/src/starboard/nplb/memory_reporter_test.cc
@@ -355,6 +355,9 @@
   SbMemoryUnmap(mem_chunk, kMemSize);
   EXPECT_EQ_NO_TRACKING(mem_chunk, mem_reporter()->last_mem_unmap());
   EXPECT_EQ_NO_TRACKING(0, mem_reporter()->number_map_mem());
+  // On some platforms, bookkeeping for memory mapping can cost allocations.
+  // Call Clear() explicitly before TearDown() checks number_allocs_;
+  mem_reporter()->Clear();
 }
 #endif  // SB_API_VERSION >= 12 || SB_HAS(MMAP)
 
diff --git a/src/starboard/nplb/microphone_read_test.cc b/src/starboard/nplb/microphone_read_test.cc
index 47f1ebc..548d229 100644
--- a/src/starboard/nplb/microphone_read_test.cc
+++ b/src/starboard/nplb/microphone_read_test.cc
@@ -100,7 +100,7 @@
     int read_bytes =
         SbMicrophoneRead(microphone, &audio_data[0], audio_data.size());
     EXPECT_GE(read_bytes, 0);
-    EXPECT_LT(read_bytes, audio_data.size());
+    EXPECT_LE(read_bytes, audio_data.size());
 
     SbMicrophoneDestroy(microphone);
   }
diff --git a/src/starboard/raspi/shared/graphics.cc b/src/starboard/raspi/shared/graphics.cc
new file mode 100644
index 0000000..15f598c
--- /dev/null
+++ b/src/starboard/raspi/shared/graphics.cc
@@ -0,0 +1,53 @@
+// 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 "starboard/raspi/shared/graphics.h"
+
+#include "cobalt/extension/graphics.h"
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+
+namespace {
+
+float GetMaximumFrameIntervalInMilliseconds() {
+  return -1.0f;
+}
+
+float GetMinimumFrameIntervalInMilliseconds() {
+  return 8.0f;
+}
+
+bool IsMapToMeshEnabled() {
+  return false;
+}
+
+const CobaltExtensionGraphicsApi kGraphicsApi = {
+  kCobaltExtensionGraphicsName,
+  3,
+  &GetMaximumFrameIntervalInMilliseconds,
+  &GetMinimumFrameIntervalInMilliseconds,
+  &IsMapToMeshEnabled,
+};
+
+}  // namespace
+
+const void* GetGraphicsApi() {
+  return &kGraphicsApi;
+}
+
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
diff --git a/src/starboard/raspi/shared/graphics.h b/src/starboard/raspi/shared/graphics.h
new file mode 100644
index 0000000..f35886ca
--- /dev/null
+++ b/src/starboard/raspi/shared/graphics.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef STARBOARD_RASPI_SHARED_GRAPHICS_H_
+#define STARBOARD_RASPI_SHARED_GRAPHICS_H_
+
+namespace starboard {
+namespace raspi {
+namespace shared {
+
+const void* GetGraphicsApi();
+
+}  // namespace shared
+}  // namespace raspi
+}  // namespace starboard
+
+#endif  // STARBOARD_RASPI_SHARED_GRAPHICS_H_
diff --git a/src/starboard/raspi/shared/player_components_factory.cc b/src/starboard/raspi/shared/player_components_factory.cc
index b08d8f9..0c488a9 100644
--- a/src/starboard/raspi/shared/player_components_factory.cc
+++ b/src/starboard/raspi/shared/player_components_factory.cc
@@ -17,6 +17,7 @@
 #include "starboard/raspi/shared/open_max/video_decoder.h"
 #include "starboard/raspi/shared/video_renderer_sink_impl.h"
 #include "starboard/shared/ffmpeg/ffmpeg_audio_decoder.h"
+#include "starboard/shared/opus/opus_audio_decoder.h"
 #include "starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h"
 #include "starboard/shared/starboard/player/filter/audio_decoder_internal.h"
 #include "starboard/shared/starboard/player/filter/audio_renderer_sink_impl.h"
@@ -52,12 +53,21 @@
       auto decoder_creator = [](const SbMediaAudioSampleInfo& audio_sample_info,
                                 SbDrmSystem drm_system) {
         typedef ::starboard::shared::ffmpeg::AudioDecoder AudioDecoderImpl;
+        typedef ::starboard::shared::opus::OpusAudioDecoder OpusAudioDecoderImpl;
 
-        scoped_ptr<AudioDecoderImpl> audio_decoder_impl(
-            AudioDecoderImpl::Create(audio_sample_info.codec,
-                                     audio_sample_info));
-        if (audio_decoder_impl && audio_decoder_impl->is_valid()) {
-          return audio_decoder_impl.PassAs<AudioDecoder>();
+        if(audio_sample_info.codec == kSbMediaAudioCodecOpus) {
+          scoped_ptr<OpusAudioDecoderImpl> opus_audio_decoder_impl(
+              new OpusAudioDecoderImpl(audio_sample_info));
+          if (opus_audio_decoder_impl && opus_audio_decoder_impl->is_valid()) {
+            return opus_audio_decoder_impl.PassAs<AudioDecoder>();
+          }
+        } else {
+          scoped_ptr<AudioDecoderImpl> audio_decoder_impl(
+              AudioDecoderImpl::Create(audio_sample_info.codec,
+                                      audio_sample_info));
+          if (audio_decoder_impl && audio_decoder_impl->is_valid()) {
+            return audio_decoder_impl.PassAs<AudioDecoder>();
+          }
         }
         return scoped_ptr<AudioDecoder>();
       };
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 8498463..b0ac195 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -51,6 +51,8 @@
         '<(DEPTH)/starboard/raspi/shared/configuration.h',
         '<(DEPTH)/starboard/raspi/shared/dispmanx_util.cc',
         '<(DEPTH)/starboard/raspi/shared/dispmanx_util.h',
+        '<(DEPTH)/starboard/raspi/shared/graphics.cc',
+        '<(DEPTH)/starboard/raspi/shared/graphics.h',
         '<(DEPTH)/starboard/raspi/shared/main.cc',
         '<(DEPTH)/starboard/raspi/shared/media_is_video_supported.cc',
         '<(DEPTH)/starboard/raspi/shared/open_max/decode_target_create.cc',
@@ -163,6 +165,8 @@
         '<(DEPTH)/starboard/shared/nouser/user_get_property.cc',
         '<(DEPTH)/starboard/shared/nouser/user_get_signed_in.cc',
         '<(DEPTH)/starboard/shared/nouser/user_internal.cc',
+        '<(DEPTH)/starboard/shared/opus/opus_audio_decoder.h',
+        '<(DEPTH)/starboard/shared/opus/opus_audio_decoder.cc',
         '<(DEPTH)/starboard/shared/posix/directory_create.cc',
         '<(DEPTH)/starboard/shared/posix/file_atomic_replace.cc',
         '<(DEPTH)/starboard/shared/posix/file_can_open.cc',
@@ -311,7 +315,7 @@
         '<(DEPTH)/starboard/shared/starboard/media/media_get_max_buffer_capacity.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_get_progressive_buffer_budget.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_get_video_buffer_budget.cc',
-        '<(DEPTH)/starboard/shared/starboard/media/media_is_audio_supported_aac_only.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/media_is_audio_supported_aac_and_opus.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_pool_allocate_on_demand.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_buffer_using_memory_pool.cc',
         '<(DEPTH)/starboard/shared/starboard/media/media_is_transfer_characteristics_supported.cc',
@@ -319,30 +323,6 @@
         '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
         '<(DEPTH)/starboard/shared/starboard/memory.cc',
         '<(DEPTH)/starboard/shared/starboard/new.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/job_queue.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/job_queue.h',
-        '<(DEPTH)/starboard/shared/starboard/player/job_thread.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/job_thread.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_create.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_destroy.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_current_frame.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_set_playback_rate.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_worker.h',
-        '<(DEPTH)/starboard/shared/starboard/player/player_write_end_of_stream.cc',
-        '<(DEPTH)/starboard/shared/starboard/player/player_write_sample2.cc',
         '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
         '<(DEPTH)/starboard/shared/starboard/string_concat.cc',
         '<(DEPTH)/starboard/shared/starboard/string_concat_wide.cc',
@@ -422,8 +402,10 @@
         '<(DEPTH)/starboard/common/common.gyp:common',
         '<(DEPTH)/third_party/dlmalloc/dlmalloc.gyp:dlmalloc',
         '<(DEPTH)/third_party/libevent/libevent.gyp:libevent',
+        '<(DEPTH)/third_party/opus/opus.gyp:opus',
         '<(DEPTH)/starboard/shared/ffmpeg/ffmpeg.gyp:ffmpeg_linked',
         '<(DEPTH)/starboard/shared/starboard/media/media.gyp:media_util',
+        '<(DEPTH)/starboard/shared/starboard/player/player.gyp:player',
         'starboard_base_symbolize',
       ],
       'conditions': [
diff --git a/src/starboard/raspi/shared/system_get_extensions.cc b/src/starboard/raspi/shared/system_get_extensions.cc
index 8ac669a..cc7490c 100644
--- a/src/starboard/raspi/shared/system_get_extensions.cc
+++ b/src/starboard/raspi/shared/system_get_extensions.cc
@@ -15,12 +15,14 @@
 #include "starboard/system.h"
 
 #include "cobalt/extension/configuration.h"
+#include "cobalt/extension/graphics.h"
 #include "starboard/common/string.h"
 #if SB_IS(EVERGREEN_COMPATIBLE)
 #include "starboard/elf_loader/evergreen_config.h"
 #endif
 
 #include "starboard/raspi/shared/configuration.h"
+#include "starboard/raspi/shared/graphics.h"
 
 const void* SbSystemGetExtension(const char* name) {
 #if SB_IS(EVERGREEN_COMPATIBLE)
@@ -38,5 +40,8 @@
   if (SbStringCompareAll(name, kCobaltExtensionConfigurationName) == 0) {
     return starboard::raspi::shared::GetConfigurationApi();
   }
+  if (SbStringCompareAll(name, kCobaltExtensionGraphicsName) == 0) {
+    return starboard::raspi::shared::GetGraphicsApi();
+  }
   return NULL;
 }
diff --git a/src/starboard/shared/posix/log.cc b/src/starboard/shared/posix/log.cc
index 5be55ca..862e011 100644
--- a/src/starboard/shared/posix/log.cc
+++ b/src/starboard/shared/posix/log.cc
@@ -23,13 +23,14 @@
 #endif  // SB_API_VERSION >= 11
 
 void SbLog(SbLogPriority priority, const char* message) {
+  FILE* stream = priority >= kSbLogPriorityError ? stderr : stdout;
 #if SB_API_VERSION < 11
-  fprintf(stderr, "%s", message);
-  fflush(stderr);
+  fprintf(stream, "%s", message);
+  fflush(stream);
 #else   // SB_API_VERSION >= 11
   starboard::shared::starboard::GetLoggingMutex()->Acquire();
-  fprintf(stderr, "%s", message);
-  fflush(stderr);
+  fprintf(stream, "%s", message);
+  fflush(stream);
   starboard::shared::starboard::GetLoggingMutex()->Release();
 #endif  // SB_API_VERSION < 11
 }
diff --git a/src/starboard/shared/signal/system_request_freeze.cc b/src/starboard/shared/signal/system_request_freeze.cc
index 374261e..b63b1ed 100644
--- a/src/starboard/shared/signal/system_request_freeze.cc
+++ b/src/starboard/shared/signal/system_request_freeze.cc
@@ -25,6 +25,10 @@
     SB_HAS(CONCEALED_STATE)
 void FreezeDone(void* /*context*/) {
   // Stop all thread execution after fully transitioning into Frozen.
+  // This would stop the platform's background thread, such as:
+  // application android thread for android platforms. Which may not
+  // be the correct expected behavoir, since application android is
+  // for listening the callbacks from android main thread.
   raise(SIGSTOP);
 }
 
diff --git a/src/starboard/shared/signal/system_request_freeze_no_freezedone_callback.cc b/src/starboard/shared/signal/system_request_freeze_no_freezedone_callback.cc
new file mode 100644
index 0000000..8d9bd2d
--- /dev/null
+++ b/src/starboard/shared/signal/system_request_freeze_no_freezedone_callback.cc
@@ -0,0 +1,47 @@
+// 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 "starboard/system.h"
+
+#include "starboard/shared/signal/signal_internal.h"
+#include "starboard/shared/starboard/application.h"
+
+#if SB_IS(EVERGREEN_COMPATIBLE)
+#include "starboard/loader_app/pending_restart.h"
+#endif
+
+#if SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION || \
+    SB_HAS(CONCEALED_STATE)
+
+void SbSystemRequestFreeze() {
+#if SB_IS(EVERGREEN_COMPATIBLE)
+  if (starboard::loader_app::IsPendingRestart()) {
+    SbLogRawFormatF("\nPending update restart . Stopping.\n");
+    SbLogFlush();
+    starboard::shared::starboard::Application::Get()->Stop(0);
+  } else {
+    // Let the platform decide if directly transit into Frozen. There
+    // is no FreezeDone callback for stopping all thread execution
+    // after fully transitioning into Frozen.
+    starboard::shared::starboard::Application::Get()->Freeze(NULL, NULL);
+  }
+#else
+  // Let the platform decide if directly transit into Frozen. There
+  // is no FreezeDone callback for stopping all thread execution
+  // after fully transitioning into Frozen.
+  starboard::shared::starboard::Application::Get()->Freeze(NULL, NULL);
+#endif
+}
+#endif  // SB_API_VERSION >= SB_ADD_CONCEALED_STATE_SUPPORT_VERSION ||
+        // SB_HAS(CONCEALED_STATE)
diff --git a/src/starboard/shared/starboard/accessibility_internal.h b/src/starboard/shared/starboard/accessibility_internal.h
new file mode 100644
index 0000000..64c3f9b
--- /dev/null
+++ b/src/starboard/shared/starboard/accessibility_internal.h
@@ -0,0 +1,175 @@
+// 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.
+
+// Module Overview: Starboard Accessibility API
+
+// Provide helper macros and functions useful to the implementations of the
+// Starboard Accessibility API on all platforms
+
+#ifndef STARBOARD_SHARED_STARBOARD_ACCESSIBILITY_INTERNAL_H_
+#define STARBOARD_SHARED_STARBOARD_ACCESSIBILITY_INTERNAL_H_
+
+#include <limits>
+
+#include "starboard/accessibility.h"
+#include "starboard/common/log.h"
+
+namespace starboard {
+namespace shared {
+namespace starboard {
+
+const int kRgbWhite = 0xFFFFFF;
+const int kRgbBlack = 0x000000;
+const int kRgbRed = 0xFF0000;
+const int kRgbYellow = 0xFFFF00;
+const int kRgbGreen = 0x00FF00;
+const int kRgbCyan = 0x00FFFF;
+const int kRgbBlue = 0x0000FF;
+const int kRgbMagenta = 0xFF00FF;
+
+const int kRgbColors[] = {
+    kRgbWhite, kRgbBlack, kRgbRed,  kRgbYellow,
+    kRgbGreen, kRgbCyan,  kRgbBlue, kRgbMagenta,
+};
+
+SbAccessibilityCaptionColor GetClosestCaptionColorRGB(int r, int g, int b) {
+  int ref_color = kRgbWhite;
+  int min_distance = std::numeric_limits<int>::max();
+
+  // Find the reference color with the least distance (squared).
+  for (int i = 0; i < SB_ARRAY_SIZE(kRgbColors); i++) {
+    int r_ref = 0xFF & (kRgbColors[i] >> 16);
+    int g_ref = 0xFF & (kRgbColors[i] >> 8);
+    int b_ref = 0xFF & (kRgbColors[i]);
+    int distance_squared =
+        pow(r - r_ref, 2) + pow(g - g_ref, 2) + pow(b - b_ref, 2);
+    if (distance_squared < min_distance) {
+      ref_color = kRgbColors[i];
+      min_distance = distance_squared;
+    }
+  }
+
+  switch (ref_color) {
+    case kRgbWhite:
+      return kSbAccessibilityCaptionColorWhite;
+    case kRgbBlack:
+      return kSbAccessibilityCaptionColorBlack;
+    case kRgbRed:
+      return kSbAccessibilityCaptionColorRed;
+    case kRgbYellow:
+      return kSbAccessibilityCaptionColorYellow;
+    case kRgbGreen:
+      return kSbAccessibilityCaptionColorGreen;
+    case kRgbCyan:
+      return kSbAccessibilityCaptionColorCyan;
+    case kRgbBlue:
+      return kSbAccessibilityCaptionColorBlue;
+    case kRgbMagenta:
+      return kSbAccessibilityCaptionColorMagenta;
+    default:
+      SB_NOTREACHED() << "Invalid RGB color conversion";
+      return kSbAccessibilityCaptionColorWhite;
+  }
+}
+
+SbAccessibilityCaptionColor GetClosestCaptionColor(int color) {
+  int r = 0xFF & (color >> 16);
+  int g = 0xFF & (color >> 8);
+  int b = 0xFF & (color);
+  return GetClosestCaptionColorRGB(r, g, b);
+}
+
+int FindClosestReferenceValue(int value,
+                              const int reference[],
+                              size_t reference_size) {
+  int result = reference[0];
+  int min_difference = std::numeric_limits<int>::max();
+
+  for (int i = 0; i < reference_size; i++) {
+    int difference = abs(reference[i] - value);
+    if (difference < min_difference) {
+      result = reference[i];
+      min_difference = difference;
+    }
+  }
+  return result;
+}
+
+const int kFontSizes[] = {25,  50,  75,  100, 125, 150,
+                          175, 200, 225, 250, 275, 300};
+
+SbAccessibilityCaptionFontSizePercentage GetClosestFontSizePercentage(
+    int font_size_percent) {
+  int reference_size = FindClosestReferenceValue(font_size_percent, kFontSizes,
+                                                 SB_ARRAY_SIZE(kFontSizes));
+  switch (reference_size) {
+    case 25:
+      return kSbAccessibilityCaptionFontSizePercentage25;
+    case 50:
+      return kSbAccessibilityCaptionFontSizePercentage50;
+    case 75:
+      return kSbAccessibilityCaptionFontSizePercentage75;
+    case 100:
+      return kSbAccessibilityCaptionFontSizePercentage100;
+    case 125:
+      return kSbAccessibilityCaptionFontSizePercentage125;
+    case 150:
+      return kSbAccessibilityCaptionFontSizePercentage150;
+    case 175:
+      return kSbAccessibilityCaptionFontSizePercentage175;
+    case 200:
+      return kSbAccessibilityCaptionFontSizePercentage200;
+    case 225:
+      return kSbAccessibilityCaptionFontSizePercentage225;
+    case 250:
+      return kSbAccessibilityCaptionFontSizePercentage250;
+    case 275:
+      return kSbAccessibilityCaptionFontSizePercentage275;
+    case 300:
+      return kSbAccessibilityCaptionFontSizePercentage300;
+    default:
+      SB_NOTREACHED() << "Invalid font size";
+      return kSbAccessibilityCaptionFontSizePercentage100;
+  }
+}
+
+const int kOpacities[] = {
+    0, 25, 50, 75, 100,
+};
+
+SbAccessibilityCaptionOpacityPercentage GetClosestOpacity(int opacity_percent) {
+  int reference_opacity_percent = FindClosestReferenceValue(
+      opacity_percent, kOpacities, SB_ARRAY_SIZE(kOpacities));
+  switch (reference_opacity_percent) {
+    case 0:
+      return kSbAccessibilityCaptionOpacityPercentage0;
+    case 25:
+      return kSbAccessibilityCaptionOpacityPercentage25;
+    case 50:
+      return kSbAccessibilityCaptionOpacityPercentage50;
+    case 75:
+      return kSbAccessibilityCaptionOpacityPercentage75;
+    case 100:
+      return kSbAccessibilityCaptionOpacityPercentage100;
+    default:
+      SB_NOTREACHED() << "Invalid opacity percentage";
+      return kSbAccessibilityCaptionOpacityPercentage100;
+  }
+}
+
+}  // namespace starboard
+}  // namespace shared
+}  // namespace starboard
+
+#endif  // STARBOARD_SHARED_STARBOARD_ACCESSIBILITY_INTERNAL_H_
diff --git a/src/starboard/shared/starboard/application.cc b/src/starboard/shared/starboard/application.cc
index 50f622a..fb92430 100644
--- a/src/starboard/shared/starboard/application.cc
+++ b/src/starboard/shared/starboard/application.cc
@@ -340,6 +340,7 @@
           Inject(scoped_event.release());
           return true;
         case kStateConcealed:
+          OnSuspend();
           break;
         case kStateFrozen:
         case kStateStopped:
@@ -506,7 +507,6 @@
     case kSbEventTypeFreeze:
       SB_DCHECK(state() == kStateConcealed);
       state_ = kStateFrozen;
-      OnSuspend();
       break;
     case kSbEventTypeUnfreeze:
       SB_DCHECK(state() == kStateFrozen);
diff --git a/src/starboard/shared/starboard/player/common_player_sources.gypi b/src/starboard/shared/starboard/player/common_player_sources.gypi
new file mode 100644
index 0000000..07121d4
--- /dev/null
+++ b/src/starboard/shared/starboard/player/common_player_sources.gypi
@@ -0,0 +1,44 @@
+# 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.
+
+{
+  'variables': {
+    'common_player_sources': [
+      '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/decoded_audio_internal.h',
+      '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/input_buffer_internal.h',
+      '<(DEPTH)/starboard/shared/starboard/player/job_queue.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/job_queue.h',
+      '<(DEPTH)/starboard/shared/starboard/player/job_thread.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/job_thread.h',
+      '<(DEPTH)/starboard/shared/starboard/player/player_create.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_destroy.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_current_frame.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_info2.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_maximum_number_of_samples_per_write.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_get_preferred_output_mode_prefer_punchout.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_internal.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_internal.h',
+      '<(DEPTH)/starboard/shared/starboard/player/player_seek2.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_set_bounds.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_set_playback_rate.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_set_volume.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_worker.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_worker.h',
+      '<(DEPTH)/starboard/shared/starboard/player/player_write_end_of_stream.cc',
+      '<(DEPTH)/starboard/shared/starboard/player/player_write_sample2.cc',
+    ],
+  },
+}
diff --git a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
index 8eba0ca..29734f4 100644
--- a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.cc
@@ -29,18 +29,13 @@
 using common::ResetAndReturn;
 
 #if SB_API_VERSION >= 11
-int GetDefaultSupportedAudioSamplesPerSecond() {
-  const int kDefaultOutputSamplesPerSecond = 48000;
-  return SbAudioSinkGetNearestSupportedSampleFrequency(
-      kDefaultOutputSamplesPerSecond);
-}
-
 AdaptiveAudioDecoder::AdaptiveAudioDecoder(
     const SbMediaAudioSampleInfo& audio_sample_info,
     SbDrmSystem drm_system,
     const AudioDecoderCreator& audio_decoder_creator,
     const OutputFormatAdjustmentCallback& output_adjustment_callback)
-    : drm_system_(drm_system),
+    : initial_audio_sample_info_(audio_sample_info),
+      drm_system_(drm_system),
       audio_decoder_creator_(audio_decoder_creator),
       output_adjustment_callback_(output_adjustment_callback),
       output_number_of_channels_(audio_sample_info.number_of_channels) {
@@ -131,7 +126,7 @@
   SB_DCHECK(first_output_received_ || ret->is_end_of_stream());
   *samples_per_second = first_output_received_
                             ? output_samples_per_second_
-                            : GetDefaultSupportedAudioSamplesPerSecond();
+                            : initial_audio_sample_info_.samples_per_second;
   return ret;
 }
 
diff --git a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h
index a9f6767..cb862a4 100644
--- a/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h
+++ b/src/starboard/shared/starboard/player/filter/adaptive_audio_decoder_internal.h
@@ -70,6 +70,7 @@
   void TeardownAudioDecoder();
   void OnDecoderOutput();
 
+  const SbMediaAudioSampleInfo initial_audio_sample_info_;
   const SbDrmSystem drm_system_;
   const AudioDecoderCreator audio_decoder_creator_;
   const OutputFormatAdjustmentCallback output_adjustment_callback_;
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_internal_impl.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_internal_impl.cc
index 601732b..9a1d793 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_internal_impl.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_internal_impl.cc
@@ -397,7 +397,9 @@
     // Fill silence frames on EOS to ensure keep the audio sink playing.
     auto start_offset =
         (*offset_in_frames + *frames_in_buffer) % max_cached_frames_;
-    auto silence_frames_to_write = max_cached_frames_ - start_offset;
+    auto silence_frames_to_write =
+        std::min(max_cached_frames_ - start_offset,
+                 max_cached_frames_ - *frames_in_buffer);
     SB_DCHECK(start_offset >= 0);
     SB_DCHECK(silence_frames_to_write >= 0);
     SB_DCHECK(start_offset + silence_frames_to_write <= max_cached_frames_);
diff --git a/src/starboard/shared/starboard/player/filter/cpu_video_frame.cc b/src/starboard/shared/starboard/player/filter/cpu_video_frame.cc
index 3aecfd4..c3e379b 100644
--- a/src/starboard/shared/starboard/player/filter/cpu_video_frame.cc
+++ b/src/starboard/shared/starboard/player/filter/cpu_video_frame.cc
@@ -187,6 +187,12 @@
     const uint8_t* v) {
   SB_DCHECK(bit_depth == 8 || bit_depth == 10 || bit_depth == 12);
 
+  if (bit_depth > 8) {
+    SB_DCHECK(source_pitch_in_bytes >= width * 2);
+  } else {
+    SB_DCHECK(source_pitch_in_bytes >= width);
+  }
+
   scoped_refptr<CpuVideoFrame> frame(new CpuVideoFrame(timestamp));
   frame->format_ = kYV12;
   frame->width_ = width;
diff --git a/src/starboard/shared/starboard/player/player.gyp b/src/starboard/shared/starboard/player/player.gyp
index 8e3c9eb..264d2b8 100644
--- a/src/starboard/shared/starboard/player/player.gyp
+++ b/src/starboard/shared/starboard/player/player.gyp
@@ -15,6 +15,19 @@
 {
   'targets': [
     {
+      'target_name': 'player',
+      'type': 'static_library',
+      'sources': [
+        '<@(common_player_sources)',
+      ],
+      'defines': [
+        # This must be defined when building Starboard, and must not when
+        # building Starboard client code.
+        'STARBOARD_IMPLEMENTATION',
+      ],
+      'includes': ['<(DEPTH)/starboard/shared/starboard/player/common_player_sources.gypi'],
+    },
+    {
       'target_name': 'video_dmp',
       'type': 'static_library',
       'sources': [
@@ -26,7 +39,7 @@
         '<(DEPTH)/starboard/shared/starboard/player/video_dmp_reader.h',
       ],
       'dependencies': [
-        '<(DEPTH)/starboard/starboard.gyp:starboard',
+        '<(DEPTH)/starboard/starboard_headers_only.gyp:starboard_headers_only',
       ],
       'defines': [
         # This allows the tests to include internal only header files.
diff --git a/src/starboard/socket_waiter.h b/src/starboard/socket_waiter.h
index ad60bc2..18bbfbd 100644
--- a/src/starboard/socket_waiter.h
+++ b/src/starboard/socket_waiter.h
@@ -34,8 +34,8 @@
 #ifndef STARBOARD_SOCKET_WAITER_H_
 #define STARBOARD_SOCKET_WAITER_H_
 
-#include "starboard/socket.h"
 #include "starboard/export.h"
+#include "starboard/socket.h"
 #include "starboard/time.h"
 #include "starboard/types.h"
 
@@ -130,8 +130,9 @@
 //   the socket:
 // - If |persistent| is |true|, then |socket| stays registered with |waiter|
 //   until SbSocketWaiterRemove() is called with |waiter| and |socket|.
-// - If |persistent| is |false|, then |socket| is removed after the next call
-//   to |callback|, even if not all registered |interests| became ready.
+// - If |persistent| is |false|, then |socket| is removed before the next call
+//   to |callback|, even if not all registered |interests| became ready,
+//   which allows for adding it again in the |callback|.
 SB_EXPORT bool SbSocketWaiterAdd(SbSocketWaiter waiter,
                                  SbSocket socket,
                                  void* context,
diff --git a/src/starboard/starboard.gyp b/src/starboard/starboard.gyp
index 9c74ba2..74008fc 100644
--- a/src/starboard/starboard.gyp
+++ b/src/starboard/starboard.gyp
@@ -25,6 +25,7 @@
         ['sb_evergreen == 1', {
           'dependencies': [
             '<(DEPTH)/starboard/client_porting/eztime/eztime.gyp:eztime',
+            '<(DEPTH)/starboard/elf_loader/sabi_string.gyp:sabi_string',
             '<(DEPTH)/starboard/starboard_headers_only.gyp:starboard_headers_only',
             '<(DEPTH)/third_party/llvm-project/compiler-rt/compiler-rt.gyp:compiler_rt',
             '<(DEPTH)/third_party/llvm-project/libcxx/libcxx.gyp:cxx',
diff --git a/src/starboard/starboard_all.gyp b/src/starboard/starboard_all.gyp
index 886d75e..5034be5 100644
--- a/src/starboard/starboard_all.gyp
+++ b/src/starboard/starboard_all.gyp
@@ -81,7 +81,7 @@
           ],
         }, {
           'dependencies': [
-            '<(DEPTH)/starboard/starboard_all.gyp:starboard_platform_tests',
+            '<(DEPTH)/starboard/starboard_all.gyp:starboard_platform_tests_deploy',
           ],
         }],
         ['sb_filter_based_player==1', {
diff --git a/src/starboard/tools/app_launcher_packager.py b/src/starboard/tools/app_launcher_packager.py
index d978de4..53ff7d1 100644
--- a/src/starboard/tools/app_launcher_packager.py
+++ b/src/starboard/tools/app_launcher_packager.py
@@ -40,12 +40,9 @@
 
 # Default python directories to app launcher resources.
 _INCLUDE_FILE_PATTERNS = [
-    ('buildbot', '_env.py'),  # Only needed for device_server to execute
-    ('buildbot', '__init__.py'),  # Only needed for device_server to execute
-    ('buildbot/device_server', '*.py'),
-    ('buildbot/device_server/shared/ssl_certs', '*'),
     ('cobalt', '*.py'),
     ('starboard', '*.py'),
+    ('starboard/tools', 'platform.py.template')
 ]
 
 _INCLUDE_BLACK_BOX_TESTS_PATTERNS = [
@@ -123,7 +120,7 @@
   logging.info('Baking platform info files.')
   current_file = os.path.abspath(__file__)
   current_dir = os.path.dirname(current_file)
-  dest_dir = current_dir.replace(repo_root, dest_root)
+  dest_dir = os.path.join(dest_root, 'starboard', 'tools')
   platforms_map = {}
   for p in starboard.tools.platform.GetAll():
     platform_path = os.path.relpath(
diff --git a/src/starboard/tools/toolchain/evergreen_linker.py b/src/starboard/tools/toolchain/evergreen_linker.py
index 04fdc19..fe9bba9 100644
--- a/src/starboard/tools/toolchain/evergreen_linker.py
+++ b/src/starboard/tools/toolchain/evergreen_linker.py
@@ -43,4 +43,5 @@
                      '-nostdlib '
                      '--whole-archive '
                      '--no-whole-archive '
+                     '-u GetEvergreenSabiString '
                      '@$rspfile'.format(lld_path, self.GetPath(), *extra_flags))
diff --git a/src/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index db8c25e..d50e5f3 100644
--- a/src/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/third_party/angle/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -41,23 +41,43 @@
     "{\n"
     "    float4 gl_Color0 : SV_TARGET0;\n"
     "};\n"
-    "#define kRefWhiteLevelSRGB 290.0f\n"
-    "#define kRefWhiteLevelPQ 10000.0f\n"
+    "#define kRefWhiteLevelSRGB 100.0f\n" // The reference white point luminance 100 nits.
+    "#define kLinearLuminanceCoeff 10000.0f\n"
+    "#define kGamma 2.2f\n"
+    "#define kMinNits 0.0f\n"
+    "#define kMaxNits 325.0f\n"  //"Common" TVs usually interpret 1.0 to 250-400 nits.
     "static const float3x3 BT709_TO_BT2020 = { // ref: ARIB STD-B62 and BT.2087\n"
-    "  0.6274,    0.3293,    0.0433,\n"
-    "  0.0691,    0.9195,    0.0114,\n"
-    "  0.0164,    0.0880,    0.8956\n"
+    " 0.6274038959, 0.3292830384, 0.0433130657,\n"
+    " 0.0690972894, 0.9195403951, 0.0113623156,\n"
+    " 0.0163914389, 0.0880133079, 0.8955952532\n"
     "};\n"
     "float3 SRGB_EOTF(float3 E)\n"
     "{\n"
     "  float3 dark = E/12.92;\n"
-    "  float3 light = pow(abs((E+0.055)/(1+0.055)), 2.4);\n"
-    "  bool3 cri = E <= 0.04045;\n"
+    "  float3 light = pow((E+0.055)/(1+0.055), 2.4);\n"
+    "  bool3  cri = E <= 0.04045;\n"
     "  float3 cri_float = (float3)cri;\n"
     "  float3 r = lerp(light, dark, cri_float);\n"
-    "  r = r * kRefWhiteLevelSRGB;\n"
     "  return r;\n"
     "}\n"
+    "float3 SRGB_OETF(float3 L) {\n"
+    "  float3 dark  = L * 12.92;\n"
+    "  float3 light = 1.055 * pow(L, 1.0 / 2.4) - 0.055;\n"
+    "  bool3  cri = L <= 0.0031308;\n"
+    "  float3 cri_float = (float3)cri;\n"
+    "  float3 r = lerp(light, dark, cri_float);\n"
+    "  return r;\n"
+    "}\n"
+    "float3 BT2100_OOTF(float3 L, float minLNits, float maxLNits, float gamma) {\n"
+    "  float3 nits = L * kRefWhiteLevelSRGB;\n"
+    "  bool3 cri   = nits >= minLNits && nits < maxLNits;\n"
+    "  float3 i    = (nits - minLNits) / (maxLNits - minLNits);\n"
+    "  float3 j    = pow(SRGB_OETF(i), gamma);\n"
+    "  float3 adj  = (minLNits + (maxLNits - minLNits) * j) / kRefWhiteLevelSRGB;\n"
+    "  float3 cri_float = (float3)cri;\n"
+    "  float3 ret = lerp(adj, L, cri_float);\n"
+    "  return ret;\n"
+    "}\n"
     "//input: normalized L in units of RefWhite (1.0=100nits), output: normalized E\n"
     "float3 PQ_OETF(float3 L)\n"
     "{\n"
@@ -66,10 +86,11 @@
     "  const float c3 = 18.6875;\n"
     "  const float m1 = 0.159301758125;\n"
     "  const float m2 = 78.84375;\n"
-    "  L = L / kRefWhiteLevelPQ;\n"
-    "  float3 Lm1 = pow(abs(L), m1);\n"
+    "  L = BT2100_OOTF(L, kMinNits, kMaxNits, kGamma);\n"
+    "  L = L * kRefWhiteLevelSRGB / kLinearLuminanceCoeff;\n"
+    "  float3 Lm1 = pow(L, m1);\n"
     "  float3 X = (c1 + c2 * Lm1) / (1 + c3 * Lm1);\n"
-    "  float3 res = pow(abs(X), m2);\n"
+    "  float3 res = pow(X, m2);\n"
     "  return res;\n"
     "}\n"
     "PS_OUTPUT generateOutput()\n"
@@ -79,6 +100,7 @@
     "    float3 input_colors = gl_Color[0].rgb;\n"
     "    float3 lin_osd_graphics = SRGB_EOTF(input_colors);\n"
     "    lin_osd_graphics =  mul(BT709_TO_BT2020, lin_osd_graphics);\n"
+    "    lin_osd_graphics *=  kMaxNits/kRefWhiteLevelSRGB;\n"
     "    output.gl_Color0.rgb = PQ_OETF(lin_osd_graphics);\n"
     "    output.gl_Color0.a = gl_Color[0].a;\n"
     "    return output;\n"
diff --git a/src/third_party/freetype2/ChangeLog b/src/third_party/freetype2/ChangeLog
index e4ea3c5..921d93e 100644
--- a/src/third_party/freetype2/ChangeLog
+++ b/src/third_party/freetype2/ChangeLog
@@ -1,3 +1,11 @@
+2020-10-19  Werner Lemberg  <wl@gnu.org>
+
+       [sfnt] Fix heap buffer overflow (#59308).
+
+       This is CVE-2020-15999.
+
+       * src/sfnt/pngshim.c (Load_SBit_Png): Test bitmap size earlier.
+
 2020-05-09  Werner Lemberg  <wl@gnu.org>
 
 	* Version 2.10.2 released.
diff --git a/src/third_party/freetype2/src/sfnt/pngshim.c b/src/third_party/freetype2/src/sfnt/pngshim.c
index 523b30a..5502108 100644
--- a/src/third_party/freetype2/src/sfnt/pngshim.c
+++ b/src/third_party/freetype2/src/sfnt/pngshim.c
@@ -328,6 +328,13 @@
 
     if ( populate_map_and_metrics )
     {
+      /* reject too large bitmaps similarly to the rasterizer */
+      if ( imgHeight > 0x7FFF || imgWidth > 0x7FFF )
+      {
+        error = FT_THROW( Array_Too_Large );
+        goto DestroyExit;
+      }
+
       metrics->width  = (FT_UShort)imgWidth;
       metrics->height = (FT_UShort)imgHeight;
 
@@ -336,13 +343,6 @@
       map->pixel_mode = FT_PIXEL_MODE_BGRA;
       map->pitch      = (int)( map->width * 4 );
       map->num_grays  = 256;
-
-      /* reject too large bitmaps similarly to the rasterizer */
-      if ( map->rows > 0x7FFF || map->width > 0x7FFF )
-      {
-        error = FT_THROW( Array_Too_Large );
-        goto DestroyExit;
-      }
     }
 
     /* convert palette/gray image to rgb */
diff --git a/src/third_party/libevent/libevent.gyp b/src/third_party/libevent/libevent.gyp
index d57206a..ab2db97 100644
--- a/src/third_party/libevent/libevent.gyp
+++ b/src/third_party/libevent/libevent.gyp
@@ -87,10 +87,6 @@
                   'include_dirs': [ 'starboard/linux' ],
                   }
                 ],
-                [ 'target_os in ("tvos", "ios", "mac")', {
-                  'include_dirs': [ 'starboard/darwin' ],
-                  }
-                ],
               ],
             }],
             # libevent has platform-specific implementation files.  Since its
diff --git a/src/third_party/libevent/poll.c b/src/third_party/libevent/poll.c
index 6fc6d44..52b6533 100644
--- a/src/third_party/libevent/poll.c
+++ b/src/third_party/libevent/poll.c
@@ -31,11 +31,11 @@
 #endif
 
 #ifdef STARBOARD
-#if defined LIBEVENT_STARBOARD_HEADER
-#include LIBEVENT_STARBOARD_HEADER
-#else  //  defined LIBEVENT_STARBOARD_HEADER
+#if defined LIBEVENT_PLATFORM_HEADER
+#include LIBEVENT_PLATFORM_HEADER
+#else  //  defined LIBEVENT_PLATFORM_HEADER
 #include "libevent-starboard.h"
-#endif  //  defined LIBEVENT_STARBOARD_HEADER
+#endif  //  defined LIBEVENT_PLATFORM_HEADER
 
 #include <poll.h>
 #include <stdlib.h>
diff --git a/src/third_party/libevent/starboard/darwin/libevent-starboard.h b/src/third_party/libevent/starboard/darwin/libevent-starboard.h
deleted file mode 100644
index 7db2078..0000000
--- a/src/third_party/libevent/starboard/darwin/libevent-starboard.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2017 Google Inc. 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 _LIBEVENT_STARBOARD_H_
-#define _LIBEVENT_STARBOARD_H_
-
-#include "starboard/atomic.h"
-#include "starboard/types.h"
-
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-/* Define if clock_gettime is available in libc */
-/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
-
-/* Define is no secure id variant is available */
-#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1
-
-/* Define to 1 if you have the `clock_gettime' function. */
-/* #undef _EVENT_HAVE_CLOCK_GETTIME */
-
-/* Define if /dev/poll is available */
-/* #undef _EVENT_HAVE_DEVPOLL */
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define _EVENT_HAVE_DLFCN_H 1
-
-/* Define if your system supports the epoll system calls */
-/* #undef _EVENT_HAVE_EPOLL */
-
-/* Define to 1 if you have the `epoll_ctl' function. */
-/* #undef _EVENT_HAVE_EPOLL_CTL */
-
-/* Define if your system supports event ports */
-/* #undef _EVENT_HAVE_EVENT_PORTS */
-
-/* Define to 1 if you have the `fcntl' function. */
-#define _EVENT_HAVE_FCNTL 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define _EVENT_HAVE_FCNTL_H 1
-
-/* Define to 1 if the system has the type `fd_mask'. */
-#define _EVENT_HAVE_FD_MASK 1
-
-/* Define to 1 if you have the `getaddrinfo' function. */
-#define _EVENT_HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `getegid' function. */
-#define _EVENT_HAVE_GETEGID 1
-
-/* Define to 1 if you have the `geteuid' function. */
-#define _EVENT_HAVE_GETEUID 1
-
-/* Define to 1 if you have the `getnameinfo' function. */
-#define _EVENT_HAVE_GETNAMEINFO 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define _EVENT_HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `inet_ntop' function. */
-#define _EVENT_HAVE_INET_NTOP 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define _EVENT_HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the `issetugid' function. */
-#define _EVENT_HAVE_ISSETUGID 1
-
-/* Define to 1 if you have the `kqueue' function. */
-/* #define _EVENT_HAVE_KQUEUE 1 */
-
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-/* #undef _EVENT_HAVE_LIBNSL */
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-#define _EVENT_HAVE_LIBRESOLV 1
-
-/* Define to 1 if you have the `rt' library (-lrt). */
-/* #undef _EVENT_HAVE_LIBRT */
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-/* #undef _EVENT_HAVE_LIBSOCKET */
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define _EVENT_HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <netinet/in6.h> header file. */
-/* #undef _EVENT_HAVE_NETINET_IN6_H */
-
-/* Define to 1 if you have the `poll' function. */
-#define HAVE_POLL 1
-#define _EVENT_HAVE_POLL 1
-
-/* Define to 1 if you have the <poll.h> header file. */
-#define _EVENT_HAVE_POLL_H 1
-
-/* Define to 1 if you have the `port_create' function. */
-/* #undef _EVENT_HAVE_PORT_CREATE */
-
-/* Define to 1 if you have the <port.h> header file. */
-/* #undef _EVENT_HAVE_PORT_H */
-
-/* Define to 1 if you have the `select' function. */
-#define _EVENT_HAVE_SELECT 1
-
-/* Define if F_SETFD is defined in <fcntl.h> */
-#define _EVENT_HAVE_SETFD 1
-
-/* Define to 1 if you have the `sigaction' function. */
-#define _EVENT_HAVE_SIGACTION 1
-
-/* Define to 1 if you have the `signal' function. */
-#define _EVENT_HAVE_SIGNAL 1
-
-/* Define to 1 if you have the <signal.h> header file. */
-#define _EVENT_HAVE_SIGNAL_H 1
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define _EVENT_HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#define _EVENT_HAVE_STDINT_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define _EVENT_HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define _EVENT_HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define _EVENT_HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-#define _EVENT_HAVE_STRLCPY 1
-
-/* Define to 1 if you have the `strsep' function. */
-#define _EVENT_HAVE_STRSEP 1
-
-/* Define to 1 if you have the `strtok_r' function. */
-#define _EVENT_HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the `strtoll' function. */
-#define _EVENT_HAVE_STRTOLL 1
-
-/* Define to 1 if the system has the type `struct in6_addr'. */
-#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
-
-/* Define to 1 if you have the <sys/devpoll.h> header file. */
-/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
-
-/* Define to 1 if you have the <sys/epoll.h> header file. */
-/* #undef _EVENT_HAVE_SYS_EPOLL_H */
-
-/* Define to 1 if you have the <sys/event.h> header file. */
-#define _EVENT_HAVE_SYS_EVENT_H 1
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#define _EVENT_HAVE_SYS_IOCTL_H 1
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define _EVENT_HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/queue.h> header file. */
-#define _EVENT_HAVE_SYS_QUEUE_H 1
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#define _EVENT_HAVE_SYS_SELECT_H 1
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#define _EVENT_HAVE_SYS_SOCKET_H 1
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define _EVENT_HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define _EVENT_HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define _EVENT_HAVE_SYS_TYPES_H 1
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#define _EVENT_HAVE_TAILQFOREACH 1
-
-/* Define if timeradd is defined in <sys/time.h> */
-#define _EVENT_HAVE_TIMERADD 1
-
-/* Define if timerclear is defined in <sys/time.h> */
-#define _EVENT_HAVE_TIMERCLEAR 1
-
-/* Define if timercmp is defined in <sys/time.h> */
-#define _EVENT_HAVE_TIMERCMP 1
-
-/* Define if timerisset is defined in <sys/time.h> */
-#define _EVENT_HAVE_TIMERISSET 1
-
-/* Define to 1 if the system has the type `uint16_t'. */
-#define _EVENT_HAVE_UINT16_T 1
-
-/* Define to 1 if the system has the type `uint32_t'. */
-#define _EVENT_HAVE_UINT32_T 1
-
-/* Define to 1 if the system has the type `uint64_t'. */
-#define _EVENT_HAVE_UINT64_T 1
-
-/* Define to 1 if the system has the type `uint8_t'. */
-#define _EVENT_HAVE_UINT8_T 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define _EVENT_HAVE_UNISTD_H 1
-
-/* Define to 1 if you have the `vasprintf' function. */
-#define _EVENT_HAVE_VASPRINTF 1
-
-/* Define if kqueue works correctly with pipes */
-/* #define HAVE_WORKING_KQUEUE 1 */
-/* #define _EVENT_HAVE_WORKING_KQUEUE 1 */
-
-/* Name of package */
-#define _EVENT_PACKAGE "libevent"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define _EVENT_PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define _EVENT_PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define _EVENT_PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define _EVENT_PACKAGE_TARNAME ""
-
-/* Define to the version of this package. */
-#define _EVENT_PACKAGE_VERSION ""
-
-/* Define to 1 if you have the ANSI C header files. */
-#define _EVENT_STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define _EVENT_TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define _EVENT_VERSION "1.4.13-stable"
-
-/* Define to appropriate substitue if compiler doesnt have __func__ */
-/* #undef _EVENT___func__ */
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef _EVENT_const */
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
-   calls it, or to nothing if 'inline' is not supported under any name.  */
-#ifndef _EVENT___cplusplus
-/* #undef _EVENT_inline */
-#endif
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef _EVENT_pid_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef _EVENT_size_t */
-
-/* Define to unsigned int if you dont have it */
-/* #undef _EVENT_socklen_t */
-
-#endif  // _LIBEVENT_STARBOARD_H_
diff --git a/src/third_party/opus/celt/os_support.h b/src/third_party/opus/celt/os_support.h
index a217197..e4a6ea2 100644
--- a/src/third_party/opus/celt/os_support.h
+++ b/src/third_party/opus/celt/os_support.h
@@ -42,6 +42,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifdef STARBOARD
+#include "starboard/client_porting/poem/stdio_poem.h"
+#include "starboard/client_porting/poem/string_poem.h"
+#else // STARBOARD
+#include <malloc.h>
+#endif // STARBOARD
+
 /** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */
 #ifndef OVERRIDE_OPUS_ALLOC
 static OPUS_INLINE void *opus_alloc (size_t size)
diff --git a/src/third_party/precommit-hooks/clang-format_wrapper.py b/src/third_party/precommit-hooks/clang-format_wrapper.py
deleted file mode 100755
index f0d11b6..0000000
--- a/src/third_party/precommit-hooks/clang-format_wrapper.py
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-import platform
-import subprocess
-import sys
-
-if __name__ == '__main__':
-  clang_format_args = sys.argv[1:]
-  path_to_clang_format = [os.getcwd(), 'buildtools']
-
-  system = platform.system()
-  if system == 'Linux':
-    path_to_clang_format += ['linux64', 'clang-format']
-  elif system == 'Darwin':
-    path_to_clang_format += ['mac', 'clang-format']
-  elif system == 'Windows':
-    path_to_clang_format += ['win', 'clang-format.exe']
-  else:
-    sys.exit(1)
-
-  clang_format_executable = os.path.join(*path_to_clang_format)
-  sys.exit(subprocess.call([clang_format_executable] + clang_format_args))
diff --git a/src/third_party/precommit-hooks/gcheckstyle_wrapper.py b/src/third_party/precommit-hooks/gcheckstyle_wrapper.py
deleted file mode 100755
index 0275960..0000000
--- a/src/third_party/precommit-hooks/gcheckstyle_wrapper.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python3
-
-import platform
-import subprocess
-import sys
-
-try:
-  from internal_tools_paths import checkstyle_path
-except ImportError:
-  checkstyle_path = None
-
-if __name__ == '__main__':
-  gcheckstyle_args = sys.argv[1:]
-  try:
-    sys.exit(subprocess.call([checkstyle_path] + gcheckstyle_args))
-  except OSError:
-    print('Checkstyle not found, skipping.')
-    sys.exit(0)
diff --git a/src/third_party/precommit-hooks/google-java-format_wrapper.py b/src/third_party/precommit-hooks/google-java-format_wrapper.py
deleted file mode 100755
index f244fa3..0000000
--- a/src/third_party/precommit-hooks/google-java-format_wrapper.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python3
-
-import platform
-import subprocess
-import sys
-
-if __name__ == '__main__':
-  if platform.system() != 'Linux':
-    sys.exit(0)
-
-  google_java_format_args = sys.argv[1:]
-  sys.exit(subprocess.call(['google-java-format'] + google_java_format_args))
diff --git a/src/tools/gyp/pylib/gyp/generator/ninja.py b/src/tools/gyp/pylib/gyp/generator/ninja.py
index c3f4ec9..85480fe 100755
--- a/src/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/src/tools/gyp/pylib/gyp/generator/ninja.py
@@ -83,15 +83,17 @@
     'win-win32-lib',
 ]
 sony_flavors = []
+nintendo_flavors = []
 
 try:
   import private_ninja_flavors
   microsoft_flavors += private_ninja_flavors.PrivateMicrosoftFlavors()
   sony_flavors += private_ninja_flavors.PrivateSonyFlavors()
+  nintendo_flavors += private_ninja_flavors.PrivateNintendoFlavors()
 except ImportError:
   pass
 
-windows_host_flavors = microsoft_flavors + sony_flavors
+windows_host_flavors = microsoft_flavors + sony_flavors + nintendo_flavors
 
 
 def GetToolchainOrNone(flavor):
@@ -157,7 +159,7 @@
     return arg  # No quoting necessary.
   if GetToolchainOrNone(flavor):
     return GetToolchainOrNone(flavor).QuoteForRspFile(arg)
-  elif flavor in sony_flavors:
+  elif flavor in sony_flavors or flavor in nintendo_flavors:
     # Escape double quotes.
     return '"' + arg.replace('\"', '\\\"') + '"'
   return "'" + arg.replace("'", "'" + '"\'"' + "'") + "'"
@@ -165,17 +167,21 @@
 
 def Define(d, flavor):
   """Takes a preprocessor define and returns a -D parameter that's ninja- and
-  shell-escaped."""
+
+  shell-escaped.
+  """
 
   return QuoteShellArgument(ninja_syntax.escape('-D' + d), flavor)
 
 
 def InvertRelativePath(path):
   """Given a relative path like foo/bar, return the inverse relative path:
+
   the path from the relative path back to the origin dir.
 
   E.g. os.path.normpath(os.path.join(path, InvertRelativePath(path)))
-  should always produce the empty string."""
+  should always produce the empty string.
+  """
 
   if not path:
     return path
@@ -240,17 +246,23 @@
 
   def PreActionInput(self, flavor):
     """Return the path, if any, that should be used as a dependency of
-    any dependent action step."""
+
+    any dependent action step.
+    """
     return self.FinalOutput() or self.preaction_stamp
 
   def PreCompileInput(self):
     """Return the path, if any, that should be used as a dependency of
-    any dependent compile step."""
+
+    any dependent compile step.
+    """
     return self.actions_stamp or self.precompile_stamp
 
   def FinalOutput(self):
     """Return the last output of the target, which depends on all prior
-    steps."""
+
+    steps.
+    """
     return self.bundle or self.binary or self.actions_stamp
 
 
@@ -374,9 +386,11 @@
 
   def GypPathToNinja(self, path, env=None):
     """Translate a gyp path to a ninja path, optionally expanding environment
+
     variable references in |path| with |env|.
 
-    See the above discourse on path conversions."""
+    See the above discourse on path conversions.
+    """
     if env:
       if self.flavor == 'mac':
         path = gyp.xcode_emulation.ExpandEnvVars(path, env)
@@ -408,7 +422,8 @@
     of the target.  This is necessary when e.g. compiling the same
     path twice for two separate output targets.
 
-    See the above discourse on path conversions."""
+    See the above discourse on path conversions.
+    """
 
     path = self.ExpandSpecial(path)
     assert not path.startswith('$'), path
@@ -438,9 +453,11 @@
 
   def WriteCollapsedDependencies(self, name, targets):
     """Given a list of targets, return a path for a single file
+
     representing the result of building all the targets or None.
 
-    Uses a stamp file if necessary."""
+    Uses a stamp file if necessary.
+    """
 
     assert targets == filter(None, targets), targets
     if len(targets) == 0:
@@ -461,7 +478,8 @@
 
     Returns a Target object, which represents the output paths for this spec.
     Returns None if there are no outputs (e.g. a settings-only 'none' type
-    target)."""
+    target).
+    """
 
     self.config_name = config_name
     self.name = spec['target_name']
@@ -476,7 +494,7 @@
     if self.flavor == 'mac':
       self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
     if (self.flavor in windows_host_flavors and is_windows):
-      if self.flavor in sony_flavors:
+      if self.flavor in sony_flavors or self.flavor in nintendo_flavors:
         self.msvs_settings = gyp.msvs_emulation.MsvsSettings(
             spec, generator_flags)
         arch = self.msvs_settings.GetArch(config_name)
@@ -585,8 +603,11 @@
     return self.target
 
   def _WinIdlRule(self, source, prebuild, outputs):
-    """Handle the implicit VS .idl rule for one source file. Fills |outputs|
-    with files that are generated."""
+    """Handle the implicit VS .idl rule for one source file.
+
+    Fills |outputs|
+    with files that are generated.
+    """
     outdir, output, vars, flags = GetToolchainOrNone(
         self.flavor).GetCompilerSettings().GetIdlBuildData(
             source, self.config_name)
@@ -623,8 +644,11 @@
 
   def WriteActionsRulesCopies(self, spec, extra_sources, prebuild,
                               mac_bundle_depends):
-    """Write out the Actions, Rules, and Copies steps.  Return a path
-    representing the outputs of these steps."""
+    """Write out the Actions, Rules, and Copies steps.
+
+    Return a path
+    representing the outputs of these steps.
+    """
     outputs = []
     extra_mac_bundle_resources = []
 
@@ -662,10 +686,10 @@
       return '%s %s: %s' % (verb, self.name, fallback)
 
   def IsCygwinRule(self, action):
-    if self.flavor in sony_flavors:
+    if self.flavor in sony_flavors or self.flavor in nintendo_flavors:
       value = str(action.get('msvs_cygwin_shell', 0)) != '0'
       if value:
-        raise Exception("Cygwin usage is no longer allowed in Cobalt Gyp")
+        raise Exception('Cygwin usage is no longer allowed in Cobalt Gyp')
     return False
 
   def WriteActions(self, actions, extra_sources, prebuild,
@@ -1227,8 +1251,10 @@
                           output_binary,
                           is_command_start=False):
     """Returns a shell command that runs all the postbuilds, and removes
+
     |output| if any of them fails. If |is_command_start| is False, then the
-    returned string will start with ' && '."""
+    returned string will start with ' && '.
+    """
     if not self.xcode_settings or spec['type'] == 'none' or not output:
       return ''
     output = QuoteShellArgument(output, self.flavor)
@@ -1264,8 +1290,10 @@
 
   def ComputeExportEnvString(self, env):
     """Given an environment, returns a string looking like
+
         'export FOO=foo; export BAR="${FOO} bar;'
-    that exports |env| to the shell."""
+    that exports |env| to the shell.
+    """
     export_str = []
     for k, v in env:
       export_str.append(
@@ -1387,7 +1415,8 @@
     """Write out a new ninja "rule" statement for a given command.
 
     Returns the name of the new rule, and a copy of |args| with variables
-    expanded."""
+    expanded.
+    """
 
     if self.flavor == 'win':
       args = [
@@ -1428,7 +1457,7 @@
       rspfile = rule_name + '.$unique_name.rsp'
       # The cygwin case handles this inside the bash sub-shell.
       run_in = ' ' + self.build_to_base
-      if self.flavor in sony_flavors:
+      if self.flavor in sony_flavors or self.flavor in nintendo_flavors:
         rspfile_content = gyp.msvs_emulation.EncodeRspFileList(args)
       else:
         rspfile_content = GetToolchainOrNone(
@@ -1479,19 +1508,13 @@
     global generator_extra_sources_for_rules
     generator_extra_sources_for_rules = getattr(
         xcode_generator, 'generator_extra_sources_for_rules', [])
-  elif flavor in sony_flavors:
-    if is_windows:
-      # This is required for BuildCygwinBashCommandLine() to work.
-      import gyp.generator.msvs as msvs_generator
-      generator_additional_non_configuration_keys = getattr(
-          msvs_generator, 'generator_additional_non_configuration_keys', [])
-      generator_additional_path_sections = getattr(
-          msvs_generator, 'generator_additional_path_sections', [])
-
-    default_variables['EXECUTABLE_SUFFIX'] = '.elf'
+  elif flavor in sony_flavors or flavor in nintendo_flavors:
+    if flavor in sony_flavors:
+      default_variables['EXECUTABLE_SUFFIX'] = '.elf'
+    else:
+      default_variables['EXECUTABLE_SUFFIX'] = '.exe'
<